@ttt-productions/ttt-core 0.79.91 → 0.79.93
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/commissions.d.ts +6 -0
- package/dist/doc-schemas/commissions.d.ts.map +1 -1
- package/dist/doc-schemas/commissions.js +5 -3
- package/dist/doc-schemas/commissions.js.map +1 -1
- package/dist/doc-schemas/media-assets.d.ts +107 -6
- package/dist/doc-schemas/media-assets.d.ts.map +1 -1
- package/dist/doc-schemas/media-assets.js +37 -19
- package/dist/doc-schemas/media-assets.js.map +1 -1
- package/dist/doc-schemas/notification-ledger.d.ts +99 -5
- package/dist/doc-schemas/notification-ledger.d.ts.map +1 -1
- package/dist/doc-schemas/notification-ledger.js +94 -16
- package/dist/doc-schemas/notification-ledger.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 +29 -1
- 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/index.d.ts +1 -0
- package/dist/media/index.d.ts.map +1 -1
- package/dist/media/index.js +1 -0
- package/dist/media/index.js.map +1 -1
- package/dist/media/publication/index.d.ts +2 -0
- package/dist/media/publication/index.d.ts.map +1 -0
- package/dist/media/publication/index.js +2 -0
- package/dist/media/publication/index.js.map +1 -0
- package/dist/media/publication/publication-args.d.ts +539 -0
- package/dist/media/publication/publication-args.d.ts.map +1 -0
- package/dist/media/publication/publication-args.js +182 -0
- package/dist/media/publication/publication-args.js.map +1 -0
- package/dist/media/target-info.d.ts.map +1 -1
- package/dist/media/target-info.js +4 -5
- package/dist/media/target-info.js.map +1 -1
- package/dist/paths/collection-groups.d.ts +1 -0
- package/dist/paths/collection-groups.d.ts.map +1 -1
- package/dist/paths/collection-groups.js +1 -0
- package/dist/paths/collection-groups.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/admin.d.ts +8 -2
- package/dist/schemas/admin.d.ts.map +1 -1
- package/dist/schemas/admin.js +10 -8
- package/dist/schemas/admin.js.map +1 -1
- package/dist/schemas/hall-library.d.ts +10 -3
- package/dist/schemas/hall-library.d.ts.map +1 -1
- package/dist/schemas/hall-library.js +30 -24
- package/dist/schemas/hall-library.js.map +1 -1
- package/dist/schemas/notification.d.ts +15 -8
- 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/schemas/users.d.ts +5 -0
- package/dist/schemas/users.d.ts.map +1 -1
- package/dist/schemas/users.js +15 -11
- package/dist/schemas/users.js.map +1 -1
- package/dist/upload-variables/create-admin-audition-variables.d.ts.map +1 -1
- package/dist/upload-variables/create-admin-audition-variables.js +2 -1
- package/dist/upload-variables/create-admin-audition-variables.js.map +1 -1
- package/dist/upload-variables/create-work-project-audition-variables.d.ts.map +1 -1
- package/dist/upload-variables/create-work-project-audition-variables.js +2 -1
- package/dist/upload-variables/create-work-project-audition-variables.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
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// media ONLY by `*AssetId` fields — never URLs. Serving authority is the
|
|
4
4
|
// gateway Worker (cookie/grant + KV blocklist); this doc is the server-side
|
|
5
5
|
// truth the edge records derive from. NO client reads, NO client writes.
|
|
6
|
-
// See ttt-prod docs/design/media-assets-and-protected-serving.md.
|
|
7
6
|
import { z } from 'zod';
|
|
8
7
|
import { StructuredErrorSchema } from '@ttt-productions/edge-protocol-core';
|
|
9
8
|
import { TIMED_MEDIA_MAIN_OUTPUT_KEY, VIDEO_POSTER_OUTPUT_KEY } from '@ttt-productions/media-schemas';
|
|
@@ -28,8 +27,7 @@ export const MediaAssetOwnerTypeSchema = z.enum([
|
|
|
28
27
|
'audition',
|
|
29
28
|
'auditionEntry',
|
|
30
29
|
// A file in a conversation's flat Conversation Files list (guild-invite or
|
|
31
|
-
// admin-support).
|
|
32
|
-
// messages no longer own media.
|
|
30
|
+
// admin-support). Chat messages own no media.
|
|
33
31
|
'conversationFile',
|
|
34
32
|
// Realm shared files are the deliberate MUTATE-IN-PLACE exception: a promoted work file
|
|
35
33
|
// keeps its ONE `workFile`-owned asset doc and flips tier in place, so no asset is ever
|
|
@@ -41,7 +39,7 @@ export const MediaAssetOwnerTypeSchema = z.enum([
|
|
|
41
39
|
// An admin video held by a system video slot; the owner id is the slot id.
|
|
42
40
|
'systemContent',
|
|
43
41
|
]);
|
|
44
|
-
// ===== Media origin lineage
|
|
42
|
+
// ===== Media origin lineage =====
|
|
45
43
|
// One canonical lineage used by media, CSAM, and safety. Embedded on every
|
|
46
44
|
// media asset + every copy.
|
|
47
45
|
/** The ONE canonical stored content media kind (what the pipeline produces and the
|
|
@@ -65,12 +63,18 @@ export const MEDIA_VARIANT_KEYS = [
|
|
|
65
63
|
VIDEO_POSTER_OUTPUT_KEY,
|
|
66
64
|
];
|
|
67
65
|
export const MediaVariantKeySchema = z.enum(MEDIA_VARIANT_KEYS);
|
|
68
|
-
/**
|
|
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
|
+
];
|
|
74
|
+
/** Why this asset was created from its source.
|
|
69
75
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* Conversation File is an ORIGINAL (`original`), never a chat derivative; nothing
|
|
73
|
-
* ever set the retired value. */
|
|
76
|
+
* Chat is text-only and owns no media, so no copy is ever made for a chat message. A
|
|
77
|
+
* Conversation File is an ORIGINAL (`original`), never a derivative. */
|
|
74
78
|
export const MediaCopyReasonSchema = z.enum([
|
|
75
79
|
'original',
|
|
76
80
|
'variant',
|
|
@@ -81,7 +85,7 @@ export const MediaCopyReasonSchema = z.enum([
|
|
|
81
85
|
'other',
|
|
82
86
|
]);
|
|
83
87
|
/**
|
|
84
|
-
* Canonical media origin lineage
|
|
88
|
+
* Canonical media origin lineage. A copy INHERITS
|
|
85
89
|
* rootIngestId/rootAssetId/originatingUploaderUid/originatingUploadEventId/
|
|
86
90
|
* originalUploadCreatedAt/rootSha256/originalSha256 unchanged; it sets its own
|
|
87
91
|
* sourceAssetId/variantSha256s/copyReason/copyActorUid/currentOwner*. Client
|
|
@@ -96,10 +100,10 @@ export const MediaOriginLineageV1Schema = z.object({
|
|
|
96
100
|
rootAssetId: z.string().min(1), // first asset created from that ingest
|
|
97
101
|
sourceAssetId: z.string().min(1).optional(), // immediate parent copied from (absent on the root)
|
|
98
102
|
originatingUploaderUid: z.string().min(1), // set server-side at first accepted ingest; IMMUTABLE; inherited
|
|
99
|
-
// May be '' for a
|
|
103
|
+
// May be '' for a copy synthesized from a source with no known upload event.
|
|
100
104
|
originatingUploadEventId: z.string(),
|
|
101
105
|
originalUploadCreatedAt: z.number(),
|
|
102
|
-
// '' until content hashing
|
|
106
|
+
// '' until content hashing fills in the real sha256.
|
|
103
107
|
// NOT z.string().min(1): the media pipeline does not compute a content hash at finalize yet,
|
|
104
108
|
// so a freshly-ingested asset legitimately carries an empty rootSha256 until it is hashed.
|
|
105
109
|
rootSha256: z.string(),
|
|
@@ -202,8 +206,6 @@ export const REALM_FILE_ACTIVE_STATUS_VALUES = [
|
|
|
202
206
|
];
|
|
203
207
|
export const RealmFileActiveStatusSchema = z.enum(REALM_FILE_ACTIVE_STATUS_VALUES);
|
|
204
208
|
// ===== Serving authority (Durable Object) + publication gating =====
|
|
205
|
-
// See ttt-prod docs/design/media-assets-and-protected-serving.md (the design owner
|
|
206
|
-
// for the Durable Object serving authority and publication gating).
|
|
207
209
|
/** Whether the canonical serving record has been applied to the DO authority. */
|
|
208
210
|
export const MediaAuthoritySyncStateSchema = z.enum(['pending', 'applied', 'deadLetter']);
|
|
209
211
|
/** Whether the asset is referenced by a visible owner doc. Orthogonal to the
|
|
@@ -363,8 +365,7 @@ export const MediaAssetSchema = z.object({
|
|
|
363
365
|
retentionPolicy: MediaRetentionPolicySchema,
|
|
364
366
|
legalHold: z.boolean(),
|
|
365
367
|
originalDeletedAt: z.number().optional(),
|
|
366
|
-
// T&S provenance lineage
|
|
367
|
-
// before the lineage rollout still parse; set server-side at first accepted
|
|
368
|
+
// T&S provenance lineage. Optional so an asset that carries no lineage still parses; set server-side at first accepted
|
|
368
369
|
// ingest, inherited unchanged by every copy/variant. Never client-supplied.
|
|
369
370
|
originLineage: MediaOriginLineageV1Schema.optional(),
|
|
370
371
|
// ===== Realm shared-files seam (request → steward approval → foldered pool) =====
|
|
@@ -390,8 +391,8 @@ export const MediaAssetSchema = z.object({
|
|
|
390
391
|
realmFileShareRequestId: z.string().min(1).optional(),
|
|
391
392
|
realmFileShareRequestedByUid: z.string().min(1).optional(),
|
|
392
393
|
realmFileShareRequestedAt: z.number().optional(),
|
|
393
|
-
// Serving authority + publication gating.
|
|
394
|
-
//
|
|
394
|
+
// Serving authority + publication gating. Optional so an asset with no
|
|
395
|
+
// authority state still parses: absent authorityVersion ⇒
|
|
395
396
|
// 0/never-applied, absent publicationState ⇒ 'unpublished'. Every
|
|
396
397
|
// serving-record mutation increments authorityVersion in an authoritative txn.
|
|
397
398
|
authorityVersion: z.number().int().nonnegative().optional(),
|
|
@@ -402,7 +403,7 @@ export const MediaAssetSchema = z.object({
|
|
|
402
403
|
authorityAppliedAt: z.number().optional(),
|
|
403
404
|
publishedAt: z.number().optional(),
|
|
404
405
|
lastAuthorityError: StructuredErrorSchema.optional(),
|
|
405
|
-
// Authority-sync retry ledger
|
|
406
|
+
// Authority-sync retry ledger: the scheduled worker bumps attemptCount + sets a backoff
|
|
406
407
|
// nextAttemptAt on a transient apply failure, and dead-letters (authoritySyncState='deadLetter')
|
|
407
408
|
// past a threshold. Absent ⇒ 0 attempts / immediately due.
|
|
408
409
|
authoritySyncAttemptCount: z.number().int().nonnegative().optional(),
|
|
@@ -482,6 +483,23 @@ export const MediaAssetSchema = z.object({
|
|
|
482
483
|
forbid(path, value, `${path} must be cleared once the request is resolved (realmFileCanonStatus is "${val.realmFileCanonStatus}")`);
|
|
483
484
|
}
|
|
484
485
|
});
|
|
486
|
+
// Field projections of an asset doc for readers that need only a few of its fields. Each composes
|
|
487
|
+
// the canonical field schemas and strips every other key, and none runs MediaAssetSchema's
|
|
488
|
+
// whole-doc refinement, so a doc with unrelated stored fields still yields the fields read.
|
|
489
|
+
/** What the Hall-media orphan reaper's asset phase reads of a candidate asset. */
|
|
490
|
+
export const MediaAssetReapCandidateSchema = z.object({
|
|
491
|
+
mediaAssetId: MediaAssetSchema.shape.mediaAssetId,
|
|
492
|
+
ownerId: MediaAssetSchema.shape.ownerId,
|
|
493
|
+
createdAt: MediaAssetSchema.shape.createdAt,
|
|
494
|
+
publicationState: MediaAssetSchema.shape.publicationState,
|
|
495
|
+
retirement: MediaAssetSchema.shape.retirement,
|
|
496
|
+
});
|
|
497
|
+
/** What a copy's safety-hold check reads of its source asset. */
|
|
498
|
+
export const MediaAssetCopySourceHoldFieldsSchema = z.object({
|
|
499
|
+
mediaAssetId: MediaAssetSchema.shape.mediaAssetId,
|
|
500
|
+
originLineage: MediaAssetSchema.shape.originLineage,
|
|
501
|
+
legalHold: MediaAssetSchema.shape.legalHold,
|
|
502
|
+
});
|
|
485
503
|
export function mediaAssetRetirementStanding(asset) {
|
|
486
504
|
if (asset === undefined)
|
|
487
505
|
return 'absent';
|
|
@@ -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// See ttt-prod docs/design/media-assets-and-protected-serving.md.\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). Replaces the removed `guildChatAttachment` owner type — chat\n // messages no longer own 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 (Appendix A0) =====\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 (A0).\n *\n * `chat_derivative` was REMOVED with the chat-attachment architecture: chat is\n * text-only and owns no media, so no copy can be made \"for a chat message\". A\n * Conversation File is an ORIGINAL (`original`), never a chat derivative; nothing\n * ever set the retired value. */\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 (Appendix A0). 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 legacy copy synthesized from a pre-rollout source with no known upload event.\n originatingUploadEventId: z.string(),\n originalUploadCreatedAt: z.number(),\n // '' until content hashing backfills the real sha256 (Phase 5 PhotoDNA / evidence capture).\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// See ttt-prod docs/design/media-assets-and-protected-serving.md (the design owner\n// for the Durable Object serving authority and 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 (Appendix A0). Additive/optional so assets written\n // before the lineage rollout still parse; 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. Additive/optional so assets\n // written before the authority build still parse: 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 (M1): 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/**\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"]}
|
|
@@ -65,17 +65,83 @@ export declare const NotificationDeliverySchema: z.ZodObject<{
|
|
|
65
65
|
expireAt: z.ZodOptional<z.ZodUnknown>;
|
|
66
66
|
}, z.core.$strip>;
|
|
67
67
|
export type NotificationDelivery = z.infer<typeof NotificationDeliverySchema>;
|
|
68
|
+
/**
|
|
69
|
+
* One phase's audience selector, keyed on `kind`, with the exact arguments that kind
|
|
70
|
+
* needs. A selector missing its target id or its uid list is refused rather than
|
|
71
|
+
* draining to zero recipients.
|
|
72
|
+
*/
|
|
73
|
+
export declare const NotificationFanoutPhaseSelectorSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
74
|
+
kind: z.ZodLiteral<"workFollowers">;
|
|
75
|
+
workProjectId: z.ZodString;
|
|
76
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
77
|
+
kind: z.ZodLiteral<"realmFollowers">;
|
|
78
|
+
workRealmId: z.ZodString;
|
|
79
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
80
|
+
kind: z.ZodLiteral<"userFollowers">;
|
|
81
|
+
artisanUid: z.ZodString;
|
|
82
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
83
|
+
kind: z.ZodLiteral<"workMembers">;
|
|
84
|
+
memberUids: z.ZodArray<z.ZodString>;
|
|
85
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
86
|
+
kind: z.ZodLiteral<"userFollowersMany">;
|
|
87
|
+
memberUids: z.ZodArray<z.ZodString>;
|
|
88
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
89
|
+
kind: z.ZodLiteral<"workGuildMembers">;
|
|
90
|
+
workProjectId: z.ZodString;
|
|
91
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
92
|
+
kind: z.ZodLiteral<"realmMembers">;
|
|
93
|
+
workRealmId: z.ZodString;
|
|
94
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
95
|
+
kind: z.ZodLiteral<"allArtisans">;
|
|
96
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
97
|
+
kind: z.ZodLiteral<"allActiveUsers">;
|
|
98
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
99
|
+
kind: z.ZodLiteral<"explicitUids">;
|
|
100
|
+
uids: z.ZodArray<z.ZodString>;
|
|
101
|
+
}, z.core.$strip>], "kind">;
|
|
102
|
+
export type NotificationFanoutPhaseSelector = z.infer<typeof NotificationFanoutPhaseSelectorSchema>;
|
|
103
|
+
export type NotificationFanoutPhaseSelectorKind = NotificationFanoutPhaseSelector['kind'];
|
|
104
|
+
/** One phase: its selector, the durable cursor in that selector's shape, and whether it is done. */
|
|
68
105
|
export declare const NotificationFanoutPhaseSchema: z.ZodObject<{
|
|
69
|
-
selector: z.
|
|
106
|
+
selector: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
107
|
+
kind: z.ZodLiteral<"workFollowers">;
|
|
108
|
+
workProjectId: z.ZodString;
|
|
109
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
110
|
+
kind: z.ZodLiteral<"realmFollowers">;
|
|
111
|
+
workRealmId: z.ZodString;
|
|
112
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
113
|
+
kind: z.ZodLiteral<"userFollowers">;
|
|
114
|
+
artisanUid: z.ZodString;
|
|
115
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
116
|
+
kind: z.ZodLiteral<"workMembers">;
|
|
117
|
+
memberUids: z.ZodArray<z.ZodString>;
|
|
118
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
119
|
+
kind: z.ZodLiteral<"userFollowersMany">;
|
|
120
|
+
memberUids: z.ZodArray<z.ZodString>;
|
|
121
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
122
|
+
kind: z.ZodLiteral<"workGuildMembers">;
|
|
123
|
+
workProjectId: z.ZodString;
|
|
124
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
125
|
+
kind: z.ZodLiteral<"realmMembers">;
|
|
126
|
+
workRealmId: z.ZodString;
|
|
127
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
128
|
+
kind: z.ZodLiteral<"allArtisans">;
|
|
129
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
130
|
+
kind: z.ZodLiteral<"allActiveUsers">;
|
|
131
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
132
|
+
kind: z.ZodLiteral<"explicitUids">;
|
|
133
|
+
uids: z.ZodArray<z.ZodString>;
|
|
134
|
+
}, z.core.$strip>], "kind">;
|
|
70
135
|
cursor: z.ZodNullable<z.ZodUnknown>;
|
|
71
136
|
done: z.ZodBoolean;
|
|
72
137
|
}, z.core.$strip>;
|
|
138
|
+
export type NotificationFanoutPhase = z.infer<typeof NotificationFanoutPhaseSchema>;
|
|
73
139
|
/** A fanout job's priority tier, one of `NOTIFICATION_FANOUT_PRIORITIES`. */
|
|
74
140
|
export declare const NotificationFanoutPrioritySchema: z.ZodLiteral<0 | 1 | 2>;
|
|
75
141
|
/**
|
|
76
|
-
* The
|
|
77
|
-
*
|
|
78
|
-
* request-id reuse
|
|
142
|
+
* The stored fanout job. `phaseIndex` names an existing phase. The three
|
|
143
|
+
* admin-broadcast replay fields form one provenance unit: a job has all of them, or
|
|
144
|
+
* none, since a partial set could not distinguish a safe retry from request-id reuse.
|
|
79
145
|
*/
|
|
80
146
|
export declare const NotificationFanoutJobSchema: z.ZodObject<{
|
|
81
147
|
jobId: z.ZodString;
|
|
@@ -85,7 +151,35 @@ export declare const NotificationFanoutJobSchema: z.ZodObject<{
|
|
|
85
151
|
priority: z.ZodLiteral<0 | 1 | 2>;
|
|
86
152
|
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
87
153
|
phases: z.ZodArray<z.ZodObject<{
|
|
88
|
-
selector: z.
|
|
154
|
+
selector: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
155
|
+
kind: z.ZodLiteral<"workFollowers">;
|
|
156
|
+
workProjectId: z.ZodString;
|
|
157
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
158
|
+
kind: z.ZodLiteral<"realmFollowers">;
|
|
159
|
+
workRealmId: z.ZodString;
|
|
160
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
161
|
+
kind: z.ZodLiteral<"userFollowers">;
|
|
162
|
+
artisanUid: z.ZodString;
|
|
163
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
164
|
+
kind: z.ZodLiteral<"workMembers">;
|
|
165
|
+
memberUids: z.ZodArray<z.ZodString>;
|
|
166
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
167
|
+
kind: z.ZodLiteral<"userFollowersMany">;
|
|
168
|
+
memberUids: z.ZodArray<z.ZodString>;
|
|
169
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
170
|
+
kind: z.ZodLiteral<"workGuildMembers">;
|
|
171
|
+
workProjectId: z.ZodString;
|
|
172
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
173
|
+
kind: z.ZodLiteral<"realmMembers">;
|
|
174
|
+
workRealmId: z.ZodString;
|
|
175
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
176
|
+
kind: z.ZodLiteral<"allArtisans">;
|
|
177
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
178
|
+
kind: z.ZodLiteral<"allActiveUsers">;
|
|
179
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
180
|
+
kind: z.ZodLiteral<"explicitUids">;
|
|
181
|
+
uids: z.ZodArray<z.ZodString>;
|
|
182
|
+
}, z.core.$strip>], "kind">;
|
|
89
183
|
cursor: z.ZodNullable<z.ZodUnknown>;
|
|
90
184
|
done: z.ZodBoolean;
|
|
91
185
|
}, z.core.$strip>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-ledger.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/notification-ledger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"notification-ledger.d.ts","sourceRoot":"","sources":["../../src/doc-schemas/notification-ledger.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB;;+CAE+C;AAC/C,eAAO,MAAM,iCAAiC;;;;iBAI5C,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,+BAA+B;;;;;EAKE,CAAC;AAC/C,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF,4FAA4F;AAC5F,eAAO,MAAM,oCAAoC;;EAEE,CAAC;AACpD,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAC;AAKlG,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8BrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAK9E;;;;GAIG;AACH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAehD,CAAC;AACH,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qCAAqC,CAAC,CAAC;AACpG,MAAM,MAAM,mCAAmC,GAAG,+BAA+B,CAAC,MAAM,CAAC,CAAC;AAkD1F,oGAAoG;AACpG,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAcxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF,6EAA6E;AAC7E,eAAO,MAAM,gCAAgC,yBAA4C,CAAC;AA4B1F;;;;GAIG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqBtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|