@ttt-productions/ttt-core 0.79.87 → 0.79.88
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/media/upload-tray-display.d.ts +16 -12
- package/dist/media/upload-tray-display.d.ts.map +1 -1
- package/dist/media/upload-tray-display.js +13 -72
- package/dist/media/upload-tray-display.js.map +1 -1
- package/dist/utils/hall-content.d.ts +104 -1
- package/dist/utils/hall-content.d.ts.map +1 -1
- package/dist/utils/hall-content.js +13 -1
- package/dist/utils/hall-content.js.map +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/utils/format.d.ts +0 -6
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.js +0 -19
- package/dist/utils/format.js.map +0 -1
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import type { FileOrigin } from './file-origin.js';
|
|
2
2
|
export declare const fileOriginRowLabel: Record<FileOrigin, string>;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
/** How long an upload row's time reads as relative ("5m ago") before it reads as a clock time. */
|
|
4
|
+
export declare const UPLOAD_ROW_RELATIVE_TIME_CUTOFF_MS: number;
|
|
5
|
+
/** An upload row's words for its time and its file's kind. */
|
|
6
|
+
export declare const UPLOAD_ROW_DISPLAY_COPY: {
|
|
7
|
+
readonly justNow: "just now";
|
|
8
|
+
readonly minutesAgo: (minutes: number) => string;
|
|
9
|
+
readonly hoursAgo: (hours: number) => string;
|
|
10
|
+
readonly yesterdayAt: (time: string) => string;
|
|
11
|
+
readonly dateAt: (date: string, time: string) => string;
|
|
12
|
+
readonly fileType: {
|
|
13
|
+
readonly image: "Image";
|
|
14
|
+
readonly video: "Video";
|
|
15
|
+
readonly audio: "Audio";
|
|
16
|
+
readonly other: "File";
|
|
17
|
+
};
|
|
18
|
+
};
|
|
15
19
|
//# sourceMappingURL=upload-tray-display.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-tray-display.d.ts","sourceRoot":"","sources":["../../src/media/upload-tray-display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"upload-tray-display.d.ts","sourceRoot":"","sources":["../../src/media/upload-tray-display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AASnD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAyBzD,CAAC;AAQF,kGAAkG;AAClG,eAAO,MAAM,kCAAkC,QAAqB,CAAC;AAErE,8DAA8D;AAC9D,eAAO,MAAM,uBAAuB;;mCAEZ,MAAM;+BACV,MAAM;iCACJ,MAAM;4BACX,MAAM,QAAQ,MAAM;;;;;;;CAE3B,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getSimplifiedMediaType } from '@ttt-productions/media-schemas';
|
|
2
1
|
// =============================================================================
|
|
3
2
|
// User-facing labels per fileOrigin
|
|
4
3
|
// =============================================================================
|
|
@@ -32,77 +31,19 @@ export const fileOriginRowLabel = {
|
|
|
32
31
|
'ncii-evidence': 'Take-it-down evidence',
|
|
33
32
|
};
|
|
34
33
|
// =============================================================================
|
|
35
|
-
//
|
|
34
|
+
// Row time and file kind
|
|
36
35
|
// =============================================================================
|
|
37
36
|
//
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*/
|
|
51
|
-
export function formatUploadTimestamp(createdAtMs, nowMs, cutoffMs = DEFAULT_RELATIVE_TIME_CUTOFF_MS) {
|
|
52
|
-
const diffMs = Math.max(0, nowMs - createdAtMs);
|
|
53
|
-
if (diffMs < cutoffMs) {
|
|
54
|
-
// Relative path.
|
|
55
|
-
if (diffMs < 60_000)
|
|
56
|
-
return 'just now';
|
|
57
|
-
const minutes = Math.floor(diffMs / 60_000);
|
|
58
|
-
if (minutes < 60)
|
|
59
|
-
return `${minutes}m ago`;
|
|
60
|
-
const hours = Math.floor(diffMs / 3_600_000);
|
|
61
|
-
return `${hours}h ago`;
|
|
62
|
-
}
|
|
63
|
-
// Absolute path.
|
|
64
|
-
const created = new Date(createdAtMs);
|
|
65
|
-
const now = new Date(nowMs);
|
|
66
|
-
const timeStr = created.toLocaleTimeString(undefined, {
|
|
67
|
-
hour: 'numeric',
|
|
68
|
-
minute: '2-digit',
|
|
69
|
-
});
|
|
70
|
-
const sameDay = created.getFullYear() === now.getFullYear() &&
|
|
71
|
-
created.getMonth() === now.getMonth() &&
|
|
72
|
-
created.getDate() === now.getDate();
|
|
73
|
-
if (sameDay)
|
|
74
|
-
return timeStr;
|
|
75
|
-
const yesterday = new Date(nowMs - 24 * 60 * 60 * 1000);
|
|
76
|
-
const isYesterday = created.getFullYear() === yesterday.getFullYear() &&
|
|
77
|
-
created.getMonth() === yesterday.getMonth() &&
|
|
78
|
-
created.getDate() === yesterday.getDate();
|
|
79
|
-
if (isYesterday)
|
|
80
|
-
return `Yesterday ${timeStr}`;
|
|
81
|
-
const dateStr = created.toLocaleDateString(undefined, {
|
|
82
|
-
month: 'short',
|
|
83
|
-
day: 'numeric',
|
|
84
|
-
});
|
|
85
|
-
return `${dateStr}, ${timeStr}`;
|
|
86
|
-
}
|
|
87
|
-
// =============================================================================
|
|
88
|
-
// File type labeling
|
|
89
|
-
// =============================================================================
|
|
90
|
-
//
|
|
91
|
-
// Friendly label for a content type string. Wraps getSimplifiedMediaType
|
|
92
|
-
// from media-schemas with capitalization for tray display.
|
|
93
|
-
// Returns null when contentType is undefined/empty.
|
|
94
|
-
export function getFileTypeLabel(contentType) {
|
|
95
|
-
if (!contentType)
|
|
96
|
-
return null;
|
|
97
|
-
switch (getSimplifiedMediaType(contentType)) {
|
|
98
|
-
case 'image':
|
|
99
|
-
return 'Image';
|
|
100
|
-
case 'video':
|
|
101
|
-
return 'Video';
|
|
102
|
-
case 'audio':
|
|
103
|
-
return 'Audio';
|
|
104
|
-
default:
|
|
105
|
-
return 'File';
|
|
106
|
-
}
|
|
107
|
-
}
|
|
37
|
+
// The words and cutoff the app hands upload-ui's `createUploadDisplayFormatters`.
|
|
38
|
+
/** How long an upload row's time reads as relative ("5m ago") before it reads as a clock time. */
|
|
39
|
+
export const UPLOAD_ROW_RELATIVE_TIME_CUTOFF_MS = 6 * 60 * 60 * 1000;
|
|
40
|
+
/** An upload row's words for its time and its file's kind. */
|
|
41
|
+
export const UPLOAD_ROW_DISPLAY_COPY = {
|
|
42
|
+
justNow: 'just now',
|
|
43
|
+
minutesAgo: (minutes) => `${minutes}m ago`,
|
|
44
|
+
hoursAgo: (hours) => `${hours}h ago`,
|
|
45
|
+
yesterdayAt: (time) => `Yesterday ${time}`,
|
|
46
|
+
dateAt: (date, time) => `${date}, ${time}`,
|
|
47
|
+
fileType: { image: 'Image', video: 'Video', audio: 'Audio', other: 'File' },
|
|
48
|
+
};
|
|
108
49
|
//# sourceMappingURL=upload-tray-display.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-tray-display.js","sourceRoot":"","sources":["../../src/media/upload-tray-display.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upload-tray-display.js","sourceRoot":"","sources":["../../src/media/upload-tray-display.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,oCAAoC;AACpC,gFAAgF;AAChF,EAAE;AACF,yEAAyE;AACzE,mEAAmE;AAEnE,MAAM,CAAC,MAAM,kBAAkB,GAA+B;IAC5D,iBAAiB,EAAE,iBAAiB;IACpC,mBAAmB,EAAE,OAAO;IAC5B,eAAe,EAAE,aAAa;IAC9B,oBAAoB,EAAE,oBAAoB;IAC1C,qBAAqB,EAAE,qBAAqB;IAC5C,iBAAiB,EAAE,UAAU;IAC7B,gFAAgF;IAChF,iFAAiF;IACjF,6DAA6D;IAC7D,uBAAuB,EAAE,gBAAgB;IACzC,gBAAgB,EAAE,gBAAgB;IAClC,0BAA0B,EAAE,YAAY;IACxC,0BAA0B,EAAE,YAAY;IACxC,6BAA6B,EAAE,YAAY;IAC3C,aAAa,EAAE,aAAa;IAC5B,eAAe,EAAE,eAAe;IAChC,kBAAkB,EAAE,aAAa;IACjC,kBAAkB,EAAE,aAAa;IACjC,0BAA0B,EAAE,eAAe;IAC3C,0BAA0B,EAAE,eAAe;IAC3C,YAAY,EAAE,YAAY;IAC1B,mBAAmB,EAAE,mBAAmB;IACxC,gBAAgB,EAAE,cAAc;IAChC,eAAe,EAAE,uBAAuB;CACzC,CAAC;AAEF,gFAAgF;AAChF,yBAAyB;AACzB,gFAAgF;AAChF,EAAE;AACF,kFAAkF;AAElF,kGAAkG;AAClG,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAErE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,OAAO,EAAE,UAAU;IACnB,UAAU,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,GAAG,OAAO,OAAO;IAClD,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,GAAG,KAAK,OAAO;IAC5C,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,aAAa,IAAI,EAAE;IAClD,MAAM,EAAE,CAAC,IAAY,EAAE,IAAY,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,EAAE;IAC1D,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE;CACnE,CAAC","sourcesContent":["import type { FileOrigin } from './file-origin.js';\n\n// =============================================================================\n// User-facing labels per fileOrigin\n// =============================================================================\n//\n// Generic labels for upload tray rows. Same regardless of platform (web,\n// iOS, Android, smart TV) since they describe TTT domain entities.\n\nexport const fileOriginRowLabel: Record<FileOrigin, string> = {\n 'profile-picture': 'Profile picture',\n 'craft-skill-media': 'Craft',\n 'squareStreetz': 'Square post',\n 'commission-posting': 'Commission posting',\n 'commission-proposal': 'Commission proposal',\n 'audition-prompt': 'Audition',\n // Neutral on purpose: this origin creates BOTH Platform and Sponsored auditions\n // (AdminAuditionPromptTargetInfoSchema.type), so it cannot borrow either settled\n // AUDITION_TYPES label without lying about half its uploads.\n 'admin-audition-prompt': 'Admin audition',\n 'audition-entry': 'Audition entry',\n 'hallLibrary-cover-square': 'Work cover',\n 'hallLibrary-cover-poster': 'Work cover',\n 'hallLibrary-cover-cinematic': 'Work cover',\n 'realm-cover': 'Realm cover',\n 'chapter-photo': 'Chapter photo',\n 'tune-track-photo': 'Track photo',\n 'tune-track-audio': 'Track audio',\n 'television-episode-photo': 'Episode photo',\n 'television-episode-video': 'Episode video',\n 'work-asset': 'Work asset',\n 'conversation-file': 'Conversation file',\n 'system-content': 'System video',\n 'ncii-evidence': 'Take-it-down evidence',\n};\n\n// =============================================================================\n// Row time and file kind\n// =============================================================================\n//\n// The words and cutoff the app hands upload-ui's `createUploadDisplayFormatters`.\n\n/** How long an upload row's time reads as relative (\"5m ago\") before it reads as a clock time. */\nexport const UPLOAD_ROW_RELATIVE_TIME_CUTOFF_MS = 6 * 60 * 60 * 1000;\n\n/** An upload row's words for its time and its file's kind. */\nexport const UPLOAD_ROW_DISPLAY_COPY = {\n justNow: 'just now',\n minutesAgo: (minutes: number) => `${minutes}m ago`,\n hoursAgo: (hours: number) => `${hours}h ago`,\n yesterdayAt: (time: string) => `Yesterday ${time}`,\n dateAt: (date: string, time: string) => `${date}, ${time}`,\n fileType: { image: 'Image', video: 'Video', audio: 'Audio', other: 'File' },\n} as const;\n"]}
|
|
@@ -1,6 +1,109 @@
|
|
|
1
1
|
import { HALL_CONTENT_TEXT_FIELDS } from '../constants/business-content.js';
|
|
2
2
|
import type { WorkProjectType } from '../types/content.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type FullChapter, type FullTelevisionEpisode, type FullTuneTrack } from '../doc-schemas/content.js';
|
|
4
|
+
/**
|
|
5
|
+
* Each work type's published Hall sub-item: the subcollection it is stored in and the schema it is
|
|
6
|
+
* stored as, declared together. A writer looks its work type up once and takes both from the one
|
|
7
|
+
* entry, so one kind's shape can never be stored in another kind's subcollection.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PUBLISHED_HALL_SUB_ITEM_BY_WORK_TYPE: {
|
|
10
|
+
readonly Tales: {
|
|
11
|
+
readonly subcollection: import("../paths/collections.js").HallItemSubcollection;
|
|
12
|
+
readonly schema: import("zod").ZodObject<{
|
|
13
|
+
uid: import("zod").ZodString;
|
|
14
|
+
title: import("zod").ZodString;
|
|
15
|
+
order: import("zod").ZodNumber;
|
|
16
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
17
|
+
content: import("zod").ZodString;
|
|
18
|
+
photoAssetId: import("zod").ZodString;
|
|
19
|
+
hidden: import("zod").ZodBoolean;
|
|
20
|
+
hiddenBy: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
21
|
+
direct: "direct";
|
|
22
|
+
cascade: "cascade";
|
|
23
|
+
}>>;
|
|
24
|
+
moderationClearedFields: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
25
|
+
moderationClearedReason: import("zod").ZodOptional<import("zod").ZodString>;
|
|
26
|
+
moderatedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
27
|
+
edgeSyncState: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodEnum<{
|
|
28
|
+
failed: "failed";
|
|
29
|
+
processing: "processing";
|
|
30
|
+
}>>>;
|
|
31
|
+
edgeSyncProcessingAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
32
|
+
edgeSyncOp: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
33
|
+
block: "block";
|
|
34
|
+
blockClear: "blockClear";
|
|
35
|
+
}>>;
|
|
36
|
+
edgeSyncDecision: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
37
|
+
edgeSyncAssetIds: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
38
|
+
edgeSyncError: import("zod").ZodOptional<import("zod").ZodString>;
|
|
39
|
+
edgeSyncFailedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
40
|
+
}, import("zod/v4/core").$strip>;
|
|
41
|
+
};
|
|
42
|
+
readonly Tunes: {
|
|
43
|
+
readonly subcollection: import("../paths/collections.js").HallItemSubcollection;
|
|
44
|
+
readonly schema: import("zod").ZodObject<{
|
|
45
|
+
uid: import("zod").ZodString;
|
|
46
|
+
title: import("zod").ZodString;
|
|
47
|
+
order: import("zod").ZodNumber;
|
|
48
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
49
|
+
audioAssetId: import("zod").ZodString;
|
|
50
|
+
photoAssetId: import("zod").ZodString;
|
|
51
|
+
hidden: import("zod").ZodBoolean;
|
|
52
|
+
hiddenBy: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
53
|
+
direct: "direct";
|
|
54
|
+
cascade: "cascade";
|
|
55
|
+
}>>;
|
|
56
|
+
moderationClearedFields: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
57
|
+
moderationClearedReason: import("zod").ZodOptional<import("zod").ZodString>;
|
|
58
|
+
moderatedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
59
|
+
edgeSyncState: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodEnum<{
|
|
60
|
+
failed: "failed";
|
|
61
|
+
processing: "processing";
|
|
62
|
+
}>>>;
|
|
63
|
+
edgeSyncProcessingAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
64
|
+
edgeSyncOp: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
65
|
+
block: "block";
|
|
66
|
+
blockClear: "blockClear";
|
|
67
|
+
}>>;
|
|
68
|
+
edgeSyncDecision: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
69
|
+
edgeSyncAssetIds: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
70
|
+
edgeSyncError: import("zod").ZodOptional<import("zod").ZodString>;
|
|
71
|
+
edgeSyncFailedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
72
|
+
}, import("zod/v4/core").$strip>;
|
|
73
|
+
};
|
|
74
|
+
readonly Television: {
|
|
75
|
+
readonly subcollection: import("../paths/collections.js").HallItemSubcollection;
|
|
76
|
+
readonly schema: import("zod").ZodObject<{
|
|
77
|
+
uid: import("zod").ZodString;
|
|
78
|
+
title: import("zod").ZodString;
|
|
79
|
+
order: import("zod").ZodNumber;
|
|
80
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
81
|
+
videoAssetId: import("zod").ZodString;
|
|
82
|
+
photoAssetId: import("zod").ZodString;
|
|
83
|
+
hidden: import("zod").ZodBoolean;
|
|
84
|
+
hiddenBy: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
85
|
+
direct: "direct";
|
|
86
|
+
cascade: "cascade";
|
|
87
|
+
}>>;
|
|
88
|
+
moderationClearedFields: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
89
|
+
moderationClearedReason: import("zod").ZodOptional<import("zod").ZodString>;
|
|
90
|
+
moderatedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
91
|
+
edgeSyncState: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodEnum<{
|
|
92
|
+
failed: "failed";
|
|
93
|
+
processing: "processing";
|
|
94
|
+
}>>>;
|
|
95
|
+
edgeSyncProcessingAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
96
|
+
edgeSyncOp: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
97
|
+
block: "block";
|
|
98
|
+
blockClear: "blockClear";
|
|
99
|
+
}>>;
|
|
100
|
+
edgeSyncDecision: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
101
|
+
edgeSyncAssetIds: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
102
|
+
edgeSyncError: import("zod").ZodOptional<import("zod").ZodString>;
|
|
103
|
+
edgeSyncFailedAt: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
104
|
+
}, import("zod/v4/core").$strip>;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
4
107
|
/** A published hall-content surface whose text a change request or the moderation
|
|
5
108
|
* text-clear remedy can target. */
|
|
6
109
|
export type HallContentTextFieldSurface = keyof typeof HALL_CONTENT_TEXT_FIELDS;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hall-content.d.ts","sourceRoot":"","sources":["../../src/utils/hall-content.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,wBAAwB,EAGzB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"hall-content.d.ts","sourceRoot":"","sources":["../../src/utils/hall-content.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,wBAAwB,EAGzB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EACnB,MAAM,2BAA2B,CAAC;AAGnC;;;;GAIG;AACH,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIuC,CAAC;AAEzF;oCACoC;AACpC,MAAM,MAAM,2BAA2B,GAAG,MAAM,OAAO,wBAAwB,CAAC;AAEhF,0FAA0F;AAC1F,MAAM,MAAM,wBAAwB,CAAC,CAAC,SAAS,2BAA2B,IACxE,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAExE,MAAM,MAAM,+BAA+B,CAAC,CAAC,SAAS,2BAA2B,IAC7E;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAA;CAAE,GACnE;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,CAAC,SAAS,2BAA2B,EACjF,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAChD,+BAA+B,CAAC,CAAC,CAAC,CAkBpC;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACzC,MAAM,EAAE,CAQV;AAED,4EAA4E;AAC5E,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACzC,OAAO,CAET;AAED,+FAA+F;AAC/F,MAAM,MAAM,iBAAiB,GAAG,CAAC,WAAW,GAAG,aAAa,GAAG,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC;AAEhG;;uBAEuB;AACvB,eAAO,MAAM,6BAA6B,4CAAoF,CAAC;AAE/H;kBACkB;AAClB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAE5D;AAED;0CAC0C;AAC1C,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAEvG;AAED;aACa;AACb,wBAAgB,+BAA+B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3E"}
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
// Pure hall-content rules shared by the member surfaces and the backend cores that own the
|
|
2
|
-
// writes. Server-safe: constants and plain functions only.
|
|
2
|
+
// writes. Server-safe: constants, canonical schemas, and plain functions only.
|
|
3
3
|
import { checkTextField } from './text-field.js';
|
|
4
4
|
import { HALL_CONTENT_TEXT_FIELDS, HALL_SUB_ITEM_REQUIRED_FIELDS_BY_WORK_TYPE, HALL_SUB_ITEM_REQUIREMENT_LABELS, } from '../constants/business-content.js';
|
|
5
5
|
import { HALL_CONTENT_CHANGE_REQUEST_INPUTS } from '../constants/text-fields.js';
|
|
6
|
+
import { PublishedChapterSchema, PublishedTelevisionEpisodeSchema, PublishedTuneTrackSchema, } from '../doc-schemas/content.js';
|
|
7
|
+
import { HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE } from '../paths/collections.js';
|
|
8
|
+
/**
|
|
9
|
+
* Each work type's published Hall sub-item: the subcollection it is stored in and the schema it is
|
|
10
|
+
* stored as, declared together. A writer looks its work type up once and takes both from the one
|
|
11
|
+
* entry, so one kind's shape can never be stored in another kind's subcollection.
|
|
12
|
+
*/
|
|
13
|
+
export const PUBLISHED_HALL_SUB_ITEM_BY_WORK_TYPE = {
|
|
14
|
+
Tales: { subcollection: HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE.Tales, schema: PublishedChapterSchema },
|
|
15
|
+
Tunes: { subcollection: HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE.Tunes, schema: PublishedTuneTrackSchema },
|
|
16
|
+
Television: { subcollection: HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE.Television, schema: PublishedTelevisionEpisodeSchema },
|
|
17
|
+
};
|
|
6
18
|
/**
|
|
7
19
|
* The ONE strict per-surface check for a proposed hall-content text map: every key must be a
|
|
8
20
|
* field that surface owns, and every value must meet that field's change-request declaration
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hall-content.js","sourceRoot":"","sources":["../../src/utils/hall-content.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F
|
|
1
|
+
{"version":3,"file":"hall-content.js","sourceRoot":"","sources":["../../src/utils/hall-content.ts"],"names":[],"mappings":"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","sourcesContent":["// Pure hall-content rules shared by the member surfaces and the backend cores that own the\n// writes. Server-safe: constants, canonical schemas, and plain functions only.\n\nimport { checkTextField, type TextFieldDeclaration } from './text-field.js';\nimport {\n HALL_CONTENT_TEXT_FIELDS,\n HALL_SUB_ITEM_REQUIRED_FIELDS_BY_WORK_TYPE,\n HALL_SUB_ITEM_REQUIREMENT_LABELS,\n} from '../constants/business-content.js';\nimport { HALL_CONTENT_CHANGE_REQUEST_INPUTS } from '../constants/text-fields.js';\nimport type { WorkProjectType } from '../types/content.js';\nimport {\n PublishedChapterSchema,\n PublishedTelevisionEpisodeSchema,\n PublishedTuneTrackSchema,\n type FullChapter,\n type FullTelevisionEpisode,\n type FullTuneTrack,\n} from '../doc-schemas/content.js';\nimport { HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE } from '../paths/collections.js';\n\n/**\n * Each work type's published Hall sub-item: the subcollection it is stored in and the schema it is\n * stored as, declared together. A writer looks its work type up once and takes both from the one\n * entry, so one kind's shape can never be stored in another kind's subcollection.\n */\nexport const PUBLISHED_HALL_SUB_ITEM_BY_WORK_TYPE = {\n Tales: { subcollection: HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE.Tales, schema: PublishedChapterSchema },\n Tunes: { subcollection: HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE.Tunes, schema: PublishedTuneTrackSchema },\n Television: { subcollection: HALL_ITEM_SUBCOLLECTION_BY_WORK_TYPE.Television, schema: PublishedTelevisionEpisodeSchema },\n} as const satisfies Record<WorkProjectType, { subcollection: string; schema: unknown }>;\n\n/** A published hall-content surface whose text a change request or the moderation\n * text-clear remedy can target. */\nexport type HallContentTextFieldSurface = keyof typeof HALL_CONTENT_TEXT_FIELDS;\n\n/** The proposed-text map a given surface accepts: only that surface's own field names. */\nexport type HallContentTextFieldsFor<S extends HallContentTextFieldSurface> =\n Partial<Record<(typeof HALL_CONTENT_TEXT_FIELDS)[S][number], string>>;\n\nexport type HallContentTextFieldsValidation<S extends HallContentTextFieldSurface> =\n | { readonly ok: true; readonly fields: HallContentTextFieldsFor<S> }\n | { readonly ok: false; readonly reason: string };\n\n/**\n * The ONE strict per-surface check for a proposed hall-content text map: every key must be a\n * field that surface owns, and every value must meet that field's change-request declaration\n * (`HALL_CONTENT_CHANGE_REQUEST_INPUTS` — trimmed, never empty, within its max, in its format). The\n * stored `hallContentChangeRequests` shape is a flat field map with the request's own `surface`\n * as the single authoritative discriminator, so this is where the allowlist is enforced — at the\n * backend boundary, before the map is persisted or written onto a published doc.\n *\n * The allowlist comes from the canonical Hall text-field map and each rule from the field's\n * declaration; there is no second allowlist anywhere.\n *\n * @returns the normalized (trimmed) field map, or the user-facing reason it was rejected.\n */\nexport function validateHallContentTextFields<S extends HallContentTextFieldSurface>(\n surface: S,\n proposedFields: Readonly<Record<string, unknown>>,\n): HallContentTextFieldsValidation<S> {\n const allowed = HALL_CONTENT_TEXT_FIELDS[surface] as readonly string[];\n const normalized: Record<string, string> = {};\n\n for (const [field, rawValue] of Object.entries(proposedFields)) {\n if (!allowed.includes(field)) {\n return { ok: false, reason: `Field \"${field}\" is not editable on this item.` };\n }\n const declaration = (HALL_CONTENT_CHANGE_REQUEST_INPUTS[surface] as Record<string, TextFieldDeclaration>)[field];\n const result = checkTextField(declaration, typeof rawValue === 'string' ? rawValue : '');\n if (!result.ok) return { ok: false, reason: result.reason };\n normalized[field] = result.value;\n }\n\n if (Object.keys(normalized).length === 0) {\n return { ok: false, reason: 'No valid text fields proposed.' };\n }\n return { ok: true, fields: normalized as HallContentTextFieldsFor<S> };\n}\n\n/**\n * The requirements a Tale chapter / Tune track / Television episode has not met yet, as the\n * wording a surface can show, in the canonical field order. Empty means the sub-item may be\n * submitted, approved, and published.\n *\n * ONE owner for the member-side eligibility filter and all three backend cores — none of them\n * restates the per-type branch.\n */\nexport function unmetHallSubItemRequirements(\n workProjectType: WorkProjectType,\n subItem: Readonly<Record<string, unknown>>,\n): string[] {\n const required = HALL_SUB_ITEM_REQUIRED_FIELDS_BY_WORK_TYPE[workProjectType];\n return required\n .filter((field) => {\n const value = subItem[field];\n return typeof value !== 'string' || value.trim().length === 0;\n })\n .map((field) => HALL_SUB_ITEM_REQUIREMENT_LABELS[field]);\n}\n\n/** True when the sub-item meets every requirement its work type imposes. */\nexport function isHallSubItemPublishable(\n workProjectType: WorkProjectType,\n subItem: Readonly<Record<string, unknown>>,\n): boolean {\n return unmetHallSubItemRequirements(workProjectType, subItem).length === 0;\n}\n\n/** The review status every chapter / track / episode carries (one set for the three kinds). */\nexport type HallSubItemStatus = (FullChapter | FullTuneTrack | FullTelevisionEpisode)['status'];\n\n/** The statuses that lock a sub-item against edits and media attaches: submitted for library\n * review, or published to the Hall. Text changes to a published item go through a change\n * request instead. */\nexport const HALL_SUB_ITEM_LOCKED_STATUSES = ['pending_approval', 'published'] as const satisfies readonly HallSubItemStatus[];\n\n/** True when a sub-item in this status is locked; any other value, a missing status included, is\n * not a lock. */\nexport function isHallSubItemLocked(status: unknown): boolean {\n return (HALL_SUB_ITEM_LOCKED_STATUSES as readonly unknown[]).includes(status);\n}\n\n/** The `targetKey` a Hall-grain change request is stored and queried under: one open request per\n * Hall item's detail or per sub-item. */\nexport function hallContentChangeRequestTargetKey(hallItemId: string, subItemId?: string | null): string {\n return `${hallItemId}_${subItemId ?? 'detail'}`;\n}\n\n/** The `targetKey` a Realm-grain change request is stored and queried under: one open request per\n * Realm. */\nexport function workRealmChangeRequestTargetKey(workRealmId: string): string {\n return `realm_${workRealmId}`;\n}\n"]}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export * from './admin-standing.js';
|
|
2
2
|
export * from './age-derivation.js';
|
|
3
3
|
export * from './app-config.js';
|
|
4
|
-
export * from './format.js';
|
|
5
4
|
export * from './guild-chat-access.js';
|
|
6
5
|
export * from './guild-invite-system-message.js';
|
|
7
6
|
export * from './hall-content.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export * from './admin-standing.js';
|
|
2
2
|
export * from './age-derivation.js';
|
|
3
3
|
export * from './app-config.js';
|
|
4
|
-
export * from './format.js';
|
|
5
4
|
export * from './guild-chat-access.js';
|
|
6
5
|
export * from './guild-invite-system-message.js';
|
|
7
6
|
export * from './hall-content.js';
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC","sourcesContent":["export * from './admin-standing.js';\nexport * from './age-derivation.js';\nexport * from './app-config.js';\nexport * from './guild-chat-access.js';\nexport * from './guild-invite-system-message.js';\nexport * from './hall-content.js';\nexport * from './password.js';\nexport * from './text-field.js';\nexport * from './public-documents.js';\nexport * from './pledge-totals.js';\nexport * from './pledge-refund-eligibility.js';\nexport * from './work-file-folder.js';\nexport * from './work-realm-eligibility.js';\nexport * from './work-realm-name.js';\nexport * from './display-name-reservation.js';\nexport * from './work-publish-readiness.js';\n"]}
|
package/package.json
CHANGED
package/dist/utils/format.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format a byte count as a human-readable string: "24 KB", "1.2 MB", "850 B".
|
|
3
|
-
* Returns null when bytes is undefined / non-finite / negative.
|
|
4
|
-
*/
|
|
5
|
-
export declare function formatFileSize(bytes: number | undefined): string | null;
|
|
6
|
-
//# sourceMappingURL=format.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAUvE"}
|
package/dist/utils/format.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Format a byte count as a human-readable string: "24 KB", "1.2 MB", "850 B".
|
|
3
|
-
* Returns null when bytes is undefined / non-finite / negative.
|
|
4
|
-
*/
|
|
5
|
-
export function formatFileSize(bytes) {
|
|
6
|
-
if (bytes === undefined || !Number.isFinite(bytes) || bytes < 0)
|
|
7
|
-
return null;
|
|
8
|
-
if (bytes < 1024)
|
|
9
|
-
return `${bytes} B`;
|
|
10
|
-
if (bytes < 1024 * 1024)
|
|
11
|
-
return `${Math.round(bytes / 1024)} KB`;
|
|
12
|
-
if (bytes < 1024 * 1024 * 1024) {
|
|
13
|
-
const mb = bytes / (1024 * 1024);
|
|
14
|
-
return `${mb < 10 ? mb.toFixed(1) : Math.round(mb)} MB`;
|
|
15
|
-
}
|
|
16
|
-
const gb = bytes / (1024 * 1024 * 1024);
|
|
17
|
-
return `${gb < 10 ? gb.toFixed(1) : Math.round(gb)} GB`;
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=format.js.map
|
package/dist/utils/format.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAyB;IACtD,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7E,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACjE,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACjC,OAAO,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;IAC1D,CAAC;IACD,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IACxC,OAAO,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC;AAC1D,CAAC","sourcesContent":["/**\n * Format a byte count as a human-readable string: \"24 KB\", \"1.2 MB\", \"850 B\".\n * Returns null when bytes is undefined / non-finite / negative.\n */\nexport function formatFileSize(bytes: number | undefined): string | null {\n if (bytes === undefined || !Number.isFinite(bytes) || bytes < 0) return null;\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;\n if (bytes < 1024 * 1024 * 1024) {\n const mb = bytes / (1024 * 1024);\n return `${mb < 10 ? mb.toFixed(1) : Math.round(mb)} MB`;\n }\n const gb = bytes / (1024 * 1024 * 1024);\n return `${gb < 10 ? gb.toFixed(1) : Math.round(gb)} GB`;\n}\n"]}
|