@echovisionlab/geul-common 0.1.0
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/LICENSE.md +6 -0
- package/README.md +37 -0
- package/package.json +89 -0
- package/src/collaboration/artist.ts +63 -0
- package/src/collaboration/block-room-codec/ai-document-applicator.ts +319 -0
- package/src/collaboration/block-room-codec/ai-document-field-mutations.ts +557 -0
- package/src/collaboration/block-room-codec/ai-document-page-structure-mutations.ts +449 -0
- package/src/collaboration/block-room-codec/ai-document-values.ts +368 -0
- package/src/collaboration/block-room-codec/hydration.ts +257 -0
- package/src/collaboration/block-room-codec/internal.ts +432 -0
- package/src/collaboration/block-room-codec/locale-change-validation.ts +237 -0
- package/src/collaboration/block-room-codec/locale-presence.ts +827 -0
- package/src/collaboration/block-room-codec/materialization.ts +450 -0
- package/src/collaboration/block-room-codec/observation.ts +518 -0
- package/src/collaboration/block-room-codec/payload-mutations.ts +347 -0
- package/src/collaboration/block-room-codec/room-access.ts +154 -0
- package/src/collaboration/block-room-codec/structure-mutations.ts +456 -0
- package/src/collaboration/block-room-codec.ts +86 -0
- package/src/collaboration/campaign.ts +37 -0
- package/src/collaboration/document-layout.ts +75 -0
- package/src/collaboration/document.ts +185 -0
- package/src/collaboration/email-layout.ts +150 -0
- package/src/collaboration/form.ts +513 -0
- package/src/collaboration/label.ts +49 -0
- package/src/collaboration/map-theme.ts +157 -0
- package/src/collaboration/member-id.ts +9 -0
- package/src/collaboration/menu.ts +258 -0
- package/src/collaboration/metadata-ai.ts +99 -0
- package/src/collaboration/page.ts +483 -0
- package/src/collaboration/post-series.ts +96 -0
- package/src/collaboration/post.ts +59 -0
- package/src/collaboration/release.ts +221 -0
- package/src/collaboration/runtime-events.ts +547 -0
- package/src/collaboration/work.ts +107 -0
- package/src/editor/link-normalization.ts +212 -0
- package/src/editor/materialized-blocks.ts +58 -0
- package/src/index.ts +22 -0
- package/src/media/block-schemas.ts +78 -0
- package/src/media/hydration.ts +226 -0
- package/src/page/block-fixtures.ts +586 -0
- package/src/page/index.ts +3 -0
- package/src/page/types.ts +57 -0
- package/src/post/index.ts +1 -0
- package/src/post/types.ts +13 -0
- package/src/test/random-id.ts +9 -0
- package/src/translation/release.ts +88 -0
- package/src/types.ts +14 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { memberIdSchema } from "./member-id.ts";
|
|
3
|
+
|
|
4
|
+
export const releaseTypeSchema = z.enum([
|
|
5
|
+
"album",
|
|
6
|
+
"compilation",
|
|
7
|
+
"ep",
|
|
8
|
+
"single",
|
|
9
|
+
]);
|
|
10
|
+
export const creditTargetTypeSchema = z.enum(["artist", "member", "text"]);
|
|
11
|
+
|
|
12
|
+
const creditItemSchema = z.object({
|
|
13
|
+
id: z.string().uuid(),
|
|
14
|
+
credit_type: creditTargetTypeSchema,
|
|
15
|
+
artist_id: z.string().uuid().nullable(),
|
|
16
|
+
artist_name: z.string().nullable(),
|
|
17
|
+
artist_slug: z.string().nullable(),
|
|
18
|
+
member_id: memberIdSchema.nullable(),
|
|
19
|
+
member_name: z.string().nullable(),
|
|
20
|
+
credited_name: z.string().nullable(),
|
|
21
|
+
credit_role: z.string().nullable(),
|
|
22
|
+
sort_order: z.number(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function requireMemberCreditId(
|
|
26
|
+
credit: z.infer<typeof creditItemSchema>,
|
|
27
|
+
): boolean {
|
|
28
|
+
return credit.credit_type !== "member" || credit.member_id !== null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const memberCreditRefinement = {
|
|
32
|
+
message: "Member credit requires member_id",
|
|
33
|
+
path: ["member_id"] as PropertyKey[],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const releaseCreditItemSchema = creditItemSchema
|
|
37
|
+
.strict()
|
|
38
|
+
.refine(requireMemberCreditId, memberCreditRefinement);
|
|
39
|
+
|
|
40
|
+
export const releaseArtistItemSchema = z
|
|
41
|
+
.object({
|
|
42
|
+
artist_id: z.string().uuid(),
|
|
43
|
+
artist_name: z.string(),
|
|
44
|
+
artist_slug: z.string().nullable(),
|
|
45
|
+
sort_order: z.number(),
|
|
46
|
+
})
|
|
47
|
+
.strict();
|
|
48
|
+
|
|
49
|
+
export const releaseLabelItemSchema = z
|
|
50
|
+
.object({
|
|
51
|
+
label_id: z.string().uuid(),
|
|
52
|
+
label_name: z.string(),
|
|
53
|
+
label_slug: z.string().nullable(),
|
|
54
|
+
catalog_number: z.string().nullable(),
|
|
55
|
+
sort_order: z.number(),
|
|
56
|
+
})
|
|
57
|
+
.strict();
|
|
58
|
+
|
|
59
|
+
export const releaseGenreItemSchema = z
|
|
60
|
+
.object({
|
|
61
|
+
id: z.string().uuid(),
|
|
62
|
+
name: z.string(),
|
|
63
|
+
slug: z.string(),
|
|
64
|
+
})
|
|
65
|
+
.strict();
|
|
66
|
+
|
|
67
|
+
export const releaseCategoryItemSchema = z
|
|
68
|
+
.object({
|
|
69
|
+
id: z.string().uuid(),
|
|
70
|
+
name: z.string(),
|
|
71
|
+
slug: z.string(),
|
|
72
|
+
})
|
|
73
|
+
.strict();
|
|
74
|
+
|
|
75
|
+
export const releaseStyleItemSchema = z
|
|
76
|
+
.object({
|
|
77
|
+
id: z.string().uuid(),
|
|
78
|
+
name: z.string(),
|
|
79
|
+
slug: z.string(),
|
|
80
|
+
})
|
|
81
|
+
.strict();
|
|
82
|
+
|
|
83
|
+
export const releaseFormatItemSchema = z
|
|
84
|
+
.object({
|
|
85
|
+
id: z.string().uuid(),
|
|
86
|
+
name: z.string(),
|
|
87
|
+
slug: z.string(),
|
|
88
|
+
format_description: z.string().nullable(),
|
|
89
|
+
})
|
|
90
|
+
.strict();
|
|
91
|
+
|
|
92
|
+
export const trackCreditItemSchema = creditItemSchema
|
|
93
|
+
.strict()
|
|
94
|
+
.refine(requireMemberCreditId, memberCreditRefinement);
|
|
95
|
+
|
|
96
|
+
export const releaseTrackItemSchema = z
|
|
97
|
+
.object({
|
|
98
|
+
id: z.string().uuid(),
|
|
99
|
+
track_number: z.number(),
|
|
100
|
+
title: z.string(),
|
|
101
|
+
audio_original_file_id: z.string().uuid().nullable().optional(),
|
|
102
|
+
credits: z.array(trackCreditItemSchema),
|
|
103
|
+
})
|
|
104
|
+
.strict();
|
|
105
|
+
|
|
106
|
+
export const releaseCollabFieldsSchema = z
|
|
107
|
+
.object({
|
|
108
|
+
title: z.string().optional(),
|
|
109
|
+
type: releaseTypeSchema.optional(),
|
|
110
|
+
releaseDate: z.string().nullable().optional(),
|
|
111
|
+
spotifyUrl: z.string().optional(),
|
|
112
|
+
appleMusicUrl: z.string().optional(),
|
|
113
|
+
bandcampUrl: z.string().optional(),
|
|
114
|
+
youtubeMusicUrl: z.string().optional(),
|
|
115
|
+
artists: z.array(releaseArtistItemSchema).optional(),
|
|
116
|
+
credits: z.array(releaseCreditItemSchema).optional(),
|
|
117
|
+
labels: z.array(releaseLabelItemSchema).optional(),
|
|
118
|
+
categories: z.array(releaseCategoryItemSchema).optional(),
|
|
119
|
+
genres: z.array(releaseGenreItemSchema).optional(),
|
|
120
|
+
styles: z.array(releaseStyleItemSchema).optional(),
|
|
121
|
+
formats: z.array(releaseFormatItemSchema).optional(),
|
|
122
|
+
tracks: z.array(releaseTrackItemSchema).optional(),
|
|
123
|
+
})
|
|
124
|
+
.strict();
|
|
125
|
+
|
|
126
|
+
export const RELEASE_JSON_KEYS: ReadonlySet<
|
|
127
|
+
keyof z.infer<typeof releaseCollabFieldsSchema>
|
|
128
|
+
> = new Set([
|
|
129
|
+
"artists",
|
|
130
|
+
"credits",
|
|
131
|
+
"labels",
|
|
132
|
+
"categories",
|
|
133
|
+
"genres",
|
|
134
|
+
"styles",
|
|
135
|
+
"formats",
|
|
136
|
+
"tracks",
|
|
137
|
+
]);
|
|
138
|
+
|
|
139
|
+
export const RELEASE_SOURCE_OWNED_FIELD_KEYS = ["title"] as const;
|
|
140
|
+
export const RELEASE_SHARED_FIELD_KEYS = [
|
|
141
|
+
"type",
|
|
142
|
+
"releaseDate",
|
|
143
|
+
"spotifyUrl",
|
|
144
|
+
"appleMusicUrl",
|
|
145
|
+
"bandcampUrl",
|
|
146
|
+
"youtubeMusicUrl",
|
|
147
|
+
"artists",
|
|
148
|
+
"credits",
|
|
149
|
+
"labels",
|
|
150
|
+
"categories",
|
|
151
|
+
"genres",
|
|
152
|
+
"styles",
|
|
153
|
+
"formats",
|
|
154
|
+
"tracks",
|
|
155
|
+
] as const;
|
|
156
|
+
|
|
157
|
+
export type ReleaseType = z.infer<typeof releaseTypeSchema>;
|
|
158
|
+
export type CreditTargetType = z.infer<typeof creditTargetTypeSchema>;
|
|
159
|
+
export type ReleaseCreditItem = z.infer<typeof releaseCreditItemSchema>;
|
|
160
|
+
export type ReleaseArtistItem = z.infer<typeof releaseArtistItemSchema>;
|
|
161
|
+
export type ReleaseLabelItem = z.infer<typeof releaseLabelItemSchema>;
|
|
162
|
+
export type ReleaseCategoryItem = z.infer<typeof releaseCategoryItemSchema>;
|
|
163
|
+
export type ReleaseGenreItem = z.infer<typeof releaseGenreItemSchema>;
|
|
164
|
+
export type ReleaseStyleItem = z.infer<typeof releaseStyleItemSchema>;
|
|
165
|
+
export type ReleaseFormatItem = z.infer<typeof releaseFormatItemSchema>;
|
|
166
|
+
export type TrackCreditItem = z.infer<typeof trackCreditItemSchema>;
|
|
167
|
+
export type ReleaseTrackItem = z.infer<typeof releaseTrackItemSchema>;
|
|
168
|
+
export type ReleaseCollabFields = z.infer<typeof releaseCollabFieldsSchema>;
|
|
169
|
+
export type ReleaseFieldValue =
|
|
170
|
+
string | number | boolean | Record<string, unknown>[] | null;
|
|
171
|
+
export type ReleaseSourceOwnedFieldKey =
|
|
172
|
+
(typeof RELEASE_SOURCE_OWNED_FIELD_KEYS)[number];
|
|
173
|
+
export type ReleaseSharedFieldKey = (typeof RELEASE_SHARED_FIELD_KEYS)[number];
|
|
174
|
+
|
|
175
|
+
export function extractReleaseFields(fieldsMap: {
|
|
176
|
+
get(key: string): ReleaseFieldValue | undefined;
|
|
177
|
+
}): ReleaseCollabFields {
|
|
178
|
+
const raw: Record<string, unknown> = {};
|
|
179
|
+
|
|
180
|
+
for (const key of Object.keys(releaseCollabFieldsSchema.shape)) {
|
|
181
|
+
let value = fieldsMap.get(key);
|
|
182
|
+
|
|
183
|
+
if (
|
|
184
|
+
RELEASE_JSON_KEYS.has(key as keyof ReleaseCollabFields) &&
|
|
185
|
+
typeof value === "string"
|
|
186
|
+
) {
|
|
187
|
+
try {
|
|
188
|
+
value = JSON.parse(value) as ReleaseFieldValue;
|
|
189
|
+
} catch {
|
|
190
|
+
throw new Error(`Failed to parse JSON for release field "${key}"`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (value !== undefined) {
|
|
195
|
+
raw[key] = value;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return releaseCollabFieldsSchema.parse(raw);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function pickReleaseSharedFields(
|
|
203
|
+
fields: ReleaseCollabFields,
|
|
204
|
+
): Pick<ReleaseCollabFields, ReleaseSharedFieldKey> {
|
|
205
|
+
return {
|
|
206
|
+
type: fields.type,
|
|
207
|
+
releaseDate: fields.releaseDate,
|
|
208
|
+
spotifyUrl: fields.spotifyUrl,
|
|
209
|
+
appleMusicUrl: fields.appleMusicUrl,
|
|
210
|
+
bandcampUrl: fields.bandcampUrl,
|
|
211
|
+
youtubeMusicUrl: fields.youtubeMusicUrl,
|
|
212
|
+
artists: fields.artists,
|
|
213
|
+
credits: fields.credits,
|
|
214
|
+
labels: fields.labels,
|
|
215
|
+
categories: fields.categories,
|
|
216
|
+
genres: fields.genres,
|
|
217
|
+
styles: fields.styles,
|
|
218
|
+
formats: fields.formats,
|
|
219
|
+
tracks: fields.tracks,
|
|
220
|
+
};
|
|
221
|
+
}
|