@ttt-productions/ttt-core 0.79.92 → 0.79.94
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/company-mascots.d.ts +27 -2
- package/dist/constants/company-mascots.d.ts.map +1 -1
- package/dist/constants/company-mascots.js +66 -6
- package/dist/constants/company-mascots.js.map +1 -1
- package/dist/doc-schemas/media-assets.d.ts +6 -0
- package/dist/doc-schemas/media-assets.d.ts.map +1 -1
- package/dist/doc-schemas/media-assets.js +8 -0
- package/dist/doc-schemas/media-assets.js.map +1 -1
- package/dist/doc-schemas/payments.d.ts +4 -0
- package/dist/doc-schemas/payments.d.ts.map +1 -1
- package/dist/doc-schemas/payments.js +7 -3
- package/dist/doc-schemas/payments.js.map +1 -1
- package/dist/doc-schemas/registry.d.ts +64 -0
- package/dist/doc-schemas/registry.d.ts.map +1 -1
- package/dist/doc-schemas/safety/foundation.d.ts +44 -20
- package/dist/doc-schemas/safety/foundation.d.ts.map +1 -1
- package/dist/doc-schemas/safety/foundation.js +96 -52
- package/dist/doc-schemas/safety/foundation.js.map +1 -1
- package/dist/media/domain-events-admin.d.ts +7 -0
- package/dist/media/domain-events-admin.d.ts.map +1 -1
- package/dist/media/domain-events-admin.js +12 -0
- package/dist/media/domain-events-admin.js.map +1 -1
- package/dist/media/domain-events-user.d.ts +12 -0
- package/dist/media/domain-events-user.d.ts.map +1 -1
- package/dist/media/domain-events-user.js +16 -1
- package/dist/media/domain-events-user.js.map +1 -1
- package/dist/media/domain-events.d.ts +16 -0
- package/dist/media/domain-events.d.ts.map +1 -1
- package/dist/media/domain-events.js +5 -2
- package/dist/media/domain-events.js.map +1 -1
- package/dist/media/pending-media.d.ts +176 -0
- package/dist/media/pending-media.d.ts.map +1 -1
- package/dist/media/publication/publication-args.d.ts +0 -2
- package/dist/media/publication/publication-args.d.ts.map +1 -1
- package/dist/media/publication/publication-args.js +31 -33
- package/dist/media/publication/publication-args.js.map +1 -1
- package/dist/paths/collection-refs.d.ts +1 -0
- package/dist/paths/collection-refs.d.ts.map +1 -1
- package/dist/paths/collection-refs.js +3 -0
- package/dist/paths/collection-refs.js.map +1 -1
- package/dist/schemas/notification.d.ts +14 -7
- package/dist/schemas/notification.d.ts.map +1 -1
- package/dist/schemas/notification.js +42 -23
- package/dist/schemas/notification.js.map +1 -1
- package/dist/utils/pledge-totals.d.ts +3 -0
- package/dist/utils/pledge-totals.d.ts.map +1 -1
- package/dist/utils/pledge-totals.js +6 -0
- package/dist/utils/pledge-totals.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,8 +8,7 @@ export type CompanyBillingKind = 'foundingPlayer' | 'player' | 'standIn';
|
|
|
8
8
|
/** Demoable move intents — keyed by intent from day one so future event
|
|
9
9
|
* performances (page-grabs, standing ovations) land as content, not code. */
|
|
10
10
|
export type CompanyPerformanceIntent = 'bow' | 'hop' | 'wave';
|
|
11
|
-
/** The performance intents, in demo-button order
|
|
12
|
-
* hand-mirrored this union in two places; consumers derive from this array. */
|
|
11
|
+
/** The performance intents, in demo-button order; consumers derive from this array. */
|
|
13
12
|
export declare const COMPANY_PERFORMANCE_INTENTS: readonly CompanyPerformanceIntent[];
|
|
14
13
|
/** The characters a user may cast as their dock companion (never a Stand-In). */
|
|
15
14
|
export type SelectableCompanionId = 'bill' | 'kit';
|
|
@@ -112,4 +111,30 @@ export declare const COMPANION_SWITCH_EXCHANGES: Readonly<Record<SelectableCompa
|
|
|
112
111
|
export declare const YORICK_BLOCK_LINES: Readonly<Record<SelectableCompanionId, readonly string[]>>;
|
|
113
112
|
export declare const SIGNED_OUT_DOCK_LINES: readonly string[];
|
|
114
113
|
export declare const ONBOARDING_CAMEOS: OnboardingCameos;
|
|
114
|
+
/** The permanent shell controls a tour step can highlight. */
|
|
115
|
+
export declare const SITE_TOUR_ANCHORS: readonly ["homeAndHelp", "accountArea", "dock", "pageActions"];
|
|
116
|
+
export type SiteTourAnchor = (typeof SITE_TOUR_ANCHORS)[number];
|
|
117
|
+
export interface SiteTourLine {
|
|
118
|
+
speaker: CompanyCharacterId;
|
|
119
|
+
text: string;
|
|
120
|
+
}
|
|
121
|
+
export interface SiteTourStepCopy {
|
|
122
|
+
/** Which permanent shell control this step highlights. */
|
|
123
|
+
anchor: SiteTourAnchor;
|
|
124
|
+
/** The mascot who leads this step. */
|
|
125
|
+
speaker: CompanyCharacterId;
|
|
126
|
+
/** Bold lead-in headline. */
|
|
127
|
+
heading: string;
|
|
128
|
+
/** Body paragraphs (verbatim), each its own paragraph. */
|
|
129
|
+
body: readonly string[];
|
|
130
|
+
/** Non-Artisan replacement for the FINAL body paragraph, when present. */
|
|
131
|
+
bodyNonArtisanFinal?: string;
|
|
132
|
+
}
|
|
133
|
+
/** The three-mascot greeting + invitation lines. */
|
|
134
|
+
export declare const SITE_TOUR_INVITATION_LINES: readonly SiteTourLine[];
|
|
135
|
+
/** The four-step tour copy. */
|
|
136
|
+
export declare const SITE_TOUR_STEPS: readonly SiteTourStepCopy[];
|
|
137
|
+
/** The three-mascot curtain-call lines. */
|
|
138
|
+
export declare const SITE_TOUR_CURTAIN_CALL_LINES: readonly SiteTourLine[];
|
|
139
|
+
export declare const SITE_TOUR_TOTAL_STEPS: number;
|
|
115
140
|
//# sourceMappingURL=company-mascots.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"company-mascots.d.ts","sourceRoot":"","sources":["../../src/constants/company-mascots.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"company-mascots.d.ts","sourceRoot":"","sources":["../../src/constants/company-mascots.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
// The ONE home for the pure, server-safe Company business truths (id unions,
|
|
5
5
|
// billing kinds, performance intents, selectability, roster order) AND the
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// (`src/lib/company-contract` + `src/lib/company-mascots.tsx`).
|
|
6
|
+
// VERBATIM character content (studies, click lines, footers, companion-switch
|
|
7
|
+
// exchanges, Yorick block lines, signed-out dock lines, onboarding cameos, the
|
|
8
|
+
// first-visit site tour).
|
|
10
9
|
//
|
|
11
10
|
// This module is pure data: NO React, NO JSX, NO Next links, NO CSS, NO SVG,
|
|
12
11
|
// NO functions inside the data. Rich copy is modelled as discriminated
|
|
@@ -22,8 +21,7 @@
|
|
|
22
21
|
// ============================================================================
|
|
23
22
|
/** The roster, in billing order (Bill → Kit → Yorick). */
|
|
24
23
|
export const COMPANY_CHARACTER_IDS = ['bill', 'kit', 'yorick'];
|
|
25
|
-
/** The performance intents, in demo-button order
|
|
26
|
-
* hand-mirrored this union in two places; consumers derive from this array. */
|
|
24
|
+
/** The performance intents, in demo-button order; consumers derive from this array. */
|
|
27
25
|
export const COMPANY_PERFORMANCE_INTENTS = ['bow', 'hop', 'wave'];
|
|
28
26
|
/** The castable dock companions, in order. */
|
|
29
27
|
export const SELECTABLE_COMPANION_IDS = ['bill', 'kit'];
|
|
@@ -269,4 +267,66 @@ export const ONBOARDING_CAMEOS = {
|
|
|
269
267
|
yorick: "You'll forget me. It's fine. Go.",
|
|
270
268
|
},
|
|
271
269
|
};
|
|
270
|
+
// ── First-visit site tour ─────────────────────────────────────────────────────
|
|
271
|
+
// The tour layer reads these records and never inlines its own strings. A `speaker` names the
|
|
272
|
+
// mascot whose headshot sits beside the line.
|
|
273
|
+
/** The permanent shell controls a tour step can highlight. */
|
|
274
|
+
export const SITE_TOUR_ANCHORS = ['homeAndHelp', 'accountArea', 'dock', 'pageActions'];
|
|
275
|
+
/** The three-mascot greeting + invitation lines. */
|
|
276
|
+
export const SITE_TOUR_INVITATION_LINES = [
|
|
277
|
+
{
|
|
278
|
+
speaker: 'bill',
|
|
279
|
+
text: 'Welcome to TTT! Before the curtain rises, may we show you the few controls that will help you find your way around?',
|
|
280
|
+
},
|
|
281
|
+
{ speaker: 'kit', text: 'Four quick stops. He rehearsed twelve.' },
|
|
282
|
+
{ speaker: 'yorick', text: 'I was told there would be snacks.' },
|
|
283
|
+
];
|
|
284
|
+
/** The four-step tour copy. */
|
|
285
|
+
export const SITE_TOUR_STEPS = [
|
|
286
|
+
{
|
|
287
|
+
anchor: 'homeAndHelp',
|
|
288
|
+
speaker: 'bill',
|
|
289
|
+
heading: "TTT brings you home. Help is where you look when you're lost.",
|
|
290
|
+
body: [
|
|
291
|
+
'TTT always returns you to Center Stage. Help opens the Backstage Guide, where you can learn how the theatre works and replay this tour.',
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
anchor: 'accountArea',
|
|
296
|
+
speaker: 'kit',
|
|
297
|
+
heading: 'Most of the theatre waits behind your account menu.',
|
|
298
|
+
body: [
|
|
299
|
+
'Use it to visit The Town, open Your Corner, change settings, or sign out. Artisans also have a separate My Work button for reaching their Works quickly.',
|
|
300
|
+
],
|
|
301
|
+
bodyNonArtisanFinal: 'If you become an Artisan, My Work will appear here for reaching your Works quickly.',
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
anchor: 'dock',
|
|
305
|
+
speaker: 'yorick',
|
|
306
|
+
heading: 'Your companion lives here. Click them for a little company—or hide them from the notification tray when you need some quiet.',
|
|
307
|
+
body: [
|
|
308
|
+
'The tray also lets you reduce motion across the whole theatre while keeping your companion visible and still.',
|
|
309
|
+
'The bell opens notifications. After you scroll down a page, an arrow appears to carry you back to the top.',
|
|
310
|
+
'I am, apparently, not eligible for the companion position.',
|
|
311
|
+
],
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
anchor: 'pageActions',
|
|
315
|
+
speaker: 'kit',
|
|
316
|
+
heading: 'Some pages place their special actions in this corner.',
|
|
317
|
+
body: [
|
|
318
|
+
'You may find controls for creating something, reviewing activity, or performing another action unique to that page. If the corner is empty, there is nothing waiting for you there.',
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
];
|
|
322
|
+
/** The three-mascot curtain-call lines. */
|
|
323
|
+
export const SITE_TOUR_CURTAIN_CALL_LINES = [
|
|
324
|
+
{
|
|
325
|
+
speaker: 'bill',
|
|
326
|
+
text: 'That is the whole house. You can revisit this tour from Help whenever you need it.',
|
|
327
|
+
},
|
|
328
|
+
{ speaker: 'kit', text: 'Four stops. Barely an epic.' },
|
|
329
|
+
{ speaker: 'yorick', text: 'I still think we missed the refreshments.' },
|
|
330
|
+
];
|
|
331
|
+
export const SITE_TOUR_TOTAL_STEPS = SITE_TOUR_STEPS.length;
|
|
272
332
|
//# sourceMappingURL=company-mascots.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"company-mascots.js","sourceRoot":"","sources":["../../src/constants/company-mascots.ts"],"names":[],"mappings":"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","sourcesContent":["// ============================================================================\n// THE COMPANY — canonical Green Room mascot contract + content (ARCH-102).\n//\n// The ONE home for the pure, server-safe Company business truths (id unions,\n// billing kinds, performance intents, selectability, roster order) AND the\n// DJ-approved VERBATIM character content (studies, click lines, footers,\n// companion-switch exchanges, Yorick block lines, signed-out dock lines,\n// onboarding cameos). Moved here losslessly from the app's staging modules\n// (`src/lib/company-contract` + `src/lib/company-mascots.tsx`).\n//\n// This module is pure data: NO React, NO JSX, NO Next links, NO CSS, NO SVG,\n// NO functions inside the data. Rich copy is modelled as discriminated\n// `CompanyCopySegment`s so a web renderer, a phone app, or an AI voice can each\n// present the exact approved words without importing a UI framework. The app\n// owns the puppets, rig, choreography, and the adapter that turns these\n// segments into `<p>`, `<em>`, and route-aware links.\n//\n// Canonical dialogue stays a versioned code constant here (never Firestore):\n// it is the personality source, the safe AI-unavailable fallback, and the\n// voice-regression fixture. Never reword — curly quotes/apostrophes are\n// authored exactly as they render.\n// ============================================================================\n\n// ── Contract: id unions, billing, intents, selectability ─────────────────────\n\n/** Every member of the Company, in roster order. */\nexport type CompanyCharacterId = 'bill' | 'kit' | 'yorick';\n\n/** The roster, in billing order (Bill → Kit → Yorick). */\nexport const COMPANY_CHARACTER_IDS: readonly CompanyCharacterId[] = ['bill', 'kit', 'yorick'];\n\n/** Billing tiers: the founding Player, permanent Players, and Stand-Ins\n * (Limited Engagement — never selectable as the companion). */\nexport type CompanyBillingKind = 'foundingPlayer' | 'player' | 'standIn';\n\n/** Demoable move intents — keyed by intent from day one so future event\n * performances (page-grabs, standing ovations) land as content, not code. */\nexport type CompanyPerformanceIntent = 'bow' | 'hop' | 'wave';\n\n/** The performance intents, in demo-button order. The app previously\n * hand-mirrored this union in two places; consumers derive from this array. */\nexport const COMPANY_PERFORMANCE_INTENTS: readonly CompanyPerformanceIntent[] = ['bow', 'hop', 'wave'];\n\n/** The characters a user may cast as their dock companion (never a Stand-In). */\nexport type SelectableCompanionId = 'bill' | 'kit';\n\n/** The castable dock companions, in order. */\nexport const SELECTABLE_COMPANION_IDS: readonly SelectableCompanionId[] = ['bill', 'kit'];\n\n// ── Rich-copy pure-data model ────────────────────────────────────────────────\n\n/** Semantic destinations the copy can link to. Each client maps these to its\n * own route/navigation — the package never carries an href in mascot copy. */\nexport type CompanyNavigationTarget = 'greenRoom' | 'futurePlans';\n\n/** A single run of copy. `link` carries a semantic target, not a URL. */\nexport type CompanyCopySegment =\n | { readonly kind: 'text'; readonly text: string }\n | { readonly kind: 'emphasis'; readonly text: string }\n | { readonly kind: 'link'; readonly label: string; readonly target: CompanyNavigationTarget };\n\n/** A block of copy — a paragraph or a set-aside aside. */\nexport type CompanyCopyBlockKind = 'paragraph' | 'aside';\n\nexport interface CompanyCopyBlock {\n readonly kind: CompanyCopyBlockKind;\n readonly segments: readonly CompanyCopySegment[];\n}\n\n// ── Registry shapes ──────────────────────────────────────────────────────────\n\nexport interface CompanyPerformance {\n readonly id: string;\n readonly label: string;\n readonly intent: CompanyPerformanceIntent;\n /** Community \"Choreography by\" credit — null until an audition stages it. */\n readonly creditUid: string | null;\n}\n\nexport interface CompanyMascot {\n readonly id: CompanyCharacterId;\n /** Full stage name shown on nameplates + the playbill (\"Bill the Understudy\"). */\n readonly name: string;\n /** The ironic-understatement epithet (the Company tradition). */\n readonly title: string;\n readonly billingKind: CompanyBillingKind;\n /** Billing line rendered beside the name (\"Founding Player\"). */\n readonly billingLabel: string;\n /** One-line structural descriptor (not character voice). */\n readonly shortBio: string;\n /** Playbill character study (human-written; the future AI personality source). */\n readonly characterStudy: readonly CompanyCopyBlock[];\n /** \"Role originated by\" — resolves live via the app when set. */\n readonly originatedByUid: string | null;\n /** Text shown after \"Role originated by — \" when originatedByUid is null. */\n readonly originatedByFallback: string;\n /** Whether the origination frame invites the reader (\"→ your name here?\"). */\n readonly invitesOrigination: boolean;\n /** The performances credit caption under the demo buttons. */\n readonly choreographyCaption: string;\n readonly performances: readonly CompanyPerformance[];\n /** Rotating click lines (dock companion bubble + on-stage line pop). Each\n * line is a segment run — most are a single text segment. */\n readonly lines: readonly (readonly CompanyCopySegment[])[];\n /** Dock speech-bubble footer segments. The character's short name is a\n * `greenRoom` link segment; the app renders it as a link when signed in and\n * as plain text when signed out. \"one day\" always links to `futurePlans`.\n * Absent for Stand-Ins (Yorick — never the dock companion). */\n readonly footer?: readonly CompanyCopySegment[];\n /** False for Stand-Ins (Yorick) — never storable as the dock companion. */\n readonly selectable: boolean;\n}\n\n/** Companion-switch snark exchange, keyed (in COMPANION_SWITCH_EXCHANGES) by the\n * character switched TO. Outgoing line first (the departing companion), then the\n * incoming retort. Plain strings. */\nexport interface CompanionSwitchExchange {\n readonly outgoing: { readonly id: SelectableCompanionId; readonly line: string };\n readonly incoming: { readonly id: SelectableCompanionId; readonly line: string };\n}\n\n/** Onboarding cameo lines — Company members crashing the registration tour. */\nexport interface OnboardingCameos {\n /** Kit crashes The Audition Stage step. */\n readonly kitAuditionStage: string;\n /** Yorick cameos on The Hall step. */\n readonly yorickHall: string;\n /** The send-off curtain call — all three bow. */\n readonly curtainCall: Readonly<Record<CompanyCharacterId, string>>;\n}\n\n// ── Segment construction helpers (module-private; output is pure data) ────────\n\n/** A line/footer that is a single plain-text run. */\nconst textRun = (text: string): readonly CompanyCopySegment[] => [{ kind: 'text', text }];\n\n/** A character's dock footer, built from the one verbatim sentence. The name is\n * a `greenRoom` link segment (the app renders it plain when signed out); \"one\n * day\" always links to `futurePlans`; `tail` is the character-specific close. */\nconst dockFooter = (name: string, tail: string): readonly CompanyCopySegment[] => [\n { kind: 'link', label: name, target: 'greenRoom' },\n { kind: 'text', text: ' is a basic version for now — ' },\n { kind: 'link', label: 'one day', target: 'futurePlans' },\n { kind: 'text', text: ` ${tail}` },\n];\n\nconst SHARED_PERFORMANCES: readonly CompanyPerformance[] = [\n { id: 'bow', label: 'Bow', intent: 'bow', creditUid: null },\n { id: 'hop', label: 'Hop', intent: 'hop', creditUid: null },\n { id: 'wave', label: 'Wave', intent: 'wave', creditUid: null },\n];\n\n// The dock-footer close sentences, VERBATIM (the pre-Company Bill wording; Kit's\n// from the settled spec). Curly apostrophes authored exactly as rendered.\nconst BILL_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide who helps you navigate the site. He’ll never make content, just help.';\nconst KIT_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide with this exact attitude. He’ll never make content. He does have opinions about yours.';\n\n// ── Bill the Understudy — Founding Player ────────────────────────────────────\n// The 14 approved lines are VERBATIM (incl. the italic emphasis in line 11).\nconst BILL: CompanyMascot = {\n id: 'bill',\n name: 'Bill the Understudy',\n title: 'The Understudy',\n billingKind: 'foundingPlayer',\n billingLabel: 'Founding Player',\n shortBio: \"TTT's founding player and your first guide.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'The most enthusiastic understudy in show business, and TTT Productions’ founding player. Bill has read the whole script of this town — well, skimmed it — and rehearses every day for the role of your guide to everything here. He insists the ‘Bill’ is short for William, and that he once wrote plays in a town called Stratford. We have chosen to let him believe it. Someday he’ll answer anything you ask about this place. Today, he mostly waves.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"One day I'll help you find your perfect collaborator. Today, I mostly wave.\"),\n textRun(\"I'm just an understudy for now — but someday I'll know every corner of this town.\"),\n textRun('Rehearsing my big role: your guide to everything TTT. No spoilers.'),\n textRun(\"They say one day I'll have real personalities. Plural. I'm excited too.\"),\n textRun(\"I'll never make the art — that's your job. I'll just help you find your people.\"),\n textRun(\"Every great production starts with somebody standing in the wings. That's me. Literally.\"),\n textRun(\"Someday you'll ask me anything about this place and I'll actually answer. Bold, I know.\"),\n textRun('The Town Crier gets to shout. I get to practice my bow. For now.'),\n textRun(\"I've read the whole script of this town. Well... skimmed. I'm working on it.\"),\n textRun('Big dreams for a stick figure: guide, helper, friend. In that order.'),\n [\n { kind: 'text', text: \"When the curtain rises on my real role, you'll be the first to know. You \" },\n { kind: 'emphasis', text: 'did' },\n { kind: 'text', text: ' click me first.' },\n ],\n textRun('Until my big debut, consider me the most enthusiastic understudy in show business.'),\n textRun(\"Even the greatest playwright who ever lived starts over as an understudy in a town this good. That's my story, anyway.\"),\n textRun('Four hundred years of theatre experience. My résumé? A drawing of myself.'),\n ],\n footer: dockFooter('Bill', BILL_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Kit the Stand-In — permanent Player #2, Bill's rival ─────────────────────\nconst KIT: CompanyMascot = {\n id: 'kit',\n name: 'Kit the Stand-In',\n title: 'The Stand-In',\n billingKind: 'player',\n billingLabel: 'Player',\n shortBio: \"Permanent Player #2, and Bill's rival.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'Sharp, quick, and absolutely certain he should have gone first. Kit auditioned for founding mascot, delivered the finest monologue the empty theatre had ever heard, and lost the part to a stick figure with a “trustworthy wave.” He has been gracious about it every single day since — loudly, to anyone in range. Keeps the rejection letter framed. Ask him about it. He’s dying for you to ask.',\n ),\n },\n {\n kind: 'aside',\n segments: textRun(\n 'Loosely nodding to a certain rival playwright — brilliant, theatrical, gone too soon. One day, an AI-powered guide with this exact personality: genuinely helpful, faintly insulted by the request.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Yes, I'm the Stand-In. Permanently. The irony isn't lost on me — it lives with me now.\"),\n textRun(\"I was FIRST in line at the founding audition. They went with a stick figure who 'waves well.'\"),\n textRun(\"Bill rehearses roles nobody wrote. I've already memorized them. We are not the same.\"),\n textRun(\"One day this whole town will know my name. Today it's 'the other one.' Fine.\"),\n textRun(\"I don't do warm-ups. I arrive brilliant.\"),\n textRun('Founding mascot. FOUNDING. He waved at a login page and they gave him a title.'),\n textRun('My five-year plan is center stage. My five-century plan is also center stage.'),\n textRun('History remembers a playwright who died before his rival got famous. Anyway. No reason.'),\n textRun('Click Bill for encouragement. Click me to hear the truth, beautifully delivered.'),\n textRun('I keep my rejection letter framed. Motivation is motivation.'),\n textRun(\"You clicked me first today. I rehearsed being gracious about this — give me a moment.\"),\n textRun(\"When the curtain finally rises on my lead role, act surprised. I won't.\"),\n textRun('They say I might have been a spy in a past life. I neither confirm nor deny. Mystique.'),\n textRun('The Understudy and the Stand-In on one stage. Somewhere a playwright is laughing at us both.'),\n ],\n footer: dockFooter('Kit', KIT_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Yorick the Forgettable — Stand-In · Limited Engagement ───────────────────\n// Never selectable, never the dock companion; his lines are on-stage only.\nconst YORICK: CompanyMascot = {\n id: 'yorick',\n name: 'Yorick the Forgettable',\n title: 'The Forgettable',\n billingKind: 'standIn',\n billingLabel: 'Stand-In · Limited Engagement',\n shortBio: 'A Limited Engagement Stand-In, keeping the light warm.',\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n \"A fellow of infinite jest, reduced to holding a light he isn't allowed to stand in. Yorick insists he was the funniest jester who ever lived — and unfortunately, everyone who could confirm it is unavailable for comment. He is keeping the stage warm until the role is properly cast, and he'd rather you didn't get attached. You'll forget him anyway. Everyone does. It's in the name.\",\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'no one will admit to it',\n invitesOrigination: false,\n choreographyCaption: 'Bow · Hop · Wave — borrowed from Bill, who says he can have them',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Oh! A visitor. Nobody visits the Wings. I'd know — I keep the guestbook. It's empty.\"),\n textRun(\"I used to kill at court, you know. Standing ovations. Kings weeping. ...You'll take my word for it.\"),\n textRun(\"Don't get attached. I'm told I'm temporary. The skull agrees.\"),\n textRun('Alas, poor me. I knew me well.'),\n textRun('Infinite jest, they said. INFINITE. And yet here I am, finite-ly employed.'),\n textRun(\"One day they'll cast this role properly and I'll be forgotten. Ahead of schedule, honestly.\"),\n ],\n selectable: false,\n};\n\nexport const COMPANY_MASCOTS: Readonly<Record<CompanyCharacterId, CompanyMascot>> = {\n bill: BILL,\n kit: KIT,\n yorick: YORICK,\n};\n\n/** Registry order (Bill → Kit → Yorick), reused from the roster. */\nexport const COMPANY_MASCOT_ORDER: readonly CompanyCharacterId[] = COMPANY_CHARACTER_IDS;\n\n// ── Pure helpers ─────────────────────────────────────────────────────────────\n\n/** True when `x` is a canonical Company character id. */\nexport function isCompanyCharacterId(x: unknown): x is CompanyCharacterId {\n return typeof x === 'string' && (COMPANY_CHARACTER_IDS as readonly string[]).includes(x);\n}\n\n/** True when `id` may be cast as the dock companion — driven by the mascot\n * data's `selectable` field (Yorick is false). */\nexport function isSelectableCompanion(id: CompanyCharacterId): id is SelectableCompanionId {\n return COMPANY_MASCOTS[id].selectable;\n}\n\n/** The mascot record for a character id. */\nexport function getCompanyMascot(id: CompanyCharacterId): CompanyMascot {\n return COMPANY_MASCOTS[id];\n}\n\n// ── Companion-switch snark exchanges (VERBATIM) ──────────────────────────────\n// Keyed by the character being switched TO. Outgoing line first (the departing\n// companion), then the incoming retort.\nexport const COMPANION_SWITCH_EXCHANGES: Readonly<\n Record<SelectableCompanionId, readonly CompanionSwitchExchange[]>\n> = {\n // Switching TO Kit — Bill exits, Kit enters.\n kit: [\n {\n outgoing: { id: 'bill', line: \"Kit?! ...No, it's fine. It's fine. I'll be in the wings. Rehearsing. Alone.\" },\n incoming: { id: 'kit', line: 'Finally. Someone with taste.' },\n },\n {\n outgoing: { id: 'bill', line: 'Take care of them, Kit. They click gently.' },\n incoming: { id: 'kit', line: 'I know how to be adored, Bill.' },\n },\n {\n outgoing: { id: 'bill', line: 'The understudy yields the stage. Again.' },\n incoming: { id: 'kit', line: 'And yet history will say I earned it. Because I did.' },\n },\n {\n outgoing: { id: 'bill', line: \"You'll come back. They always— they usually come back.\" },\n incoming: { id: 'kit', line: \"Don't wait up.\" },\n },\n {\n outgoing: { id: 'bill', line: 'Break a leg, Kit.' },\n incoming: { id: 'kit', line: 'I never break anything but hearts and attendance records.' },\n },\n ],\n // Switching TO Bill — Kit exits, Bill enters.\n bill: [\n {\n outgoing: { id: 'kit', line: 'Unbelievable. UNBELIEVABLE.' },\n incoming: { id: 'bill', line: \"It's good to be back! ...He'll be alright.\" },\n },\n {\n outgoing: { id: 'kit', line: \"Enjoy the waving. That's all he does, you know.\" },\n incoming: { id: 'bill', line: \"I also bow now! I've been practicing.\" },\n },\n {\n outgoing: { id: 'kit', line: 'I was BRILLIANT and you choose the stick figure with the cap.' },\n incoming: { id: 'bill', line: \"He means 'welcome back.' We're working on it.\" },\n },\n {\n outgoing: { id: 'kit', line: 'Fine. FINE. The wings have better lighting anyway.' },\n incoming: { id: 'bill', line: \"They really don't. I'd know.\" },\n },\n {\n outgoing: { id: 'kit', line: 'This is the founding audition all over again.' },\n incoming: { id: 'bill', line: \"You'll get the next one, Kit. ...Probably not. But maybe!\" },\n },\n ],\n};\n\n// ── Yorick block lines (VERBATIM) ────────────────────────────────────────────\n// Spoken by the ACTIVE companion when the user presses Yorick's cast button.\nexport const YORICK_BLOCK_LINES: Readonly<Record<SelectableCompanionId, readonly string[]>> = {\n bill: [\n \"Soft you now — he's a Stand-In! He's only keeping the light warm. Thou art stuck with me. Nay — blessed with me.\",\n \"Yorick?! He doesn't even know his blocking. Literally. He asks me where to stand.\",\n \"You can't cast Yorick — he's on a Limited Engagement. Very limited. He leaves when the real role is cast.\",\n 'Alas, poor choice — I knew him better than you do. Pick a Player.',\n ],\n kit: [\n 'The skeleton crew? No. Absolutely not. You have TWO trained professionals right here.',\n \"He doesn't even know his blocking. I've watched him bow into the curtain. Twice.\",\n \"Yorick's not staying. Don't get attached to the help.\",\n \"You'd pass over ME for the temp? ...I need to sit down. On the couch he's not allowed on.\",\n ],\n};\n\n// ── Signed-out dock lines (VERBATIM) ─────────────────────────────────────────\n// Spoken by whichever Player is on the dock when NO user is signed in — the\n// pre-login pitch.\nexport const SIGNED_OUT_DOCK_LINES: readonly string[] = [\n \"The show's inside — and it's free. No ads, just an email.\",\n \"I'd introduce you to the whole Company, but you'll need a ticket. Tickets are free.\",\n 'Everything in this town is made by real people. Come see.',\n];\n\n// ── Onboarding cameo lines (VERBATIM) ────────────────────────────────────────\nexport const ONBOARDING_CAMEOS: OnboardingCameos = {\n kitAuditionStage:\n \"The Audition Stage. Where stars are born. I was robbed here once — anyway, you'll love it.\",\n yorickHall:\n 'The Hall — every tale, tune, and show the town keeps. Four hundred years of my material, and not one shelf. Enjoy.',\n curtainCall: {\n bill: 'Break a leg out there.',\n kit: 'Try not to embarrass us.',\n yorick: \"You'll forget me. It's fine. Go.\",\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"company-mascots.js","sourceRoot":"","sources":["../../src/constants/company-mascots.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,2EAA2E;AAC3E,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,+EAA+E;AAC/E,0BAA0B;AAC1B,EAAE;AACF,6EAA6E;AAC7E,uEAAuE;AACvE,gFAAgF;AAChF,6EAA6E;AAC7E,wEAAwE;AACxE,sDAAsD;AACtD,EAAE;AACF,6EAA6E;AAC7E,0EAA0E;AAC1E,wEAAwE;AACxE,mCAAmC;AACnC,+EAA+E;AAO/E,0DAA0D;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAkC,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AAU9F,uFAAuF;AACvF,MAAM,CAAC,MAAM,2BAA2B,GAAwC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAKvG,8CAA8C;AAC9C,MAAM,CAAC,MAAM,wBAAwB,GAAqC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAoF1F,iFAAiF;AAEjF,qDAAqD;AACrD,MAAM,OAAO,GAAG,CAAC,IAAY,EAAiC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAE1F;;kFAEkF;AAClF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,IAAY,EAAiC,EAAE,CAAC;IAChF,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE;IAClD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gCAAgC,EAAE;IACxD,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE;IACzD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE;CACnC,CAAC;AAEF,MAAM,mBAAmB,GAAkC;IACzD,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;IAC3D,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;IAC3D,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;CAC/D,CAAC;AAEF,iFAAiF;AACjF,0EAA0E;AAC1E,MAAM,gBAAgB,GACpB,+GAA+G,CAAC;AAClH,MAAM,eAAe,GACnB,gIAAgI,CAAC;AAEnI,gFAAgF;AAChF,6EAA6E;AAC7E,MAAM,IAAI,GAAkB;IAC1B,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,gBAAgB;IACvB,WAAW,EAAE,gBAAgB;IAC7B,YAAY,EAAE,iBAAiB;IAC/B,QAAQ,EAAE,6CAA6C;IACvD,cAAc,EAAE;QACd;YACE,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,OAAO,CACf,6bAA6b,CAC9b;SACF;KACF;IACD,eAAe,EAAE,IAAI;IACrB,oBAAoB,EAAE,kBAAkB;IACxC,kBAAkB,EAAE,IAAI;IACxB,mBAAmB,EAAE,oCAAoC;IACzD,YAAY,EAAE,mBAAmB;IACjC,KAAK,EAAE;QACL,OAAO,CAAC,6EAA6E,CAAC;QACtF,OAAO,CAAC,mFAAmF,CAAC;QAC5F,OAAO,CAAC,oEAAoE,CAAC;QAC7E,OAAO,CAAC,yEAAyE,CAAC;QAClF,OAAO,CAAC,iFAAiF,CAAC;QAC1F,OAAO,CAAC,0FAA0F,CAAC;QACnG,OAAO,CAAC,yFAAyF,CAAC;QAClG,OAAO,CAAC,kEAAkE,CAAC;QAC3E,OAAO,CAAC,8EAA8E,CAAC;QACvF,OAAO,CAAC,sEAAsE,CAAC;QAC/E;YACE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2EAA2E,EAAE;YACnG,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE;YACjC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE;SAC3C;QACD,OAAO,CAAC,oFAAoF,CAAC;QAC7F,OAAO,CAAC,wHAAwH,CAAC;QACjI,OAAO,CAAC,2EAA2E,CAAC;KACrF;IACD,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAC5C,UAAU,EAAE,IAAI;CACjB,CAAC;AAEF,gFAAgF;AAChF,MAAM,GAAG,GAAkB;IACzB,EAAE,EAAE,KAAK;IACT,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,QAAQ;IACrB,YAAY,EAAE,QAAQ;IACtB,QAAQ,EAAE,wCAAwC;IAClD,cAAc,EAAE;QACd;YACE,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,OAAO,CACf,wYAAwY,CACzY;SACF;QACD;YACE,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,OAAO,CACf,qMAAqM,CACtM;SACF;KACF;IACD,eAAe,EAAE,IAAI;IACrB,oBAAoB,EAAE,kBAAkB;IACxC,kBAAkB,EAAE,IAAI;IACxB,mBAAmB,EAAE,oCAAoC;IACzD,YAAY,EAAE,mBAAmB;IACjC,KAAK,EAAE;QACL,OAAO,CAAC,wFAAwF,CAAC;QACjG,OAAO,CAAC,+FAA+F,CAAC;QACxG,OAAO,CAAC,sFAAsF,CAAC;QAC/F,OAAO,CAAC,8EAA8E,CAAC;QACvF,OAAO,CAAC,0CAA0C,CAAC;QACnD,OAAO,CAAC,gFAAgF,CAAC;QACzF,OAAO,CAAC,+EAA+E,CAAC;QACxF,OAAO,CAAC,yFAAyF,CAAC;QAClG,OAAO,CAAC,kFAAkF,CAAC;QAC3F,OAAO,CAAC,8DAA8D,CAAC;QACvE,OAAO,CAAC,uFAAuF,CAAC;QAChG,OAAO,CAAC,yEAAyE,CAAC;QAClF,OAAO,CAAC,wFAAwF,CAAC;QACjG,OAAO,CAAC,8FAA8F,CAAC;KACxG;IACD,MAAM,EAAE,UAAU,CAAC,KAAK,EAAE,eAAe,CAAC;IAC1C,UAAU,EAAE,IAAI;CACjB,CAAC;AAEF,gFAAgF;AAChF,2EAA2E;AAC3E,MAAM,MAAM,GAAkB;IAC5B,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,wBAAwB;IAC9B,KAAK,EAAE,iBAAiB;IACxB,WAAW,EAAE,SAAS;IACtB,YAAY,EAAE,+BAA+B;IAC7C,QAAQ,EAAE,wDAAwD;IAClE,cAAc,EAAE;QACd;YACE,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,OAAO,CACf,+XAA+X,CAChY;SACF;KACF;IACD,eAAe,EAAE,IAAI;IACrB,oBAAoB,EAAE,yBAAyB;IAC/C,kBAAkB,EAAE,KAAK;IACzB,mBAAmB,EAAE,kEAAkE;IACvF,YAAY,EAAE,mBAAmB;IACjC,KAAK,EAAE;QACL,OAAO,CAAC,sFAAsF,CAAC;QAC/F,OAAO,CAAC,qGAAqG,CAAC;QAC9G,OAAO,CAAC,+DAA+D,CAAC;QACxE,OAAO,CAAC,gCAAgC,CAAC;QACzC,OAAO,CAAC,4EAA4E,CAAC;QACrF,OAAO,CAAC,6FAA6F,CAAC;KACvG;IACD,UAAU,EAAE,KAAK;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAwD;IAClF,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,GAAG;IACR,MAAM,EAAE,MAAM;CACf,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAkC,qBAAqB,CAAC;AAEzF,gFAAgF;AAEhF,yDAAyD;AACzD,MAAM,UAAU,oBAAoB,CAAC,CAAU;IAC7C,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAK,qBAA2C,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED;mDACmD;AACnD,MAAM,UAAU,qBAAqB,CAAC,EAAsB;IAC1D,OAAO,eAAe,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;AACxC,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,gBAAgB,CAAC,EAAsB;IACrD,OAAO,eAAe,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,gFAAgF;AAChF,+EAA+E;AAC/E,wCAAwC;AACxC,MAAM,CAAC,MAAM,0BAA0B,GAEnC;IACF,6CAA6C;IAC7C,GAAG,EAAE;QACH;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,6EAA6E,EAAE;YAC7G,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,8BAA8B,EAAE;SAC9D;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,4CAA4C,EAAE;YAC5E,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,gCAAgC,EAAE;SAChE;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,yCAAyC,EAAE;YACzE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,sDAAsD,EAAE;SACtF;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,wDAAwD,EAAE;YACxF,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE;SAChD;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE;YACnD,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,2DAA2D,EAAE;SAC3F;KACF;IACD,8CAA8C;IAC9C,IAAI,EAAE;QACJ;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,6BAA6B,EAAE;YAC5D,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,4CAA4C,EAAE;SAC7E;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,iDAAiD,EAAE;YAChF,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,uCAAuC,EAAE;SACxE;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,+DAA+D,EAAE;YAC9F,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,+CAA+C,EAAE;SAChF;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,oDAAoD,EAAE;YACnF,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,EAAE;SAC/D;QACD;YACE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,+CAA+C,EAAE;YAC9E,QAAQ,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,2DAA2D,EAAE;SAC5F;KACF;CACF,CAAC;AAEF,gFAAgF;AAChF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAA+D;IAC5F,IAAI,EAAE;QACJ,kHAAkH;QAClH,mFAAmF;QACnF,2GAA2G;QAC3G,mEAAmE;KACpE;IACD,GAAG,EAAE;QACH,uFAAuF;QACvF,kFAAkF;QAClF,uDAAuD;QACvD,2FAA2F;KAC5F;CACF,CAAC;AAEF,gFAAgF;AAChF,4EAA4E;AAC5E,mBAAmB;AACnB,MAAM,CAAC,MAAM,qBAAqB,GAAsB;IACtD,2DAA2D;IAC3D,qFAAqF;IACrF,2DAA2D;CAC5D,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAAqB;IACjD,gBAAgB,EACd,4FAA4F;IAC9F,UAAU,EACR,oHAAoH;IACtH,WAAW,EAAE;QACX,IAAI,EAAE,wBAAwB;QAC9B,GAAG,EAAE,0BAA0B;QAC/B,MAAM,EAAE,kCAAkC;KAC3C;CACF,CAAC;AAEF,iFAAiF;AACjF,8FAA8F;AAC9F,8CAA8C;AAE9C,8DAA8D;AAC9D,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,CAAU,CAAC;AAqBhG,oDAAoD;AACpD,MAAM,CAAC,MAAM,0BAA0B,GAA4B;IACjE;QACE,OAAO,EAAE,MAAM;QACf,IAAI,EACF,qHAAqH;KACxH;IACD,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,wCAAwC,EAAE;IAClE,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,mCAAmC,EAAE;CACjE,CAAC;AAEF,+BAA+B;AAC/B,MAAM,CAAC,MAAM,eAAe,GAAgC;IAC1D;QACE,MAAM,EAAE,aAAa;QACrB,OAAO,EAAE,MAAM;QACf,OAAO,EAAE,+DAA+D;QACxE,IAAI,EAAE;YACJ,yIAAyI;SAC1I;KACF;IACD;QACE,MAAM,EAAE,aAAa;QACrB,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,qDAAqD;QAC9D,IAAI,EAAE;YACJ,0JAA0J;SAC3J;QACD,mBAAmB,EACjB,qFAAqF;KACxF;IACD;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,QAAQ;QACjB,OAAO,EACL,8HAA8H;QAChI,IAAI,EAAE;YACJ,+GAA+G;YAC/G,4GAA4G;YAC5G,4DAA4D;SAC7D;KACF;IACD;QACE,MAAM,EAAE,aAAa;QACrB,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,wDAAwD;QACjE,IAAI,EAAE;YACJ,qLAAqL;SACtL;KACF;CACF,CAAC;AAEF,2CAA2C;AAC3C,MAAM,CAAC,MAAM,4BAA4B,GAA4B;IACnE;QACE,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,oFAAoF;KAC3F;IACD,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,6BAA6B,EAAE;IACvD,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,2CAA2C,EAAE;CACzE,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAe,CAAC,MAAM,CAAC","sourcesContent":["// ============================================================================\n// THE COMPANY — canonical Green Room mascot contract + content (ARCH-102).\n//\n// The ONE home for the pure, server-safe Company business truths (id unions,\n// billing kinds, performance intents, selectability, roster order) AND the\n// VERBATIM character content (studies, click lines, footers, companion-switch\n// exchanges, Yorick block lines, signed-out dock lines, onboarding cameos, the\n// first-visit site tour).\n//\n// This module is pure data: NO React, NO JSX, NO Next links, NO CSS, NO SVG,\n// NO functions inside the data. Rich copy is modelled as discriminated\n// `CompanyCopySegment`s so a web renderer, a phone app, or an AI voice can each\n// present the exact approved words without importing a UI framework. The app\n// owns the puppets, rig, choreography, and the adapter that turns these\n// segments into `<p>`, `<em>`, and route-aware links.\n//\n// Canonical dialogue stays a versioned code constant here (never Firestore):\n// it is the personality source, the safe AI-unavailable fallback, and the\n// voice-regression fixture. Never reword — curly quotes/apostrophes are\n// authored exactly as they render.\n// ============================================================================\n\n// ── Contract: id unions, billing, intents, selectability ─────────────────────\n\n/** Every member of the Company, in roster order. */\nexport type CompanyCharacterId = 'bill' | 'kit' | 'yorick';\n\n/** The roster, in billing order (Bill → Kit → Yorick). */\nexport const COMPANY_CHARACTER_IDS: readonly CompanyCharacterId[] = ['bill', 'kit', 'yorick'];\n\n/** Billing tiers: the founding Player, permanent Players, and Stand-Ins\n * (Limited Engagement — never selectable as the companion). */\nexport type CompanyBillingKind = 'foundingPlayer' | 'player' | 'standIn';\n\n/** Demoable move intents — keyed by intent from day one so future event\n * performances (page-grabs, standing ovations) land as content, not code. */\nexport type CompanyPerformanceIntent = 'bow' | 'hop' | 'wave';\n\n/** The performance intents, in demo-button order; consumers derive from this array. */\nexport const COMPANY_PERFORMANCE_INTENTS: readonly CompanyPerformanceIntent[] = ['bow', 'hop', 'wave'];\n\n/** The characters a user may cast as their dock companion (never a Stand-In). */\nexport type SelectableCompanionId = 'bill' | 'kit';\n\n/** The castable dock companions, in order. */\nexport const SELECTABLE_COMPANION_IDS: readonly SelectableCompanionId[] = ['bill', 'kit'];\n\n// ── Rich-copy pure-data model ────────────────────────────────────────────────\n\n/** Semantic destinations the copy can link to. Each client maps these to its\n * own route/navigation — the package never carries an href in mascot copy. */\nexport type CompanyNavigationTarget = 'greenRoom' | 'futurePlans';\n\n/** A single run of copy. `link` carries a semantic target, not a URL. */\nexport type CompanyCopySegment =\n | { readonly kind: 'text'; readonly text: string }\n | { readonly kind: 'emphasis'; readonly text: string }\n | { readonly kind: 'link'; readonly label: string; readonly target: CompanyNavigationTarget };\n\n/** A block of copy — a paragraph or a set-aside aside. */\nexport type CompanyCopyBlockKind = 'paragraph' | 'aside';\n\nexport interface CompanyCopyBlock {\n readonly kind: CompanyCopyBlockKind;\n readonly segments: readonly CompanyCopySegment[];\n}\n\n// ── Registry shapes ──────────────────────────────────────────────────────────\n\nexport interface CompanyPerformance {\n readonly id: string;\n readonly label: string;\n readonly intent: CompanyPerformanceIntent;\n /** Community \"Choreography by\" credit — null until an audition stages it. */\n readonly creditUid: string | null;\n}\n\nexport interface CompanyMascot {\n readonly id: CompanyCharacterId;\n /** Full stage name shown on nameplates + the playbill (\"Bill the Understudy\"). */\n readonly name: string;\n /** The ironic-understatement epithet (the Company tradition). */\n readonly title: string;\n readonly billingKind: CompanyBillingKind;\n /** Billing line rendered beside the name (\"Founding Player\"). */\n readonly billingLabel: string;\n /** One-line structural descriptor (not character voice). */\n readonly shortBio: string;\n /** Playbill character study (human-written; the future AI personality source). */\n readonly characterStudy: readonly CompanyCopyBlock[];\n /** \"Role originated by\" — resolves live via the app when set. */\n readonly originatedByUid: string | null;\n /** Text shown after \"Role originated by — \" when originatedByUid is null. */\n readonly originatedByFallback: string;\n /** Whether the origination frame invites the reader (\"→ your name here?\"). */\n readonly invitesOrigination: boolean;\n /** The performances credit caption under the demo buttons. */\n readonly choreographyCaption: string;\n readonly performances: readonly CompanyPerformance[];\n /** Rotating click lines (dock companion bubble + on-stage line pop). Each\n * line is a segment run — most are a single text segment. */\n readonly lines: readonly (readonly CompanyCopySegment[])[];\n /** Dock speech-bubble footer segments. The character's short name is a\n * `greenRoom` link segment; the app renders it as a link when signed in and\n * as plain text when signed out. \"one day\" always links to `futurePlans`.\n * Absent for Stand-Ins (Yorick — never the dock companion). */\n readonly footer?: readonly CompanyCopySegment[];\n /** False for Stand-Ins (Yorick) — never storable as the dock companion. */\n readonly selectable: boolean;\n}\n\n/** Companion-switch snark exchange, keyed (in COMPANION_SWITCH_EXCHANGES) by the\n * character switched TO. Outgoing line first (the departing companion), then the\n * incoming retort. Plain strings. */\nexport interface CompanionSwitchExchange {\n readonly outgoing: { readonly id: SelectableCompanionId; readonly line: string };\n readonly incoming: { readonly id: SelectableCompanionId; readonly line: string };\n}\n\n/** Onboarding cameo lines — Company members crashing the registration tour. */\nexport interface OnboardingCameos {\n /** Kit crashes The Audition Stage step. */\n readonly kitAuditionStage: string;\n /** Yorick cameos on The Hall step. */\n readonly yorickHall: string;\n /** The send-off curtain call — all three bow. */\n readonly curtainCall: Readonly<Record<CompanyCharacterId, string>>;\n}\n\n// ── Segment construction helpers (module-private; output is pure data) ────────\n\n/** A line/footer that is a single plain-text run. */\nconst textRun = (text: string): readonly CompanyCopySegment[] => [{ kind: 'text', text }];\n\n/** A character's dock footer, built from the one verbatim sentence. The name is\n * a `greenRoom` link segment (the app renders it plain when signed out); \"one\n * day\" always links to `futurePlans`; `tail` is the character-specific close. */\nconst dockFooter = (name: string, tail: string): readonly CompanyCopySegment[] => [\n { kind: 'link', label: name, target: 'greenRoom' },\n { kind: 'text', text: ' is a basic version for now — ' },\n { kind: 'link', label: 'one day', target: 'futurePlans' },\n { kind: 'text', text: ` ${tail}` },\n];\n\nconst SHARED_PERFORMANCES: readonly CompanyPerformance[] = [\n { id: 'bow', label: 'Bow', intent: 'bow', creditUid: null },\n { id: 'hop', label: 'Hop', intent: 'hop', creditUid: null },\n { id: 'wave', label: 'Wave', intent: 'wave', creditUid: null },\n];\n\n// The dock-footer close sentences, VERBATIM (the pre-Company Bill wording; Kit's\n// from the settled spec). Curly apostrophes authored exactly as rendered.\nconst BILL_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide who helps you navigate the site. He’ll never make content, just help.';\nconst KIT_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide with this exact attitude. He’ll never make content. He does have opinions about yours.';\n\n// ── Bill the Understudy — Founding Player ────────────────────────────────────\n// The 14 approved lines are VERBATIM (incl. the italic emphasis in line 11).\nconst BILL: CompanyMascot = {\n id: 'bill',\n name: 'Bill the Understudy',\n title: 'The Understudy',\n billingKind: 'foundingPlayer',\n billingLabel: 'Founding Player',\n shortBio: \"TTT's founding player and your first guide.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'The most enthusiastic understudy in show business, and TTT Productions’ founding player. Bill has read the whole script of this town — well, skimmed it — and rehearses every day for the role of your guide to everything here. He insists the ‘Bill’ is short for William, and that he once wrote plays in a town called Stratford. We have chosen to let him believe it. Someday he’ll answer anything you ask about this place. Today, he mostly waves.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"One day I'll help you find your perfect collaborator. Today, I mostly wave.\"),\n textRun(\"I'm just an understudy for now — but someday I'll know every corner of this town.\"),\n textRun('Rehearsing my big role: your guide to everything TTT. No spoilers.'),\n textRun(\"They say one day I'll have real personalities. Plural. I'm excited too.\"),\n textRun(\"I'll never make the art — that's your job. I'll just help you find your people.\"),\n textRun(\"Every great production starts with somebody standing in the wings. That's me. Literally.\"),\n textRun(\"Someday you'll ask me anything about this place and I'll actually answer. Bold, I know.\"),\n textRun('The Town Crier gets to shout. I get to practice my bow. For now.'),\n textRun(\"I've read the whole script of this town. Well... skimmed. I'm working on it.\"),\n textRun('Big dreams for a stick figure: guide, helper, friend. In that order.'),\n [\n { kind: 'text', text: \"When the curtain rises on my real role, you'll be the first to know. You \" },\n { kind: 'emphasis', text: 'did' },\n { kind: 'text', text: ' click me first.' },\n ],\n textRun('Until my big debut, consider me the most enthusiastic understudy in show business.'),\n textRun(\"Even the greatest playwright who ever lived starts over as an understudy in a town this good. That's my story, anyway.\"),\n textRun('Four hundred years of theatre experience. My résumé? A drawing of myself.'),\n ],\n footer: dockFooter('Bill', BILL_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Kit the Stand-In — permanent Player #2, Bill's rival ─────────────────────\nconst KIT: CompanyMascot = {\n id: 'kit',\n name: 'Kit the Stand-In',\n title: 'The Stand-In',\n billingKind: 'player',\n billingLabel: 'Player',\n shortBio: \"Permanent Player #2, and Bill's rival.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'Sharp, quick, and absolutely certain he should have gone first. Kit auditioned for founding mascot, delivered the finest monologue the empty theatre had ever heard, and lost the part to a stick figure with a “trustworthy wave.” He has been gracious about it every single day since — loudly, to anyone in range. Keeps the rejection letter framed. Ask him about it. He’s dying for you to ask.',\n ),\n },\n {\n kind: 'aside',\n segments: textRun(\n 'Loosely nodding to a certain rival playwright — brilliant, theatrical, gone too soon. One day, an AI-powered guide with this exact personality: genuinely helpful, faintly insulted by the request.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Yes, I'm the Stand-In. Permanently. The irony isn't lost on me — it lives with me now.\"),\n textRun(\"I was FIRST in line at the founding audition. They went with a stick figure who 'waves well.'\"),\n textRun(\"Bill rehearses roles nobody wrote. I've already memorized them. We are not the same.\"),\n textRun(\"One day this whole town will know my name. Today it's 'the other one.' Fine.\"),\n textRun(\"I don't do warm-ups. I arrive brilliant.\"),\n textRun('Founding mascot. FOUNDING. He waved at a login page and they gave him a title.'),\n textRun('My five-year plan is center stage. My five-century plan is also center stage.'),\n textRun('History remembers a playwright who died before his rival got famous. Anyway. No reason.'),\n textRun('Click Bill for encouragement. Click me to hear the truth, beautifully delivered.'),\n textRun('I keep my rejection letter framed. Motivation is motivation.'),\n textRun(\"You clicked me first today. I rehearsed being gracious about this — give me a moment.\"),\n textRun(\"When the curtain finally rises on my lead role, act surprised. I won't.\"),\n textRun('They say I might have been a spy in a past life. I neither confirm nor deny. Mystique.'),\n textRun('The Understudy and the Stand-In on one stage. Somewhere a playwright is laughing at us both.'),\n ],\n footer: dockFooter('Kit', KIT_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Yorick the Forgettable — Stand-In · Limited Engagement ───────────────────\n// Never selectable, never the dock companion; his lines are on-stage only.\nconst YORICK: CompanyMascot = {\n id: 'yorick',\n name: 'Yorick the Forgettable',\n title: 'The Forgettable',\n billingKind: 'standIn',\n billingLabel: 'Stand-In · Limited Engagement',\n shortBio: 'A Limited Engagement Stand-In, keeping the light warm.',\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n \"A fellow of infinite jest, reduced to holding a light he isn't allowed to stand in. Yorick insists he was the funniest jester who ever lived — and unfortunately, everyone who could confirm it is unavailable for comment. He is keeping the stage warm until the role is properly cast, and he'd rather you didn't get attached. You'll forget him anyway. Everyone does. It's in the name.\",\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'no one will admit to it',\n invitesOrigination: false,\n choreographyCaption: 'Bow · Hop · Wave — borrowed from Bill, who says he can have them',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Oh! A visitor. Nobody visits the Wings. I'd know — I keep the guestbook. It's empty.\"),\n textRun(\"I used to kill at court, you know. Standing ovations. Kings weeping. ...You'll take my word for it.\"),\n textRun(\"Don't get attached. I'm told I'm temporary. The skull agrees.\"),\n textRun('Alas, poor me. I knew me well.'),\n textRun('Infinite jest, they said. INFINITE. And yet here I am, finite-ly employed.'),\n textRun(\"One day they'll cast this role properly and I'll be forgotten. Ahead of schedule, honestly.\"),\n ],\n selectable: false,\n};\n\nexport const COMPANY_MASCOTS: Readonly<Record<CompanyCharacterId, CompanyMascot>> = {\n bill: BILL,\n kit: KIT,\n yorick: YORICK,\n};\n\n/** Registry order (Bill → Kit → Yorick), reused from the roster. */\nexport const COMPANY_MASCOT_ORDER: readonly CompanyCharacterId[] = COMPANY_CHARACTER_IDS;\n\n// ── Pure helpers ─────────────────────────────────────────────────────────────\n\n/** True when `x` is a canonical Company character id. */\nexport function isCompanyCharacterId(x: unknown): x is CompanyCharacterId {\n return typeof x === 'string' && (COMPANY_CHARACTER_IDS as readonly string[]).includes(x);\n}\n\n/** True when `id` may be cast as the dock companion — driven by the mascot\n * data's `selectable` field (Yorick is false). */\nexport function isSelectableCompanion(id: CompanyCharacterId): id is SelectableCompanionId {\n return COMPANY_MASCOTS[id].selectable;\n}\n\n/** The mascot record for a character id. */\nexport function getCompanyMascot(id: CompanyCharacterId): CompanyMascot {\n return COMPANY_MASCOTS[id];\n}\n\n// ── Companion-switch snark exchanges (VERBATIM) ──────────────────────────────\n// Keyed by the character being switched TO. Outgoing line first (the departing\n// companion), then the incoming retort.\nexport const COMPANION_SWITCH_EXCHANGES: Readonly<\n Record<SelectableCompanionId, readonly CompanionSwitchExchange[]>\n> = {\n // Switching TO Kit — Bill exits, Kit enters.\n kit: [\n {\n outgoing: { id: 'bill', line: \"Kit?! ...No, it's fine. It's fine. I'll be in the wings. Rehearsing. Alone.\" },\n incoming: { id: 'kit', line: 'Finally. Someone with taste.' },\n },\n {\n outgoing: { id: 'bill', line: 'Take care of them, Kit. They click gently.' },\n incoming: { id: 'kit', line: 'I know how to be adored, Bill.' },\n },\n {\n outgoing: { id: 'bill', line: 'The understudy yields the stage. Again.' },\n incoming: { id: 'kit', line: 'And yet history will say I earned it. Because I did.' },\n },\n {\n outgoing: { id: 'bill', line: \"You'll come back. They always— they usually come back.\" },\n incoming: { id: 'kit', line: \"Don't wait up.\" },\n },\n {\n outgoing: { id: 'bill', line: 'Break a leg, Kit.' },\n incoming: { id: 'kit', line: 'I never break anything but hearts and attendance records.' },\n },\n ],\n // Switching TO Bill — Kit exits, Bill enters.\n bill: [\n {\n outgoing: { id: 'kit', line: 'Unbelievable. UNBELIEVABLE.' },\n incoming: { id: 'bill', line: \"It's good to be back! ...He'll be alright.\" },\n },\n {\n outgoing: { id: 'kit', line: \"Enjoy the waving. That's all he does, you know.\" },\n incoming: { id: 'bill', line: \"I also bow now! I've been practicing.\" },\n },\n {\n outgoing: { id: 'kit', line: 'I was BRILLIANT and you choose the stick figure with the cap.' },\n incoming: { id: 'bill', line: \"He means 'welcome back.' We're working on it.\" },\n },\n {\n outgoing: { id: 'kit', line: 'Fine. FINE. The wings have better lighting anyway.' },\n incoming: { id: 'bill', line: \"They really don't. I'd know.\" },\n },\n {\n outgoing: { id: 'kit', line: 'This is the founding audition all over again.' },\n incoming: { id: 'bill', line: \"You'll get the next one, Kit. ...Probably not. But maybe!\" },\n },\n ],\n};\n\n// ── Yorick block lines (VERBATIM) ────────────────────────────────────────────\n// Spoken by the ACTIVE companion when the user presses Yorick's cast button.\nexport const YORICK_BLOCK_LINES: Readonly<Record<SelectableCompanionId, readonly string[]>> = {\n bill: [\n \"Soft you now — he's a Stand-In! He's only keeping the light warm. Thou art stuck with me. Nay — blessed with me.\",\n \"Yorick?! He doesn't even know his blocking. Literally. He asks me where to stand.\",\n \"You can't cast Yorick — he's on a Limited Engagement. Very limited. He leaves when the real role is cast.\",\n 'Alas, poor choice — I knew him better than you do. Pick a Player.',\n ],\n kit: [\n 'The skeleton crew? No. Absolutely not. You have TWO trained professionals right here.',\n \"He doesn't even know his blocking. I've watched him bow into the curtain. Twice.\",\n \"Yorick's not staying. Don't get attached to the help.\",\n \"You'd pass over ME for the temp? ...I need to sit down. On the couch he's not allowed on.\",\n ],\n};\n\n// ── Signed-out dock lines (VERBATIM) ─────────────────────────────────────────\n// Spoken by whichever Player is on the dock when NO user is signed in — the\n// pre-login pitch.\nexport const SIGNED_OUT_DOCK_LINES: readonly string[] = [\n \"The show's inside — and it's free. No ads, just an email.\",\n \"I'd introduce you to the whole Company, but you'll need a ticket. Tickets are free.\",\n 'Everything in this town is made by real people. Come see.',\n];\n\n// ── Onboarding cameo lines (VERBATIM) ────────────────────────────────────────\nexport const ONBOARDING_CAMEOS: OnboardingCameos = {\n kitAuditionStage:\n \"The Audition Stage. Where stars are born. I was robbed here once — anyway, you'll love it.\",\n yorickHall:\n 'The Hall — every tale, tune, and show the town keeps. Four hundred years of my material, and not one shelf. Enjoy.',\n curtainCall: {\n bill: 'Break a leg out there.',\n kit: 'Try not to embarrass us.',\n yorick: \"You'll forget me. It's fine. Go.\",\n },\n};\n\n// ── First-visit site tour ─────────────────────────────────────────────────────\n// The tour layer reads these records and never inlines its own strings. A `speaker` names the\n// mascot whose headshot sits beside the line.\n\n/** The permanent shell controls a tour step can highlight. */\nexport const SITE_TOUR_ANCHORS = ['homeAndHelp', 'accountArea', 'dock', 'pageActions'] as const;\nexport type SiteTourAnchor = (typeof SITE_TOUR_ANCHORS)[number];\n\nexport interface SiteTourLine {\n speaker: CompanyCharacterId;\n text: string;\n}\n\nexport interface SiteTourStepCopy {\n /** Which permanent shell control this step highlights. */\n anchor: SiteTourAnchor;\n /** The mascot who leads this step. */\n speaker: CompanyCharacterId;\n /** Bold lead-in headline. */\n heading: string;\n /** Body paragraphs (verbatim), each its own paragraph. */\n body: readonly string[];\n /** Non-Artisan replacement for the FINAL body paragraph, when present. */\n bodyNonArtisanFinal?: string;\n}\n\n/** The three-mascot greeting + invitation lines. */\nexport const SITE_TOUR_INVITATION_LINES: readonly SiteTourLine[] = [\n {\n speaker: 'bill',\n text:\n 'Welcome to TTT! Before the curtain rises, may we show you the few controls that will help you find your way around?',\n },\n { speaker: 'kit', text: 'Four quick stops. He rehearsed twelve.' },\n { speaker: 'yorick', text: 'I was told there would be snacks.' },\n];\n\n/** The four-step tour copy. */\nexport const SITE_TOUR_STEPS: readonly SiteTourStepCopy[] = [\n {\n anchor: 'homeAndHelp',\n speaker: 'bill',\n heading: \"TTT brings you home. Help is where you look when you're lost.\",\n body: [\n 'TTT always returns you to Center Stage. Help opens the Backstage Guide, where you can learn how the theatre works and replay this tour.',\n ],\n },\n {\n anchor: 'accountArea',\n speaker: 'kit',\n heading: 'Most of the theatre waits behind your account menu.',\n body: [\n 'Use it to visit The Town, open Your Corner, change settings, or sign out. Artisans also have a separate My Work button for reaching their Works quickly.',\n ],\n bodyNonArtisanFinal:\n 'If you become an Artisan, My Work will appear here for reaching your Works quickly.',\n },\n {\n anchor: 'dock',\n speaker: 'yorick',\n heading:\n 'Your companion lives here. Click them for a little company—or hide them from the notification tray when you need some quiet.',\n body: [\n 'The tray also lets you reduce motion across the whole theatre while keeping your companion visible and still.',\n 'The bell opens notifications. After you scroll down a page, an arrow appears to carry you back to the top.',\n 'I am, apparently, not eligible for the companion position.',\n ],\n },\n {\n anchor: 'pageActions',\n speaker: 'kit',\n heading: 'Some pages place their special actions in this corner.',\n body: [\n 'You may find controls for creating something, reviewing activity, or performing another action unique to that page. If the corner is empty, there is nothing waiting for you there.',\n ],\n },\n];\n\n/** The three-mascot curtain-call lines. */\nexport const SITE_TOUR_CURTAIN_CALL_LINES: readonly SiteTourLine[] = [\n {\n speaker: 'bill',\n text: 'That is the whole house. You can revisit this tour from Help whenever you need it.',\n },\n { speaker: 'kit', text: 'Four stops. Barely an epic.' },\n { speaker: 'yorick', text: 'I still think we missed the refreshments.' },\n];\n\nexport const SITE_TOUR_TOTAL_STEPS = SITE_TOUR_STEPS.length;\n"]}
|
|
@@ -63,6 +63,12 @@ export declare const MediaVariantKeySchema: z.ZodEnum<{
|
|
|
63
63
|
main: "main";
|
|
64
64
|
}>;
|
|
65
65
|
export type MediaVariantKey = z.infer<typeof MediaVariantKeySchema>;
|
|
66
|
+
/** The sizes a profile picture is produced in (`TTT_MEDIA_SPECS['profile-picture']`), largest first. */
|
|
67
|
+
export declare const PROFILE_PICTURE_VARIANT_KEYS: readonly ["full", "medium", "small"];
|
|
68
|
+
export type ProfilePictureVariantKey = (typeof PROFILE_PICTURE_VARIANT_KEYS)[number];
|
|
69
|
+
/** Which variant renders a stored image as a single display: the largest servable one. An image
|
|
70
|
+
* origin carries exactly one of `main` / `full`; a profile picture adds the smaller sizes. */
|
|
71
|
+
export declare const MEDIA_DISPLAY_VARIANT_PRECEDENCE: readonly ["main", "full", "medium", "small"];
|
|
66
72
|
/** Why this asset was created from its source.
|
|
67
73
|
*
|
|
68
74
|
* Chat is text-only and owns no media, so no copy is ever made for a chat message. A
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-assets.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/media-assets.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"media-assets.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/media-assets.ts"],"names":[],"mappings":"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"}
|
|
@@ -63,6 +63,14 @@ export const MEDIA_VARIANT_KEYS = [
|
|
|
63
63
|
VIDEO_POSTER_OUTPUT_KEY,
|
|
64
64
|
];
|
|
65
65
|
export const MediaVariantKeySchema = z.enum(MEDIA_VARIANT_KEYS);
|
|
66
|
+
/** The sizes a profile picture is produced in (`TTT_MEDIA_SPECS['profile-picture']`), largest first. */
|
|
67
|
+
export const PROFILE_PICTURE_VARIANT_KEYS = ['full', 'medium', 'small'];
|
|
68
|
+
/** Which variant renders a stored image as a single display: the largest servable one. An image
|
|
69
|
+
* origin carries exactly one of `main` / `full`; a profile picture adds the smaller sizes. */
|
|
70
|
+
export const MEDIA_DISPLAY_VARIANT_PRECEDENCE = [
|
|
71
|
+
TIMED_MEDIA_MAIN_OUTPUT_KEY,
|
|
72
|
+
...PROFILE_PICTURE_VARIANT_KEYS,
|
|
73
|
+
];
|
|
66
74
|
/** Why this asset was created from its source.
|
|
67
75
|
*
|
|
68
76
|
* Chat is text-only and owns no media, so no copy is ever made for a chat message. A
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-assets.js","sourceRoot":"","sources":["../../src/doc-schemas/media-assets.ts"],"names":[],"mappings":"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","sourcesContent":["// mediaAssets/{mediaAssetId} — the canonical media registry. One doc per\n// logical uploaded media item; all variants inside. Content docs reference\n// media ONLY by `*AssetId` fields — never URLs. Serving authority is the\n// gateway Worker (cookie/grant + KV blocklist); this doc is the server-side\n// truth the edge records derive from. NO client reads, NO client writes.\n\nimport { z } from 'zod';\nimport { StructuredErrorSchema } from '@ttt-productions/edge-protocol-core';\nimport { TIMED_MEDIA_MAIN_OUTPUT_KEY, VIDEO_POSTER_OUTPUT_KEY } from '@ttt-productions/media-schemas';\nimport { FileOriginSchema } from '../media/file-origin.js';\n\n/** Who may be served the bytes (the Worker's tier check). */\nexport const MediaAccessTierSchema = z.enum(['broad', 'scoped', 'artisan', 'adminOnly']);\nexport type MediaAccessTier = z.infer<typeof MediaAccessTierSchema>;\n\n/** Canonical serving state. The edge record derives from this; hide/restore/\n * quarantine flows write it together with the blocklist. */\nexport const MediaServingStatusSchema = z.enum(['servable', 'hidden', 'quarantined', 'deleted']);\nexport type MediaServingStatus = z.infer<typeof MediaServingStatusSchema>;\n\n/** The surface that owns this asset. One asset never serves two scopes —\n * publishing to the Hall (or future realm promotion) creates a NEW asset\n * owned by the destination surface. */\nexport const MediaAssetOwnerTypeSchema = z.enum([\n 'userProfile',\n 'craftSkill',\n 'squareStreetzPost',\n 'workProject',\n 'workContent', // tale chapter / tune track / television episode media (pre-publish)\n 'hallItem',\n 'commissionListing',\n 'commissionProposal',\n 'audition',\n 'auditionEntry',\n // A file in a conversation's flat Conversation Files list (guild-invite or\n // admin-support). Chat messages own no media.\n 'conversationFile',\n // Realm shared files are the deliberate MUTATE-IN-PLACE exception: a promoted work file\n // keeps its ONE `workFile`-owned asset doc and flips tier in place, so no asset is ever\n // owned by `realmFile` today. The owner type stays declared for a future realm-owned\n // media surface; it is NOT the seam realm sharing rides (that is `realmFileCanonStatus`\n // + `realmId` + `realmFileFolderId` on the work file's own asset).\n 'realmFile',\n 'safetyEvidence', // inert system sentinel — synthetic NCII-evidence assets (never an account surface)\n // An admin video held by a system video slot; the owner id is the slot id.\n 'systemContent',\n]);\nexport type MediaAssetOwnerType = z.infer<typeof MediaAssetOwnerTypeSchema>;\n\n// ===== Media origin lineage =====\n// One canonical lineage used by media, CSAM, and safety. Embedded on every\n// media asset + every copy.\n\n/** The ONE canonical stored content media kind (what the pipeline produces and the\n * asset doc records). Distinct from the 4-value display/transport MediaTypeSchema\n * (doc-schemas/social.ts, adds 'other') and media-schemas' generic MediaKindSchema. */\nexport const ContentMediaKindSchema = z.enum(['image', 'video', 'audio']);\nexport type ContentMediaKind = z.infer<typeof ContentMediaKindSchema>;\n\n/**\n * Every variant key the media pipeline writes under an asset id — never an open `string`: the image\n * variants `TTT_MEDIA_SPECS` declares, plus the video and audio outputs, which derive from the\n * pipeline's own output-key declarations (media-schemas) — the transcoded `main` and the video's\n * `poster` frame. A copy or an ingest intent names its objects with these, so a key outside the set\n * could be written but never reclaimed. `__tests__/media-origin-lineage.test.ts` fails when a spec\n * declares a key outside the set, a pipeline output falls outside it, or a member is produced by\n * nothing.\n */\nexport const MEDIA_VARIANT_KEYS = [\n 'full',\n 'medium',\n 'small',\n TIMED_MEDIA_MAIN_OUTPUT_KEY,\n VIDEO_POSTER_OUTPUT_KEY,\n] as const;\nexport const MediaVariantKeySchema = z.enum(MEDIA_VARIANT_KEYS);\nexport type MediaVariantKey = z.infer<typeof MediaVariantKeySchema>;\n\n/** Why this asset was created from its source.\n *\n * Chat is text-only and owns no media, so no copy is ever made for a chat message. A\n * Conversation File is an ORIGINAL (`original`), never a derivative. */\nexport const MediaCopyReasonSchema = z.enum([\n 'original',\n 'variant',\n 'hall_publish',\n 'profile_derivative',\n 'moderation_copy',\n 'evidence_copy',\n 'other',\n]);\nexport type MediaCopyReason = z.infer<typeof MediaCopyReasonSchema>;\n\n/**\n * Canonical media origin lineage. A copy INHERITS\n * rootIngestId/rootAssetId/originatingUploaderUid/originatingUploadEventId/\n * originalUploadCreatedAt/rootSha256/originalSha256 unchanged; it sets its own\n * sourceAssetId/variantSha256s/copyReason/copyActorUid/currentOwner*. Client\n * requests can NEVER set or override any lineage field. Automatic account\n * action targets ONLY `originatingUploaderUid`; incident-wide blocking\n * enumerates by `rootIngestId`. Missing/corrupt lineage → safetyLocked +\n * manual decision, never a guessed ban.\n */\nexport const MediaOriginLineageV1Schema = z.object({\n lineageVersion: z.literal(1),\n rootIngestId: z.string().min(1), // first-accepted ingest event id; stable across all copies\n rootAssetId: z.string().min(1), // first asset created from that ingest\n sourceAssetId: z.string().min(1).optional(), // immediate parent copied from (absent on the root)\n originatingUploaderUid: z.string().min(1), // set server-side at first accepted ingest; IMMUTABLE; inherited\n // May be '' for a copy synthesized from a source with no known upload event.\n originatingUploadEventId: z.string(),\n originalUploadCreatedAt: z.number(),\n // '' until content hashing fills in the real sha256.\n // NOT z.string().min(1): the media pipeline does not compute a content hash at finalize yet,\n // so a freshly-ingested asset legitimately carries an empty rootSha256 until it is hashed.\n rootSha256: z.string(),\n originalSha256: z.string().min(1).optional(),\n // PARTIAL map: one hash per PRODUCED variant (an asset produces only the variants its\n // origin declares — e.g. full/medium/small for a profile picture, 'main' for others —\n // never all four). Typed keys, never an open string. `z.partialRecord` (NOT `z.record`):\n // in Zod 4 `z.record(enum,…)` is EXHAUSTIVE (demands every enum key), which would reject\n // every real asset's partial variant set; `partialRecord` makes the keys optional.\n variantSha256s: z.partialRecord(MediaVariantKeySchema, z.string().min(1)),\n copyReason: MediaCopyReasonSchema,\n createdFromOwnerType: MediaAssetOwnerTypeSchema.optional(), // never a bare string\n createdFromOwnerId: z.string().min(1).optional(),\n copyActorUid: z.string().min(1).optional(), // who triggered the copy (distinct from the original uploader)\n currentOwnerType: MediaAssetOwnerTypeSchema, // mutable; the asset's present owner\n currentOwnerId: z.string().min(1),\n}).strict();\nexport type MediaOriginLineageV1 = z.infer<typeof MediaOriginLineageV1Schema>;\n\nexport const MediaAssetVariantSchema = z.object({\n contentType: z.string().min(1),\n sizeBytes: z.number().int().nonnegative(),\n width: z.number().int().positive().optional(),\n height: z.number().int().positive().optional(),\n durationSec: z.number().positive().optional(),\n /**\n * Server-owned filename the gateway puts in `Content-Disposition` for a\n * `?download=1` request. VARIANT-specific on purpose: the downloadable bytes are\n * a PROCESSED variant, so the extension must match THIS variant's actual\n * `contentType` — a transcoded JPEG/WebP/MP4 is never labelled with the original\n * upload's incompatible extension.\n *\n * Written ONLY by backend publishers, and ONLY for surfaces that intentionally\n * offer a Download action — Work Files (including the same asset shared to a\n * Realm), Conversation Files, and downloadable Hall media. Profiles, posts,\n * covers, and every other surface leave it ABSENT so no private original filename\n * is ever exposed; an absent value serves the safe bare `attachment` disposition.\n *\n * Always produced by `normalizeDownloadFilename` (media/download-filename.ts) —\n * that helper owns the sanitization rules and the UTF-8 byte cap, so no bound is\n * restated here. A client query parameter is NEVER the filename authority.\n * Filenames are user content: never log this value.\n */\n downloadFilename: z.string().min(1).optional(),\n}).strict();\nexport type MediaAssetVariant = z.infer<typeof MediaAssetVariantSchema>;\n\nexport const MediaRetentionPolicySchema = z.enum([\n 'standard', // staging original deleted ~24h after verified mirror\n 'preserveForTrustAndSafety',\n 'legalHold',\n]);\nexport type MediaRetentionPolicy = z.infer<typeof MediaRetentionPolicySchema>;\n\n// Realm shared-files: a work file's standing in its realm's shared pool. ONE seam — the\n// approval gate is a value in this union, never a parallel status field.\n// none — not shared to the realm (default)\n// pendingApproval — a Work file admin has REQUESTED promotion; the Realm steward has not\n// decided yet. The file is NOT served to the Realm (tier stays `scoped`)\n// and is invisible to the member gallery, whose query selects only\n// nonCanon|canon — so pending rows are excluded structurally, not by a\n// filter someone can forget.\n// nonCanon — approved into the realm's pool (in a steward-chosen folder), non-canon\n// canon — approved and marked canon (realm steward toggles canon ↔ nonCanon)\n// Moderation/takedown is NOT a value here — a hidden file is hidden via the shared\n// media path (`servingStatus: 'hidden'`), so the gallery filters on servingStatus.\n//\n// Each member is declared ONCE as a named constant below and every set is assembled from\n// those names, so a member constant and the sets that contain it cannot drift apart.\n\n/** Not shared to the realm — the default standing for every work file. */\nexport const REALM_FILE_NONE_STATUS = 'none' as const;\n/** The single AWAITING-DECISION standing. Exported as a VALUE as well as a schema so a\n * consumer can branch on it (`status === REALM_FILE_PENDING_APPROVAL_STATUS`) without\n * re-quoting the member — the redeclaration guard pins this literal to this file. */\nexport const REALM_FILE_PENDING_APPROVAL_STATUS = 'pendingApproval' as const;\n/** Approved into the realm's shared pool, not marked canon. */\nexport const REALM_FILE_NON_CANON_STATUS = 'nonCanon' as const;\n/** Approved into the realm's shared pool AND marked canon by the Realm steward. */\nexport const REALM_FILE_CANON_STATUS = 'canon' as const;\n\nexport const REALM_FILE_CANON_STATUS_VALUES = [\n REALM_FILE_NONE_STATUS,\n REALM_FILE_PENDING_APPROVAL_STATUS,\n REALM_FILE_NON_CANON_STATUS,\n REALM_FILE_CANON_STATUS,\n] as const;\nexport const RealmFileCanonStatusSchema = z.enum(REALM_FILE_CANON_STATUS_VALUES);\nexport type RealmFileCanonStatus = z.infer<typeof RealmFileCanonStatusSchema>;\n\n/** The two APPROVED (steward-accepted, realm-served) standings. The member gallery query\n * and its projection accept exactly these — never the full status union, so a pending or\n * unshared row can never be typed into an approved-files response. Derived from the one\n * union above; consumers import this instead of re-quoting the members (ARCH-102). */\nexport const REALM_FILE_APPROVED_STATUS_VALUES = [\n REALM_FILE_NON_CANON_STATUS,\n REALM_FILE_CANON_STATUS,\n] as const;\nexport const RealmFileApprovedStatusSchema = z.enum(REALM_FILE_APPROVED_STATUS_VALUES);\nexport type RealmFileApprovedStatus = z.infer<typeof RealmFileApprovedStatusSchema>;\n\n/** The steward promotion-queue projection accepts only this, so an approved or unshared row\n * can never be typed into the queue. */\nexport const RealmFilePendingApprovalStatusSchema = z.literal(REALM_FILE_PENDING_APPROVAL_STATUS);\nexport type RealmFilePendingApprovalStatus = z.infer<typeof RealmFilePendingApprovalStatusSchema>;\n\n/** Every standing EXCEPT `none` — a file that has entered the request/approval lifecycle at\n * all. Derived from the two subsets above, so adding a future standing to one of them\n * reaches this set automatically. Used by the Work-side share-state projection, whose rows\n * exist only for files that are actually requested or shared. */\nexport const REALM_FILE_ACTIVE_STATUS_VALUES = [\n REALM_FILE_PENDING_APPROVAL_STATUS,\n ...REALM_FILE_APPROVED_STATUS_VALUES,\n] as const;\nexport const RealmFileActiveStatusSchema = z.enum(REALM_FILE_ACTIVE_STATUS_VALUES);\nexport type RealmFileActiveStatus = z.infer<typeof RealmFileActiveStatusSchema>;\n\n// ===== Serving authority (Durable Object) + publication gating =====\n\n/** Whether the canonical serving record has been applied to the DO authority. */\nexport const MediaAuthoritySyncStateSchema = z.enum(['pending', 'applied', 'deadLetter']);\nexport type MediaAuthoritySyncState = z.infer<typeof MediaAuthoritySyncStateSchema>;\n\n/** Whether the asset is referenced by a visible owner doc. Orthogonal to the\n * upload's processing outcome (`pendingMedia.status`) and to `servingStatus`. */\nexport const MediaAssetPublicationStateSchema = z.enum(['unpublished', 'published', 'retired']);\nexport type MediaAssetPublicationState = z.infer<typeof MediaAssetPublicationStateSchema>;\n\n/**\n * Typed immutable serving scope for scoped-tier assets. The gateway Worker matches\n * a grant against the scope by `kind` — so a whole-Work `{w}` grant matches ONLY a\n * `workProject` scope, never a conversation scope, and a conversation grant is never\n * reachable by a Work asset.\n *\n * - `workProject` — pre-publish content media (hall covers / sub-item media during\n * authoring), scoped to project read membership. Carries the matchable\n * `workProjectId`. This is the typed home for work scope on the strongly-consistent\n * serving record so the DO-fallback path can authorize it (the DO persists scope\n * only as `scopeJson`, no separate column).\n * - `workFileFolder` — a work-project FILE living in a folder. The EXACT folder scope,\n * NOT the whole-Work `{w}` grant: a custom folder's bytes must be unreachable by a\n * guildmate outside that folder's view trade-professions, so the grant callable runs\n * the per-folder view check and the Worker EXACT-matches `{workProjectId,\n * workFileFolderId}` — a plain Work `{w}` grant NEVER matches a folder file, and a\n * folder grant NEVER matches a `workProject`-scoped content asset.\n * - `guildInvite` / `adminSupport` — the two Conversation Files scopes; an EXACT\n * conversation scope, matching the `ConversationFileRef` that owns the file. There is\n * NO guildChannel scope: guild chat channels have no Conversation Files (guildmates\n * share files through Work Files, which keeps its own workFileFolder scope).\n *\n * `null` scope = no scope match required beyond the access tier (e.g. broad).\n */\nexport const MediaServingScopeSchema = z.discriminatedUnion('kind', [\n z.object({\n kind: z.literal('workProject'),\n workProjectId: z.string().min(1),\n }).strict(),\n z.object({\n kind: z.literal('workFileFolder'),\n workProjectId: z.string().min(1),\n workFileFolderId: z.string().min(1),\n }).strict(),\n z.object({\n kind: z.literal('guildInvite'),\n guildInviteId: z.string().min(1),\n }).strict(),\n z.object({\n kind: z.literal('adminSupport'),\n adminDispatchId: z.string().min(1),\n }).strict(),\n]);\nexport type MediaServingScope = z.infer<typeof MediaServingScopeSchema>;\n\n/**\n * The typed owner adapter a publication goes through. The activation job\n * carries this kind; a server-side registry validates per-kind `publicationArgs`\n * and performs the idempotent owner write. Every kind is a Firestore-owner adapter.\n */\nexport const MediaPublicationKindSchema = z.enum([\n 'profilePicture',\n 'squarePostMedia',\n 'workAsset',\n 'hallCover',\n // Realm cover — Firestore-owner adapter writes `realmCoverAssetId` onto\n // workRealms/{workRealmId} (the 'realm-cover' upload origin).\n 'realmCover',\n 'workContentMedia', // sub-item media (tale chapter / tune track / television episode) — attaches the *AssetId field on the workContent doc; scoped to the work project\n 'auditionMedia',\n 'commissionListingMedia',\n 'commissionProposalMedia',\n 'craftSkillMedia',\n // Conversation File: the ONE adapter that creates a visible Conversation File owner\n // record ({conversationParent}/conversationFiles/{conversationFileId}) and transfers\n // the quota reservation to published counters in the same transaction. Replaces the\n // removed `chatAttachment` (Channel-DO flip) and `adminSupportAttachment` (message\n // placeholder flip) kinds. Carries the typed `guildInvite` / `adminSupport`\n // MediaServingScope of the owning conversation.\n 'conversationFile',\n // Points a system video slot at its new video and retires the video it replaces, in one\n // transaction.\n 'systemVideoSlot',\n]);\nexport type MediaPublicationKind = z.infer<typeof MediaPublicationKindSchema>;\n\n/**\n * The normalized serving record — the SAME contract used to generate both\n * the DO authority row and the KV cache payload (one function, so they can't\n * drift). The R2 object key stays deterministic (`mediaAssets/{assetId}/{key}`)\n * and is NOT persisted here. `payloadHash` is computed over the canonical\n * payload EXCLUDING the hash itself (see edge-protocol-core `hashPayload`).\n */\nexport const MediaServingAuthorityRecordSchema = z.object({\n schemaVersion: z.number().int().positive(),\n assetId: z.string().min(1),\n authorityVersion: z.number().int().nonnegative(),\n operationId: z.string().min(1),\n payloadHash: z.string().min(1),\n\n servingStatus: MediaServingStatusSchema,\n accessTier: MediaAccessTierSchema,\n\n ownerType: MediaAssetOwnerTypeSchema,\n ownerId: z.string().min(1),\n scope: MediaServingScopeSchema.nullable(),\n\n variants: z.record(z.string(), MediaAssetVariantSchema),\n\n updatedAtMs: z.number(),\n}).strict();\nexport type MediaServingAuthorityRecord = z.infer<typeof MediaServingAuthorityRecordSchema>;\n\n/**\n * Why the retirement drain last deferred an owed retirement: `held` — a legal or safety hold\n * blocks the byte removal; `failed` — an edge step or an object delete failed.\n */\nexport const MediaAssetRetirementDeferralSchema = z.enum(['held', 'failed']);\nexport type MediaAssetRetirementDeferral = z.infer<typeof MediaAssetRetirementDeferralSchema>;\n\n/**\n * The retirement obligation of an asset whose owner record is gone — written onto the asset doc in\n * the SAME transaction or batch as the delete (or refusal) that leaves it unowned, together with the\n * durable authority deny when the asset is still servable (servingStatusOnRetirementRequest), so no\n * path deletes a record and then retires its media best-effort. One\n * scheduled drain owns the byte removal: it takes up due obligations in `nextAttemptAt` order, and\n * the asset becomes `retired` only when every variant's object delete has succeeded. A hold or a\n * failure defers the obligation (`attemptCount`, `nextAttemptAt`, `lastDeferral`); it is never\n * dropped. The drain deletes the obligation in the transaction that marks the asset retired.\n */\nexport const MediaAssetRetirementSchema = z\n .object({\n /** Epoch ms the obligation was co-written with the delete. */\n requestedAt: z.number().int().nonnegative(),\n /** Variant keys whose object delete has not yet succeeded (an already-absent object counts as\n * deleted). Starts as every key of `variants`; the drain removes a key only after its delete\n * succeeds. */\n pendingVariantKeys: z.array(z.string().min(1)),\n attemptCount: z.number().int().nonnegative(),\n /** Epoch ms from which the drain may take the obligation up; the drain lists due ones in this\n * order, so a deferred one rotates behind the ones that can finish. */\n nextAttemptAt: z.number().int().nonnegative(),\n lastDeferral: MediaAssetRetirementDeferralSchema.optional(),\n lastError: StructuredErrorSchema.optional(),\n })\n .strict()\n .superRefine((val, ctx) => {\n if (new Set(val.pendingVariantKeys).size !== val.pendingVariantKeys.length) {\n ctx.addIssue({ code: 'custom', path: ['pendingVariantKeys'], message: 'a variant key is owed at most once' });\n }\n if (val.lastError !== undefined && val.lastDeferral !== 'failed') {\n ctx.addIssue({ code: 'custom', path: ['lastError'], message: 'an error is recorded only for a failed attempt' });\n }\n });\nexport type MediaAssetRetirement = z.infer<typeof MediaAssetRetirementSchema>;\n\nexport const MediaAssetSchema = z.object({\n mediaAssetId: z.string().min(1),\n mediaKind: ContentMediaKindSchema,\n fileOrigin: FileOriginSchema,\n\n // Ownership / scope. ownerId is the owning doc's id within ownerType's\n // surface; scope ids let the Worker/grant layer match scoped access.\n ownerType: MediaAssetOwnerTypeSchema,\n ownerId: z.string().min(1),\n workProjectId: z.string().optional(),\n realmId: z.string().optional(),\n createdByUid: z.string().min(1),\n\n // Access + serving (canonical; edge records derive from these).\n accessTier: MediaAccessTierSchema,\n servingStatus: MediaServingStatusSchema,\n\n // Variants by key. The object key in R2 (and the Storage emulator) is\n // deterministic — mediaAssets/{mediaAssetId}/{variantKey} — never stored.\n variants: z.record(z.string(), MediaAssetVariantSchema),\n\n // Lifecycle / trust-and-safety.\n moderationStatus: z.enum(['approved', 'quarantined']),\n retentionPolicy: MediaRetentionPolicySchema,\n legalHold: z.boolean(),\n originalDeletedAt: z.number().optional(),\n\n // T&S provenance lineage. Optional so an asset that carries no lineage still parses; set server-side at first accepted\n // ingest, inherited unchanged by every copy/variant. Never client-supplied.\n originLineage: MediaOriginLineageV1Schema.optional(),\n\n // ===== Realm shared-files seam (request → steward approval → foldered pool) =====\n // A file's standing in its realm's shared pool; set at creation to 'none' and moved\n // ONLY by the realm shared-files callables. The legal combinations of this field with\n // `realmId`, `realmFileFolderId`, and the three request fields are ENFORCED by the\n // refinement below — the fields are not independently optional.\n realmFileCanonStatus: RealmFileCanonStatusSchema,\n\n // The steward-chosen folder under `workRealms/{realmId}/realmFileFolders/{id}`. There is\n // no default folder: approval IS the folder assignment, so every approved file is in a\n // folder by construction. Cleared on decline, withdrawal, and admin un-share — but\n // PRESERVED through moderation hide/restore (hide is reversible and changes serving state\n // only; clearing it would restore an approved file with no folder and lose the steward's\n // organization).\n realmFileFolderId: z.string().min(1).optional(),\n\n // Pending-request metadata, present ONLY while `realmFileCanonStatus === 'pendingApproval'`.\n // `realmFileShareRequestId` is the CLIENT-GENERATED stable request id carried by the\n // request input; approval, decline, and withdrawal all compare against it, so a stale tab\n // can never decide a newer re-request. `realmFileShareRequestedByUid` is the recorded\n // requester — the resolution notification is addressed from THIS field, never guessed from\n // `createdByUid` (the uploader and the promoting file admin are frequently different\n // people). `realmFileShareRequestedAt` is epoch ms (ARCH-105).\n realmFileShareRequestId: z.string().min(1).optional(),\n realmFileShareRequestedByUid: z.string().min(1).optional(),\n realmFileShareRequestedAt: z.number().optional(),\n\n // Serving authority + publication gating. Optional so an asset with no\n // authority state still parses: absent authorityVersion ⇒\n // 0/never-applied, absent publicationState ⇒ 'unpublished'. Every\n // serving-record mutation increments authorityVersion in an authoritative txn.\n authorityVersion: z.number().int().nonnegative().optional(),\n authorityPayloadHash: z.string().optional(),\n authoritySyncState: MediaAuthoritySyncStateSchema.optional(),\n publicationState: MediaAssetPublicationStateSchema.optional(),\n scope: MediaServingScopeSchema.optional(),\n authorityAppliedAt: z.number().optional(),\n publishedAt: z.number().optional(),\n lastAuthorityError: StructuredErrorSchema.optional(),\n // Authority-sync retry ledger: the scheduled worker bumps attemptCount + sets a backoff\n // nextAttemptAt on a transient apply failure, and dead-letters (authoritySyncState='deadLetter')\n // past a threshold. Absent ⇒ 0 attempts / immediately due.\n authoritySyncAttemptCount: z.number().int().nonnegative().optional(),\n authoritySyncNextAttemptAt: z.number().optional(),\n\n // Present exactly while a retirement is owed (MediaAssetRetirementSchema).\n retirement: MediaAssetRetirementSchema.optional(),\n\n createdAt: z.number(),\n updatedAt: z.number(),\n}).strict().superRefine((val, ctx) => {\n // ===== Retirement invariant =====\n // An owed retirement already denies serving (the delete co-wrote the authority deny) and is not\n // yet retired (the drain clears it when it marks the asset retired). It owes only the asset's\n // own variants.\n if (val.retirement !== undefined) {\n if (val.servingStatus === 'servable') {\n ctx.addIssue({ code: 'custom', path: ['servingStatus'], message: 'an asset owing retirement is never servable' });\n }\n if (val.publicationState === 'retired') {\n ctx.addIssue({ code: 'custom', path: ['retirement'], message: 'a retired asset owes no retirement' });\n }\n for (const key of val.retirement.pendingVariantKeys) {\n if (!Object.prototype.hasOwnProperty.call(val.variants, key)) {\n ctx.addIssue({ code: 'custom', path: ['retirement', 'pendingVariantKeys'], message: `${key} is not one of this asset's variants` });\n }\n }\n }\n\n // ===== Realm-file legal-combination invariant =====\n // The realm-file field GROUP is one state machine, not five independently-optional\n // fields. Declared HERE, on the canonical doc schema (ARCH-102), so every writer inherits\n // it from one parse instead of each transition re-deciding — and so no reader ever has to\n // defend against a half-written state (an approved file with no folder, a pending file\n // already flipped into the realm, a decline that left request metadata behind).\n //\n // none → no realmId, no folder, no request fields\n // pendingApproval → realmId + ALL THREE request fields; NO folder (approval assigns it)\n // nonCanon|canon → realmId + folder; NO request fields (the request is resolved)\n //\n // DELIBERATELY NOT CONSTRAINED HERE: `accessTier`. Tier is origin-dependent across the\n // whole asset universe (this one schema covers every media origin, not just work files),\n // so binding tier to a realm-file status would misjudge assets that have nothing to do\n // with realms. Tier correctness on these transitions (`scoped` while pending, `artisan`\n // once approved) is enforced by the callable transactions and their tests.\n // `servingStatus` stays orthogonal too — moderation hide/quarantine is independent of a\n // file's realm standing.\n const requestFields = [\n ['realmFileShareRequestId', val.realmFileShareRequestId],\n ['realmFileShareRequestedByUid', val.realmFileShareRequestedByUid],\n ['realmFileShareRequestedAt', val.realmFileShareRequestedAt],\n ] as const;\n\n const forbid = (path: string, value: unknown, message: string) => {\n if (value !== undefined) ctx.addIssue({ code: 'custom', path: [path], message });\n };\n const require_ = (path: string, value: unknown, message: string) => {\n if (value === undefined) ctx.addIssue({ code: 'custom', path: [path], message });\n };\n\n if (val.realmFileCanonStatus === 'none') {\n forbid('realmId', val.realmId, 'realmId is only set on a realm-shared or pending asset (realmFileCanonStatus is \"none\")');\n forbid('realmFileFolderId', val.realmFileFolderId, 'realmFileFolderId is only set on an APPROVED realm-shared asset (realmFileCanonStatus is \"none\")');\n for (const [path, value] of requestFields) {\n forbid(path, value, `${path} is only set while a promotion request is pending (realmFileCanonStatus is \"none\")`);\n }\n return;\n }\n\n require_('realmId', val.realmId, `realmId is required whenever realmFileCanonStatus is \"${val.realmFileCanonStatus}\"`);\n\n if (val.realmFileCanonStatus === 'pendingApproval') {\n forbid('realmFileFolderId', val.realmFileFolderId, 'a pending request has no folder yet — the steward assigns the folder AT approval');\n for (const [path, value] of requestFields) {\n require_(path, value, `${path} is required while realmFileCanonStatus is \"pendingApproval\"`);\n }\n return;\n }\n\n // 'nonCanon' | 'canon' — approved into the pool.\n require_('realmFileFolderId', val.realmFileFolderId, `realmFileFolderId is required on an approved realm file (realmFileCanonStatus is \"${val.realmFileCanonStatus}\")`);\n for (const [path, value] of requestFields) {\n forbid(path, value, `${path} must be cleared once the request is resolved (realmFileCanonStatus is \"${val.realmFileCanonStatus}\")`);\n }\n});\nexport type MediaAsset = z.infer<typeof MediaAssetSchema>;\n\n// Field projections of an asset doc for readers that need only a few of its fields. Each composes\n// the canonical field schemas and strips every other key, and none runs MediaAssetSchema's\n// whole-doc refinement, so a doc with unrelated stored fields still yields the fields read.\n\n/** What the Hall-media orphan reaper's asset phase reads of a candidate asset. */\nexport const MediaAssetReapCandidateSchema = z.object({\n mediaAssetId: MediaAssetSchema.shape.mediaAssetId,\n ownerId: MediaAssetSchema.shape.ownerId,\n createdAt: MediaAssetSchema.shape.createdAt,\n publicationState: MediaAssetSchema.shape.publicationState,\n retirement: MediaAssetSchema.shape.retirement,\n});\nexport type MediaAssetReapCandidate = z.infer<typeof MediaAssetReapCandidateSchema>;\n\n/** What a copy's safety-hold check reads of its source asset. */\nexport const MediaAssetCopySourceHoldFieldsSchema = z.object({\n mediaAssetId: MediaAssetSchema.shape.mediaAssetId,\n originLineage: MediaAssetSchema.shape.originLineage,\n legalHold: MediaAssetSchema.shape.legalHold,\n});\nexport type MediaAssetCopySourceHoldFields = z.infer<typeof MediaAssetCopySourceHoldFieldsSchema>;\n\n/**\n * Where an asset stands on retirement — the one reading a caller that must not delete a record\n * naming media before its media is gone (account erasure) decides from: `absent` (no asset doc),\n * `retired` (every byte removed), `owed` (an obligation is still draining), `none` (not retiring).\n */\nexport type MediaAssetRetirementStanding = 'absent' | 'retired' | 'owed' | 'none';\n\nexport function mediaAssetRetirementStanding(\n asset: Pick<MediaAsset, 'publicationState' | 'retirement'> | undefined,\n): MediaAssetRetirementStanding {\n if (asset === undefined) return 'absent';\n if (asset.publicationState === 'retired') return 'retired';\n if (asset.retirement !== undefined) return 'owed';\n return 'none';\n}\n\n/**\n * The serving status a retirement co-write leaves on an asset: a `servable` asset is denied\n * (`hidden`) at once, and an asset already `hidden`, `quarantined`, or `deleted` keeps its status —\n * retiring an asset never downgrades a quarantine or reopens a deleted one (MEDIA-103).\n */\nexport function servingStatusOnRetirementRequest(current: MediaServingStatus): MediaServingStatus {\n return current === 'servable' ? 'hidden' : current;\n}\n\n/**\n * The serving status the drain writes when it marks an asset `retired`: `deleted`, except that a\n * `quarantined` asset stays quarantined — only the safety flows move a quarantine.\n */\nexport function servingStatusOnRetirementComplete(current: MediaServingStatus): MediaServingStatus {\n return current === 'quarantined' ? 'quarantined' : 'deleted';\n}\n"]}
|
|
1
|
+
{"version":3,"file":"media-assets.js","sourceRoot":"","sources":["../../src/doc-schemas/media-assets.ts"],"names":[],"mappings":"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","sourcesContent":["// mediaAssets/{mediaAssetId} — the canonical media registry. One doc per\n// logical uploaded media item; all variants inside. Content docs reference\n// media ONLY by `*AssetId` fields — never URLs. Serving authority is the\n// gateway Worker (cookie/grant + KV blocklist); this doc is the server-side\n// truth the edge records derive from. NO client reads, NO client writes.\n\nimport { z } from 'zod';\nimport { StructuredErrorSchema } from '@ttt-productions/edge-protocol-core';\nimport { TIMED_MEDIA_MAIN_OUTPUT_KEY, VIDEO_POSTER_OUTPUT_KEY } from '@ttt-productions/media-schemas';\nimport { FileOriginSchema } from '../media/file-origin.js';\n\n/** Who may be served the bytes (the Worker's tier check). */\nexport const MediaAccessTierSchema = z.enum(['broad', 'scoped', 'artisan', 'adminOnly']);\nexport type MediaAccessTier = z.infer<typeof MediaAccessTierSchema>;\n\n/** Canonical serving state. The edge record derives from this; hide/restore/\n * quarantine flows write it together with the blocklist. */\nexport const MediaServingStatusSchema = z.enum(['servable', 'hidden', 'quarantined', 'deleted']);\nexport type MediaServingStatus = z.infer<typeof MediaServingStatusSchema>;\n\n/** The surface that owns this asset. One asset never serves two scopes —\n * publishing to the Hall (or future realm promotion) creates a NEW asset\n * owned by the destination surface. */\nexport const MediaAssetOwnerTypeSchema = z.enum([\n 'userProfile',\n 'craftSkill',\n 'squareStreetzPost',\n 'workProject',\n 'workContent', // tale chapter / tune track / television episode media (pre-publish)\n 'hallItem',\n 'commissionListing',\n 'commissionProposal',\n 'audition',\n 'auditionEntry',\n // A file in a conversation's flat Conversation Files list (guild-invite or\n // admin-support). Chat messages own no media.\n 'conversationFile',\n // Realm shared files are the deliberate MUTATE-IN-PLACE exception: a promoted work file\n // keeps its ONE `workFile`-owned asset doc and flips tier in place, so no asset is ever\n // owned by `realmFile` today. The owner type stays declared for a future realm-owned\n // media surface; it is NOT the seam realm sharing rides (that is `realmFileCanonStatus`\n // + `realmId` + `realmFileFolderId` on the work file's own asset).\n 'realmFile',\n 'safetyEvidence', // inert system sentinel — synthetic NCII-evidence assets (never an account surface)\n // An admin video held by a system video slot; the owner id is the slot id.\n 'systemContent',\n]);\nexport type MediaAssetOwnerType = z.infer<typeof MediaAssetOwnerTypeSchema>;\n\n// ===== Media origin lineage =====\n// One canonical lineage used by media, CSAM, and safety. Embedded on every\n// media asset + every copy.\n\n/** The ONE canonical stored content media kind (what the pipeline produces and the\n * asset doc records). Distinct from the 4-value display/transport MediaTypeSchema\n * (doc-schemas/social.ts, adds 'other') and media-schemas' generic MediaKindSchema. */\nexport const ContentMediaKindSchema = z.enum(['image', 'video', 'audio']);\nexport type ContentMediaKind = z.infer<typeof ContentMediaKindSchema>;\n\n/**\n * Every variant key the media pipeline writes under an asset id — never an open `string`: the image\n * variants `TTT_MEDIA_SPECS` declares, plus the video and audio outputs, which derive from the\n * pipeline's own output-key declarations (media-schemas) — the transcoded `main` and the video's\n * `poster` frame. A copy or an ingest intent names its objects with these, so a key outside the set\n * could be written but never reclaimed. `__tests__/media-origin-lineage.test.ts` fails when a spec\n * declares a key outside the set, a pipeline output falls outside it, or a member is produced by\n * nothing.\n */\nexport const MEDIA_VARIANT_KEYS = [\n 'full',\n 'medium',\n 'small',\n TIMED_MEDIA_MAIN_OUTPUT_KEY,\n VIDEO_POSTER_OUTPUT_KEY,\n] as const;\nexport const MediaVariantKeySchema = z.enum(MEDIA_VARIANT_KEYS);\nexport type MediaVariantKey = z.infer<typeof MediaVariantKeySchema>;\n\n/** The sizes a profile picture is produced in (`TTT_MEDIA_SPECS['profile-picture']`), largest first. */\nexport const PROFILE_PICTURE_VARIANT_KEYS = ['full', 'medium', 'small'] as const satisfies readonly MediaVariantKey[];\nexport type ProfilePictureVariantKey = (typeof PROFILE_PICTURE_VARIANT_KEYS)[number];\n\n/** Which variant renders a stored image as a single display: the largest servable one. An image\n * origin carries exactly one of `main` / `full`; a profile picture adds the smaller sizes. */\nexport const MEDIA_DISPLAY_VARIANT_PRECEDENCE = [\n TIMED_MEDIA_MAIN_OUTPUT_KEY,\n ...PROFILE_PICTURE_VARIANT_KEYS,\n] as const satisfies readonly MediaVariantKey[];\n\n/** Why this asset was created from its source.\n *\n * Chat is text-only and owns no media, so no copy is ever made for a chat message. A\n * Conversation File is an ORIGINAL (`original`), never a derivative. */\nexport const MediaCopyReasonSchema = z.enum([\n 'original',\n 'variant',\n 'hall_publish',\n 'profile_derivative',\n 'moderation_copy',\n 'evidence_copy',\n 'other',\n]);\nexport type MediaCopyReason = z.infer<typeof MediaCopyReasonSchema>;\n\n/**\n * Canonical media origin lineage. A copy INHERITS\n * rootIngestId/rootAssetId/originatingUploaderUid/originatingUploadEventId/\n * originalUploadCreatedAt/rootSha256/originalSha256 unchanged; it sets its own\n * sourceAssetId/variantSha256s/copyReason/copyActorUid/currentOwner*. Client\n * requests can NEVER set or override any lineage field. Automatic account\n * action targets ONLY `originatingUploaderUid`; incident-wide blocking\n * enumerates by `rootIngestId`. Missing/corrupt lineage → safetyLocked +\n * manual decision, never a guessed ban.\n */\nexport const MediaOriginLineageV1Schema = z.object({\n lineageVersion: z.literal(1),\n rootIngestId: z.string().min(1), // first-accepted ingest event id; stable across all copies\n rootAssetId: z.string().min(1), // first asset created from that ingest\n sourceAssetId: z.string().min(1).optional(), // immediate parent copied from (absent on the root)\n originatingUploaderUid: z.string().min(1), // set server-side at first accepted ingest; IMMUTABLE; inherited\n // May be '' for a copy synthesized from a source with no known upload event.\n originatingUploadEventId: z.string(),\n originalUploadCreatedAt: z.number(),\n // '' until content hashing fills in the real sha256.\n // NOT z.string().min(1): the media pipeline does not compute a content hash at finalize yet,\n // so a freshly-ingested asset legitimately carries an empty rootSha256 until it is hashed.\n rootSha256: z.string(),\n originalSha256: z.string().min(1).optional(),\n // PARTIAL map: one hash per PRODUCED variant (an asset produces only the variants its\n // origin declares — e.g. full/medium/small for a profile picture, 'main' for others —\n // never all four). Typed keys, never an open string. `z.partialRecord` (NOT `z.record`):\n // in Zod 4 `z.record(enum,…)` is EXHAUSTIVE (demands every enum key), which would reject\n // every real asset's partial variant set; `partialRecord` makes the keys optional.\n variantSha256s: z.partialRecord(MediaVariantKeySchema, z.string().min(1)),\n copyReason: MediaCopyReasonSchema,\n createdFromOwnerType: MediaAssetOwnerTypeSchema.optional(), // never a bare string\n createdFromOwnerId: z.string().min(1).optional(),\n copyActorUid: z.string().min(1).optional(), // who triggered the copy (distinct from the original uploader)\n currentOwnerType: MediaAssetOwnerTypeSchema, // mutable; the asset's present owner\n currentOwnerId: z.string().min(1),\n}).strict();\nexport type MediaOriginLineageV1 = z.infer<typeof MediaOriginLineageV1Schema>;\n\nexport const MediaAssetVariantSchema = z.object({\n contentType: z.string().min(1),\n sizeBytes: z.number().int().nonnegative(),\n width: z.number().int().positive().optional(),\n height: z.number().int().positive().optional(),\n durationSec: z.number().positive().optional(),\n /**\n * Server-owned filename the gateway puts in `Content-Disposition` for a\n * `?download=1` request. VARIANT-specific on purpose: the downloadable bytes are\n * a PROCESSED variant, so the extension must match THIS variant's actual\n * `contentType` — a transcoded JPEG/WebP/MP4 is never labelled with the original\n * upload's incompatible extension.\n *\n * Written ONLY by backend publishers, and ONLY for surfaces that intentionally\n * offer a Download action — Work Files (including the same asset shared to a\n * Realm), Conversation Files, and downloadable Hall media. Profiles, posts,\n * covers, and every other surface leave it ABSENT so no private original filename\n * is ever exposed; an absent value serves the safe bare `attachment` disposition.\n *\n * Always produced by `normalizeDownloadFilename` (media/download-filename.ts) —\n * that helper owns the sanitization rules and the UTF-8 byte cap, so no bound is\n * restated here. A client query parameter is NEVER the filename authority.\n * Filenames are user content: never log this value.\n */\n downloadFilename: z.string().min(1).optional(),\n}).strict();\nexport type MediaAssetVariant = z.infer<typeof MediaAssetVariantSchema>;\n\nexport const MediaRetentionPolicySchema = z.enum([\n 'standard', // staging original deleted ~24h after verified mirror\n 'preserveForTrustAndSafety',\n 'legalHold',\n]);\nexport type MediaRetentionPolicy = z.infer<typeof MediaRetentionPolicySchema>;\n\n// Realm shared-files: a work file's standing in its realm's shared pool. ONE seam — the\n// approval gate is a value in this union, never a parallel status field.\n// none — not shared to the realm (default)\n// pendingApproval — a Work file admin has REQUESTED promotion; the Realm steward has not\n// decided yet. The file is NOT served to the Realm (tier stays `scoped`)\n// and is invisible to the member gallery, whose query selects only\n// nonCanon|canon — so pending rows are excluded structurally, not by a\n// filter someone can forget.\n// nonCanon — approved into the realm's pool (in a steward-chosen folder), non-canon\n// canon — approved and marked canon (realm steward toggles canon ↔ nonCanon)\n// Moderation/takedown is NOT a value here — a hidden file is hidden via the shared\n// media path (`servingStatus: 'hidden'`), so the gallery filters on servingStatus.\n//\n// Each member is declared ONCE as a named constant below and every set is assembled from\n// those names, so a member constant and the sets that contain it cannot drift apart.\n\n/** Not shared to the realm — the default standing for every work file. */\nexport const REALM_FILE_NONE_STATUS = 'none' as const;\n/** The single AWAITING-DECISION standing. Exported as a VALUE as well as a schema so a\n * consumer can branch on it (`status === REALM_FILE_PENDING_APPROVAL_STATUS`) without\n * re-quoting the member — the redeclaration guard pins this literal to this file. */\nexport const REALM_FILE_PENDING_APPROVAL_STATUS = 'pendingApproval' as const;\n/** Approved into the realm's shared pool, not marked canon. */\nexport const REALM_FILE_NON_CANON_STATUS = 'nonCanon' as const;\n/** Approved into the realm's shared pool AND marked canon by the Realm steward. */\nexport const REALM_FILE_CANON_STATUS = 'canon' as const;\n\nexport const REALM_FILE_CANON_STATUS_VALUES = [\n REALM_FILE_NONE_STATUS,\n REALM_FILE_PENDING_APPROVAL_STATUS,\n REALM_FILE_NON_CANON_STATUS,\n REALM_FILE_CANON_STATUS,\n] as const;\nexport const RealmFileCanonStatusSchema = z.enum(REALM_FILE_CANON_STATUS_VALUES);\nexport type RealmFileCanonStatus = z.infer<typeof RealmFileCanonStatusSchema>;\n\n/** The two APPROVED (steward-accepted, realm-served) standings. The member gallery query\n * and its projection accept exactly these — never the full status union, so a pending or\n * unshared row can never be typed into an approved-files response. Derived from the one\n * union above; consumers import this instead of re-quoting the members (ARCH-102). */\nexport const REALM_FILE_APPROVED_STATUS_VALUES = [\n REALM_FILE_NON_CANON_STATUS,\n REALM_FILE_CANON_STATUS,\n] as const;\nexport const RealmFileApprovedStatusSchema = z.enum(REALM_FILE_APPROVED_STATUS_VALUES);\nexport type RealmFileApprovedStatus = z.infer<typeof RealmFileApprovedStatusSchema>;\n\n/** The steward promotion-queue projection accepts only this, so an approved or unshared row\n * can never be typed into the queue. */\nexport const RealmFilePendingApprovalStatusSchema = z.literal(REALM_FILE_PENDING_APPROVAL_STATUS);\nexport type RealmFilePendingApprovalStatus = z.infer<typeof RealmFilePendingApprovalStatusSchema>;\n\n/** Every standing EXCEPT `none` — a file that has entered the request/approval lifecycle at\n * all. Derived from the two subsets above, so adding a future standing to one of them\n * reaches this set automatically. Used by the Work-side share-state projection, whose rows\n * exist only for files that are actually requested or shared. */\nexport const REALM_FILE_ACTIVE_STATUS_VALUES = [\n REALM_FILE_PENDING_APPROVAL_STATUS,\n ...REALM_FILE_APPROVED_STATUS_VALUES,\n] as const;\nexport const RealmFileActiveStatusSchema = z.enum(REALM_FILE_ACTIVE_STATUS_VALUES);\nexport type RealmFileActiveStatus = z.infer<typeof RealmFileActiveStatusSchema>;\n\n// ===== Serving authority (Durable Object) + publication gating =====\n\n/** Whether the canonical serving record has been applied to the DO authority. */\nexport const MediaAuthoritySyncStateSchema = z.enum(['pending', 'applied', 'deadLetter']);\nexport type MediaAuthoritySyncState = z.infer<typeof MediaAuthoritySyncStateSchema>;\n\n/** Whether the asset is referenced by a visible owner doc. Orthogonal to the\n * upload's processing outcome (`pendingMedia.status`) and to `servingStatus`. */\nexport const MediaAssetPublicationStateSchema = z.enum(['unpublished', 'published', 'retired']);\nexport type MediaAssetPublicationState = z.infer<typeof MediaAssetPublicationStateSchema>;\n\n/**\n * Typed immutable serving scope for scoped-tier assets. The gateway Worker matches\n * a grant against the scope by `kind` — so a whole-Work `{w}` grant matches ONLY a\n * `workProject` scope, never a conversation scope, and a conversation grant is never\n * reachable by a Work asset.\n *\n * - `workProject` — pre-publish content media (hall covers / sub-item media during\n * authoring), scoped to project read membership. Carries the matchable\n * `workProjectId`. This is the typed home for work scope on the strongly-consistent\n * serving record so the DO-fallback path can authorize it (the DO persists scope\n * only as `scopeJson`, no separate column).\n * - `workFileFolder` — a work-project FILE living in a folder. The EXACT folder scope,\n * NOT the whole-Work `{w}` grant: a custom folder's bytes must be unreachable by a\n * guildmate outside that folder's view trade-professions, so the grant callable runs\n * the per-folder view check and the Worker EXACT-matches `{workProjectId,\n * workFileFolderId}` — a plain Work `{w}` grant NEVER matches a folder file, and a\n * folder grant NEVER matches a `workProject`-scoped content asset.\n * - `guildInvite` / `adminSupport` — the two Conversation Files scopes; an EXACT\n * conversation scope, matching the `ConversationFileRef` that owns the file. There is\n * NO guildChannel scope: guild chat channels have no Conversation Files (guildmates\n * share files through Work Files, which keeps its own workFileFolder scope).\n *\n * `null` scope = no scope match required beyond the access tier (e.g. broad).\n */\nexport const MediaServingScopeSchema = z.discriminatedUnion('kind', [\n z.object({\n kind: z.literal('workProject'),\n workProjectId: z.string().min(1),\n }).strict(),\n z.object({\n kind: z.literal('workFileFolder'),\n workProjectId: z.string().min(1),\n workFileFolderId: z.string().min(1),\n }).strict(),\n z.object({\n kind: z.literal('guildInvite'),\n guildInviteId: z.string().min(1),\n }).strict(),\n z.object({\n kind: z.literal('adminSupport'),\n adminDispatchId: z.string().min(1),\n }).strict(),\n]);\nexport type MediaServingScope = z.infer<typeof MediaServingScopeSchema>;\n\n/**\n * The typed owner adapter a publication goes through. The activation job\n * carries this kind; a server-side registry validates per-kind `publicationArgs`\n * and performs the idempotent owner write. Every kind is a Firestore-owner adapter.\n */\nexport const MediaPublicationKindSchema = z.enum([\n 'profilePicture',\n 'squarePostMedia',\n 'workAsset',\n 'hallCover',\n // Realm cover — Firestore-owner adapter writes `realmCoverAssetId` onto\n // workRealms/{workRealmId} (the 'realm-cover' upload origin).\n 'realmCover',\n 'workContentMedia', // sub-item media (tale chapter / tune track / television episode) — attaches the *AssetId field on the workContent doc; scoped to the work project\n 'auditionMedia',\n 'commissionListingMedia',\n 'commissionProposalMedia',\n 'craftSkillMedia',\n // Conversation File: the ONE adapter that creates a visible Conversation File owner\n // record ({conversationParent}/conversationFiles/{conversationFileId}) and transfers\n // the quota reservation to published counters in the same transaction. Replaces the\n // removed `chatAttachment` (Channel-DO flip) and `adminSupportAttachment` (message\n // placeholder flip) kinds. Carries the typed `guildInvite` / `adminSupport`\n // MediaServingScope of the owning conversation.\n 'conversationFile',\n // Points a system video slot at its new video and retires the video it replaces, in one\n // transaction.\n 'systemVideoSlot',\n]);\nexport type MediaPublicationKind = z.infer<typeof MediaPublicationKindSchema>;\n\n/**\n * The normalized serving record — the SAME contract used to generate both\n * the DO authority row and the KV cache payload (one function, so they can't\n * drift). The R2 object key stays deterministic (`mediaAssets/{assetId}/{key}`)\n * and is NOT persisted here. `payloadHash` is computed over the canonical\n * payload EXCLUDING the hash itself (see edge-protocol-core `hashPayload`).\n */\nexport const MediaServingAuthorityRecordSchema = z.object({\n schemaVersion: z.number().int().positive(),\n assetId: z.string().min(1),\n authorityVersion: z.number().int().nonnegative(),\n operationId: z.string().min(1),\n payloadHash: z.string().min(1),\n\n servingStatus: MediaServingStatusSchema,\n accessTier: MediaAccessTierSchema,\n\n ownerType: MediaAssetOwnerTypeSchema,\n ownerId: z.string().min(1),\n scope: MediaServingScopeSchema.nullable(),\n\n variants: z.record(z.string(), MediaAssetVariantSchema),\n\n updatedAtMs: z.number(),\n}).strict();\nexport type MediaServingAuthorityRecord = z.infer<typeof MediaServingAuthorityRecordSchema>;\n\n/**\n * Why the retirement drain last deferred an owed retirement: `held` — a legal or safety hold\n * blocks the byte removal; `failed` — an edge step or an object delete failed.\n */\nexport const MediaAssetRetirementDeferralSchema = z.enum(['held', 'failed']);\nexport type MediaAssetRetirementDeferral = z.infer<typeof MediaAssetRetirementDeferralSchema>;\n\n/**\n * The retirement obligation of an asset whose owner record is gone — written onto the asset doc in\n * the SAME transaction or batch as the delete (or refusal) that leaves it unowned, together with the\n * durable authority deny when the asset is still servable (servingStatusOnRetirementRequest), so no\n * path deletes a record and then retires its media best-effort. One\n * scheduled drain owns the byte removal: it takes up due obligations in `nextAttemptAt` order, and\n * the asset becomes `retired` only when every variant's object delete has succeeded. A hold or a\n * failure defers the obligation (`attemptCount`, `nextAttemptAt`, `lastDeferral`); it is never\n * dropped. The drain deletes the obligation in the transaction that marks the asset retired.\n */\nexport const MediaAssetRetirementSchema = z\n .object({\n /** Epoch ms the obligation was co-written with the delete. */\n requestedAt: z.number().int().nonnegative(),\n /** Variant keys whose object delete has not yet succeeded (an already-absent object counts as\n * deleted). Starts as every key of `variants`; the drain removes a key only after its delete\n * succeeds. */\n pendingVariantKeys: z.array(z.string().min(1)),\n attemptCount: z.number().int().nonnegative(),\n /** Epoch ms from which the drain may take the obligation up; the drain lists due ones in this\n * order, so a deferred one rotates behind the ones that can finish. */\n nextAttemptAt: z.number().int().nonnegative(),\n lastDeferral: MediaAssetRetirementDeferralSchema.optional(),\n lastError: StructuredErrorSchema.optional(),\n })\n .strict()\n .superRefine((val, ctx) => {\n if (new Set(val.pendingVariantKeys).size !== val.pendingVariantKeys.length) {\n ctx.addIssue({ code: 'custom', path: ['pendingVariantKeys'], message: 'a variant key is owed at most once' });\n }\n if (val.lastError !== undefined && val.lastDeferral !== 'failed') {\n ctx.addIssue({ code: 'custom', path: ['lastError'], message: 'an error is recorded only for a failed attempt' });\n }\n });\nexport type MediaAssetRetirement = z.infer<typeof MediaAssetRetirementSchema>;\n\nexport const MediaAssetSchema = z.object({\n mediaAssetId: z.string().min(1),\n mediaKind: ContentMediaKindSchema,\n fileOrigin: FileOriginSchema,\n\n // Ownership / scope. ownerId is the owning doc's id within ownerType's\n // surface; scope ids let the Worker/grant layer match scoped access.\n ownerType: MediaAssetOwnerTypeSchema,\n ownerId: z.string().min(1),\n workProjectId: z.string().optional(),\n realmId: z.string().optional(),\n createdByUid: z.string().min(1),\n\n // Access + serving (canonical; edge records derive from these).\n accessTier: MediaAccessTierSchema,\n servingStatus: MediaServingStatusSchema,\n\n // Variants by key. The object key in R2 (and the Storage emulator) is\n // deterministic — mediaAssets/{mediaAssetId}/{variantKey} — never stored.\n variants: z.record(z.string(), MediaAssetVariantSchema),\n\n // Lifecycle / trust-and-safety.\n moderationStatus: z.enum(['approved', 'quarantined']),\n retentionPolicy: MediaRetentionPolicySchema,\n legalHold: z.boolean(),\n originalDeletedAt: z.number().optional(),\n\n // T&S provenance lineage. Optional so an asset that carries no lineage still parses; set server-side at first accepted\n // ingest, inherited unchanged by every copy/variant. Never client-supplied.\n originLineage: MediaOriginLineageV1Schema.optional(),\n\n // ===== Realm shared-files seam (request → steward approval → foldered pool) =====\n // A file's standing in its realm's shared pool; set at creation to 'none' and moved\n // ONLY by the realm shared-files callables. The legal combinations of this field with\n // `realmId`, `realmFileFolderId`, and the three request fields are ENFORCED by the\n // refinement below — the fields are not independently optional.\n realmFileCanonStatus: RealmFileCanonStatusSchema,\n\n // The steward-chosen folder under `workRealms/{realmId}/realmFileFolders/{id}`. There is\n // no default folder: approval IS the folder assignment, so every approved file is in a\n // folder by construction. Cleared on decline, withdrawal, and admin un-share — but\n // PRESERVED through moderation hide/restore (hide is reversible and changes serving state\n // only; clearing it would restore an approved file with no folder and lose the steward's\n // organization).\n realmFileFolderId: z.string().min(1).optional(),\n\n // Pending-request metadata, present ONLY while `realmFileCanonStatus === 'pendingApproval'`.\n // `realmFileShareRequestId` is the CLIENT-GENERATED stable request id carried by the\n // request input; approval, decline, and withdrawal all compare against it, so a stale tab\n // can never decide a newer re-request. `realmFileShareRequestedByUid` is the recorded\n // requester — the resolution notification is addressed from THIS field, never guessed from\n // `createdByUid` (the uploader and the promoting file admin are frequently different\n // people). `realmFileShareRequestedAt` is epoch ms (ARCH-105).\n realmFileShareRequestId: z.string().min(1).optional(),\n realmFileShareRequestedByUid: z.string().min(1).optional(),\n realmFileShareRequestedAt: z.number().optional(),\n\n // Serving authority + publication gating. Optional so an asset with no\n // authority state still parses: absent authorityVersion ⇒\n // 0/never-applied, absent publicationState ⇒ 'unpublished'. Every\n // serving-record mutation increments authorityVersion in an authoritative txn.\n authorityVersion: z.number().int().nonnegative().optional(),\n authorityPayloadHash: z.string().optional(),\n authoritySyncState: MediaAuthoritySyncStateSchema.optional(),\n publicationState: MediaAssetPublicationStateSchema.optional(),\n scope: MediaServingScopeSchema.optional(),\n authorityAppliedAt: z.number().optional(),\n publishedAt: z.number().optional(),\n lastAuthorityError: StructuredErrorSchema.optional(),\n // Authority-sync retry ledger: the scheduled worker bumps attemptCount + sets a backoff\n // nextAttemptAt on a transient apply failure, and dead-letters (authoritySyncState='deadLetter')\n // past a threshold. Absent ⇒ 0 attempts / immediately due.\n authoritySyncAttemptCount: z.number().int().nonnegative().optional(),\n authoritySyncNextAttemptAt: z.number().optional(),\n\n // Present exactly while a retirement is owed (MediaAssetRetirementSchema).\n retirement: MediaAssetRetirementSchema.optional(),\n\n createdAt: z.number(),\n updatedAt: z.number(),\n}).strict().superRefine((val, ctx) => {\n // ===== Retirement invariant =====\n // An owed retirement already denies serving (the delete co-wrote the authority deny) and is not\n // yet retired (the drain clears it when it marks the asset retired). It owes only the asset's\n // own variants.\n if (val.retirement !== undefined) {\n if (val.servingStatus === 'servable') {\n ctx.addIssue({ code: 'custom', path: ['servingStatus'], message: 'an asset owing retirement is never servable' });\n }\n if (val.publicationState === 'retired') {\n ctx.addIssue({ code: 'custom', path: ['retirement'], message: 'a retired asset owes no retirement' });\n }\n for (const key of val.retirement.pendingVariantKeys) {\n if (!Object.prototype.hasOwnProperty.call(val.variants, key)) {\n ctx.addIssue({ code: 'custom', path: ['retirement', 'pendingVariantKeys'], message: `${key} is not one of this asset's variants` });\n }\n }\n }\n\n // ===== Realm-file legal-combination invariant =====\n // The realm-file field GROUP is one state machine, not five independently-optional\n // fields. Declared HERE, on the canonical doc schema (ARCH-102), so every writer inherits\n // it from one parse instead of each transition re-deciding — and so no reader ever has to\n // defend against a half-written state (an approved file with no folder, a pending file\n // already flipped into the realm, a decline that left request metadata behind).\n //\n // none → no realmId, no folder, no request fields\n // pendingApproval → realmId + ALL THREE request fields; NO folder (approval assigns it)\n // nonCanon|canon → realmId + folder; NO request fields (the request is resolved)\n //\n // DELIBERATELY NOT CONSTRAINED HERE: `accessTier`. Tier is origin-dependent across the\n // whole asset universe (this one schema covers every media origin, not just work files),\n // so binding tier to a realm-file status would misjudge assets that have nothing to do\n // with realms. Tier correctness on these transitions (`scoped` while pending, `artisan`\n // once approved) is enforced by the callable transactions and their tests.\n // `servingStatus` stays orthogonal too — moderation hide/quarantine is independent of a\n // file's realm standing.\n const requestFields = [\n ['realmFileShareRequestId', val.realmFileShareRequestId],\n ['realmFileShareRequestedByUid', val.realmFileShareRequestedByUid],\n ['realmFileShareRequestedAt', val.realmFileShareRequestedAt],\n ] as const;\n\n const forbid = (path: string, value: unknown, message: string) => {\n if (value !== undefined) ctx.addIssue({ code: 'custom', path: [path], message });\n };\n const require_ = (path: string, value: unknown, message: string) => {\n if (value === undefined) ctx.addIssue({ code: 'custom', path: [path], message });\n };\n\n if (val.realmFileCanonStatus === 'none') {\n forbid('realmId', val.realmId, 'realmId is only set on a realm-shared or pending asset (realmFileCanonStatus is \"none\")');\n forbid('realmFileFolderId', val.realmFileFolderId, 'realmFileFolderId is only set on an APPROVED realm-shared asset (realmFileCanonStatus is \"none\")');\n for (const [path, value] of requestFields) {\n forbid(path, value, `${path} is only set while a promotion request is pending (realmFileCanonStatus is \"none\")`);\n }\n return;\n }\n\n require_('realmId', val.realmId, `realmId is required whenever realmFileCanonStatus is \"${val.realmFileCanonStatus}\"`);\n\n if (val.realmFileCanonStatus === 'pendingApproval') {\n forbid('realmFileFolderId', val.realmFileFolderId, 'a pending request has no folder yet — the steward assigns the folder AT approval');\n for (const [path, value] of requestFields) {\n require_(path, value, `${path} is required while realmFileCanonStatus is \"pendingApproval\"`);\n }\n return;\n }\n\n // 'nonCanon' | 'canon' — approved into the pool.\n require_('realmFileFolderId', val.realmFileFolderId, `realmFileFolderId is required on an approved realm file (realmFileCanonStatus is \"${val.realmFileCanonStatus}\")`);\n for (const [path, value] of requestFields) {\n forbid(path, value, `${path} must be cleared once the request is resolved (realmFileCanonStatus is \"${val.realmFileCanonStatus}\")`);\n }\n});\nexport type MediaAsset = z.infer<typeof MediaAssetSchema>;\n\n// Field projections of an asset doc for readers that need only a few of its fields. Each composes\n// the canonical field schemas and strips every other key, and none runs MediaAssetSchema's\n// whole-doc refinement, so a doc with unrelated stored fields still yields the fields read.\n\n/** What the Hall-media orphan reaper's asset phase reads of a candidate asset. */\nexport const MediaAssetReapCandidateSchema = z.object({\n mediaAssetId: MediaAssetSchema.shape.mediaAssetId,\n ownerId: MediaAssetSchema.shape.ownerId,\n createdAt: MediaAssetSchema.shape.createdAt,\n publicationState: MediaAssetSchema.shape.publicationState,\n retirement: MediaAssetSchema.shape.retirement,\n});\nexport type MediaAssetReapCandidate = z.infer<typeof MediaAssetReapCandidateSchema>;\n\n/** What a copy's safety-hold check reads of its source asset. */\nexport const MediaAssetCopySourceHoldFieldsSchema = z.object({\n mediaAssetId: MediaAssetSchema.shape.mediaAssetId,\n originLineage: MediaAssetSchema.shape.originLineage,\n legalHold: MediaAssetSchema.shape.legalHold,\n});\nexport type MediaAssetCopySourceHoldFields = z.infer<typeof MediaAssetCopySourceHoldFieldsSchema>;\n\n/**\n * Where an asset stands on retirement — the one reading a caller that must not delete a record\n * naming media before its media is gone (account erasure) decides from: `absent` (no asset doc),\n * `retired` (every byte removed), `owed` (an obligation is still draining), `none` (not retiring).\n */\nexport type MediaAssetRetirementStanding = 'absent' | 'retired' | 'owed' | 'none';\n\nexport function mediaAssetRetirementStanding(\n asset: Pick<MediaAsset, 'publicationState' | 'retirement'> | undefined,\n): MediaAssetRetirementStanding {\n if (asset === undefined) return 'absent';\n if (asset.publicationState === 'retired') return 'retired';\n if (asset.retirement !== undefined) return 'owed';\n return 'none';\n}\n\n/**\n * The serving status a retirement co-write leaves on an asset: a `servable` asset is denied\n * (`hidden`) at once, and an asset already `hidden`, `quarantined`, or `deleted` keeps its status —\n * retiring an asset never downgrades a quarantine or reopens a deleted one (MEDIA-103).\n */\nexport function servingStatusOnRetirementRequest(current: MediaServingStatus): MediaServingStatus {\n return current === 'servable' ? 'hidden' : current;\n}\n\n/**\n * The serving status the drain writes when it marks an asset `retired`: `deleted`, except that a\n * `quarantined` asset stays quarantined — only the safety flows move a quarantine.\n */\nexport function servingStatusOnRetirementComplete(current: MediaServingStatus): MediaServingStatus {\n return current === 'quarantined' ? 'quarantined' : 'deleted';\n}\n"]}
|