@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.
Files changed (47) hide show
  1. package/LICENSE.md +6 -0
  2. package/README.md +37 -0
  3. package/package.json +89 -0
  4. package/src/collaboration/artist.ts +63 -0
  5. package/src/collaboration/block-room-codec/ai-document-applicator.ts +319 -0
  6. package/src/collaboration/block-room-codec/ai-document-field-mutations.ts +557 -0
  7. package/src/collaboration/block-room-codec/ai-document-page-structure-mutations.ts +449 -0
  8. package/src/collaboration/block-room-codec/ai-document-values.ts +368 -0
  9. package/src/collaboration/block-room-codec/hydration.ts +257 -0
  10. package/src/collaboration/block-room-codec/internal.ts +432 -0
  11. package/src/collaboration/block-room-codec/locale-change-validation.ts +237 -0
  12. package/src/collaboration/block-room-codec/locale-presence.ts +827 -0
  13. package/src/collaboration/block-room-codec/materialization.ts +450 -0
  14. package/src/collaboration/block-room-codec/observation.ts +518 -0
  15. package/src/collaboration/block-room-codec/payload-mutations.ts +347 -0
  16. package/src/collaboration/block-room-codec/room-access.ts +154 -0
  17. package/src/collaboration/block-room-codec/structure-mutations.ts +456 -0
  18. package/src/collaboration/block-room-codec.ts +86 -0
  19. package/src/collaboration/campaign.ts +37 -0
  20. package/src/collaboration/document-layout.ts +75 -0
  21. package/src/collaboration/document.ts +185 -0
  22. package/src/collaboration/email-layout.ts +150 -0
  23. package/src/collaboration/form.ts +513 -0
  24. package/src/collaboration/label.ts +49 -0
  25. package/src/collaboration/map-theme.ts +157 -0
  26. package/src/collaboration/member-id.ts +9 -0
  27. package/src/collaboration/menu.ts +258 -0
  28. package/src/collaboration/metadata-ai.ts +99 -0
  29. package/src/collaboration/page.ts +483 -0
  30. package/src/collaboration/post-series.ts +96 -0
  31. package/src/collaboration/post.ts +59 -0
  32. package/src/collaboration/release.ts +221 -0
  33. package/src/collaboration/runtime-events.ts +547 -0
  34. package/src/collaboration/work.ts +107 -0
  35. package/src/editor/link-normalization.ts +212 -0
  36. package/src/editor/materialized-blocks.ts +58 -0
  37. package/src/index.ts +22 -0
  38. package/src/media/block-schemas.ts +78 -0
  39. package/src/media/hydration.ts +226 -0
  40. package/src/page/block-fixtures.ts +586 -0
  41. package/src/page/index.ts +3 -0
  42. package/src/page/types.ts +57 -0
  43. package/src/post/index.ts +1 -0
  44. package/src/post/types.ts +13 -0
  45. package/src/test/random-id.ts +9 -0
  46. package/src/translation/release.ts +88 -0
  47. package/src/types.ts +14 -0
@@ -0,0 +1,586 @@
1
+ import type { ExternalVideoAspectRatio } from "../media/block-schemas.ts";
2
+
3
+ export type PageBlockType =
4
+ | "rich-text"
5
+ | "post-list"
6
+ | "post-table"
7
+ | "post-map"
8
+ | "work-map"
9
+ | "work-table"
10
+ | "work-list"
11
+ | "program-event-list"
12
+ | "release-list"
13
+ | "artist-list"
14
+ | "label-list"
15
+ | "text-marquee"
16
+ | "client-marquee"
17
+ | "label-marquee"
18
+ | "author-list"
19
+ | "form"
20
+ | "immersive-scene"
21
+ | "map"
22
+ | "external-video"
23
+ | "columns";
24
+
25
+ export interface ExternalVideoProps {
26
+ url: string;
27
+ caption: string;
28
+ aspectRatio: ExternalVideoAspectRatio;
29
+ }
30
+
31
+ export interface PageBlockFixtureInlineContent {
32
+ type: string;
33
+ text?: string;
34
+ styles?: Record<string, unknown>;
35
+ }
36
+
37
+ export interface PageBlockFixtureBlock {
38
+ id: string;
39
+ type: string;
40
+ props: Record<string, unknown>;
41
+ content?: PageBlockFixtureInlineContent[];
42
+ children?: PageBlockFixtureBlock[];
43
+ }
44
+
45
+ export interface PageBlockFixtureSection {
46
+ id: string;
47
+ type: PageBlockType;
48
+ settings: {
49
+ backgroundColor?: string;
50
+ paddingTop?: string;
51
+ paddingBottom?: string;
52
+ paddingLeft?: string;
53
+ paddingRight?: string;
54
+ maxWidth?: "full" | "container" | "narrow";
55
+ };
56
+ props?: Record<string, unknown>;
57
+ content?: PageBlockFixtureBlock[];
58
+ columns?: Array<{
59
+ id: string;
60
+ sections: PageBlockFixtureSection[];
61
+ }>;
62
+ }
63
+
64
+ export const PAGE_BLOCK_TYPES = [
65
+ "rich-text",
66
+ "post-list",
67
+ "post-table",
68
+ "post-map",
69
+ "work-map",
70
+ "work-table",
71
+ "author-list",
72
+ "work-list",
73
+ "program-event-list",
74
+ "release-list",
75
+ "artist-list",
76
+ "label-list",
77
+ "text-marquee",
78
+ "client-marquee",
79
+ "label-marquee",
80
+ "form",
81
+ "immersive-scene",
82
+ "map",
83
+ "external-video",
84
+ "columns",
85
+ ] as const satisfies readonly PageBlockType[];
86
+
87
+ function createParagraphBlock(id: string, text: string): PageBlockFixtureBlock {
88
+ return {
89
+ id,
90
+ type: "paragraph",
91
+ props: {},
92
+ content: [{ type: "text", text, styles: {} }],
93
+ children: [],
94
+ };
95
+ }
96
+
97
+ export const PAGE_BLOCK_FIXTURE_SECTIONS: PageBlockFixtureSection[] = [
98
+ {
99
+ id: "fixture-section-rich-text",
100
+ type: "rich-text",
101
+ settings: {},
102
+ props: {},
103
+ content: [
104
+ createParagraphBlock(
105
+ "fixture-rich-text-paragraph",
106
+ "Fixture rich text block",
107
+ ),
108
+ {
109
+ id: "fixture-rich-text-audio",
110
+ type: "file",
111
+ props: {
112
+ fileId: "fixture-audio-file",
113
+ name: "fixture-audio.wav",
114
+ caption: "Fixture audio caption",
115
+ previewWidth: "100",
116
+ textAlignment: "left",
117
+ },
118
+ children: [],
119
+ },
120
+ {
121
+ id: "fixture-rich-text-video",
122
+ type: "file",
123
+ props: {
124
+ fileId: "fixture-video-file",
125
+ name: "fixture-video.mp4",
126
+ caption: "Fixture video caption",
127
+ previewWidth: "100",
128
+ textAlignment: "left",
129
+ },
130
+ children: [],
131
+ },
132
+ {
133
+ id: "fixture-rich-text-attachment",
134
+ type: "file",
135
+ props: {
136
+ fileId: "fixture-attachment-file",
137
+ name: "fixture-score.pdf",
138
+ caption: "Fixture attachment caption",
139
+ previewWidth: "100",
140
+ textAlignment: "left",
141
+ },
142
+ children: [],
143
+ },
144
+ {
145
+ id: "fixture-rich-text-file",
146
+ type: "file",
147
+ props: {
148
+ fileId: "fixture-file",
149
+ name: "fixture-archive.zip",
150
+ caption: "Fixture file caption",
151
+ previewWidth: "100",
152
+ textAlignment: "left",
153
+ },
154
+ children: [],
155
+ },
156
+ ],
157
+ },
158
+ {
159
+ id: "fixture-section-post-list",
160
+ type: "post-list",
161
+ settings: {},
162
+ props: {
163
+ layout: "grid",
164
+ columns: "2",
165
+ limit: "4",
166
+ showFeaturedImage: "true",
167
+ showMeta: "true",
168
+ imageAspectRatio: "16:9",
169
+ },
170
+ },
171
+ {
172
+ id: "fixture-section-post-table",
173
+ type: "post-table",
174
+ settings: {},
175
+ props: {
176
+ categoryIds: "",
177
+ tagIds: "",
178
+ authorIds: "",
179
+ seriesId: "",
180
+ pageSize: "5",
181
+ },
182
+ },
183
+ {
184
+ id: "fixture-section-post-map",
185
+ type: "post-map",
186
+ settings: {},
187
+ props: {
188
+ seriesId: "00000000-0000-0000-0000-000000000000",
189
+ requirePlace: "true",
190
+ sortBy: "published_at",
191
+ sortOrder: "desc",
192
+ aspectRatio: "4:3",
193
+ previewWidth: "100",
194
+ primaryLabel: "content_title",
195
+ preferredScheme: "auto",
196
+ areaLabelsMode: "inherit",
197
+ poiLabelsMode: "inherit",
198
+ },
199
+ },
200
+ {
201
+ id: "fixture-section-work-map",
202
+ type: "work-map",
203
+ settings: {},
204
+ props: {
205
+ workTypes: "music_project,portfolio",
206
+ featuredOnly: "false",
207
+ sortBy: "published_at",
208
+ sortOrder: "desc",
209
+ aspectRatio: "4:3",
210
+ previewWidth: "100",
211
+ primaryLabel: "content_title",
212
+ preferredScheme: "auto",
213
+ areaLabelsMode: "inherit",
214
+ poiLabelsMode: "inherit",
215
+ },
216
+ },
217
+ {
218
+ id: "fixture-section-work-table",
219
+ type: "work-table",
220
+ settings: {},
221
+ props: {
222
+ workTypes: "music_project,portfolio",
223
+ featuredOnly: "false",
224
+ pageSize: "5",
225
+ },
226
+ },
227
+ {
228
+ id: "fixture-section-author-list",
229
+ type: "author-list",
230
+ settings: {},
231
+ props: {
232
+ layout: "grid",
233
+ columns: "2",
234
+ limit: "4",
235
+ showBio: "true",
236
+ showAvatar: "true",
237
+ },
238
+ },
239
+ {
240
+ id: "fixture-section-work-list",
241
+ type: "work-list",
242
+ settings: {},
243
+ props: {
244
+ layout: "grid",
245
+ columns: "2",
246
+ limit: "4",
247
+ workTypes: "music_project,portfolio",
248
+ sortBy: "published_at",
249
+ sortOrder: "desc",
250
+ showPagination: "false",
251
+ showImage: "true",
252
+ showMeta: "true",
253
+ imageAspectRatio: "16:9",
254
+ carouselLoop: "true",
255
+ carouselIndicators: "true",
256
+ },
257
+ },
258
+ {
259
+ id: "fixture-section-program-event-list",
260
+ type: "program-event-list",
261
+ settings: {},
262
+ props: {
263
+ layout: "grid",
264
+ columns: "2",
265
+ limit: "4",
266
+ typeIds: "",
267
+ seriesId: "",
268
+ timeWindow: "all",
269
+ sortBy: "starts_at",
270
+ sortOrder: "asc",
271
+ showPagination: "false",
272
+ showImage: "true",
273
+ showMeta: "true",
274
+ imageAspectRatio: "16:9",
275
+ carouselLoop: "true",
276
+ carouselIndicators: "true",
277
+ },
278
+ },
279
+ {
280
+ id: "fixture-section-release-list",
281
+ type: "release-list",
282
+ settings: {},
283
+ props: {
284
+ layout: "grid",
285
+ columns: "2",
286
+ limit: "4",
287
+ types: "album,single",
288
+ categoryIds: "",
289
+ sortBy: "release_date",
290
+ sortOrder: "desc",
291
+ showPagination: "false",
292
+ showImage: "true",
293
+ showMeta: "true",
294
+ imageAspectRatio: "1:1",
295
+ carouselLoop: "true",
296
+ carouselIndicators: "true",
297
+ },
298
+ },
299
+ {
300
+ id: "fixture-section-artist-list",
301
+ type: "artist-list",
302
+ settings: {},
303
+ props: {
304
+ layout: "grid",
305
+ sortBy: "name",
306
+ sortOrder: "asc",
307
+ columns: "2",
308
+ limit: "4",
309
+ showPagination: "false",
310
+ showImage: "true",
311
+ showMeta: "true",
312
+ imageAspectRatio: "1:1",
313
+ },
314
+ },
315
+ {
316
+ id: "fixture-section-label-list",
317
+ type: "label-list",
318
+ settings: {},
319
+ props: {
320
+ layout: "grid",
321
+ sortBy: "name",
322
+ sortOrder: "asc",
323
+ columns: "2",
324
+ limit: "4",
325
+ showPagination: "false",
326
+ showImage: "true",
327
+ showMeta: "true",
328
+ imageAspectRatio: "1:1",
329
+ carouselLoop: "true",
330
+ carouselIndicators: "true",
331
+ },
332
+ },
333
+ {
334
+ id: "fixture-section-text-marquee",
335
+ type: "text-marquee",
336
+ settings: {},
337
+ props: {
338
+ itemsJson: JSON.stringify([
339
+ { text: "Fixture announcement", href: "https://example.com" },
340
+ { text: "Fixture item" },
341
+ ]),
342
+ direction: "left",
343
+ speed: "normal",
344
+ speedPxPerSecond: "12",
345
+ itemHeight: "md",
346
+ itemHeightPx: "28",
347
+ gap: "lg",
348
+ pauseOnHover: "true",
349
+ linkTarget: "same-tab",
350
+ },
351
+ },
352
+ {
353
+ id: "fixture-section-client-marquee",
354
+ type: "client-marquee",
355
+ settings: {},
356
+ props: {
357
+ source: "all",
358
+ ids: "",
359
+ linkMode: "entity",
360
+ logoScale: "contain",
361
+ fallbackMode: "name",
362
+ limit: "12",
363
+ direction: "left",
364
+ speed: "normal",
365
+ speedPxPerSecond: "12",
366
+ itemHeight: "md",
367
+ itemHeightPx: "28",
368
+ gap: "lg",
369
+ pauseOnHover: "true",
370
+ linkTarget: "same-tab",
371
+ },
372
+ },
373
+ {
374
+ id: "fixture-section-label-marquee",
375
+ type: "label-marquee",
376
+ settings: {},
377
+ props: {
378
+ source: "all",
379
+ ids: "",
380
+ linkMode: "entity",
381
+ logoScale: "contain",
382
+ fallbackMode: "name",
383
+ limit: "12",
384
+ direction: "left",
385
+ speed: "normal",
386
+ speedPxPerSecond: "12",
387
+ itemHeight: "md",
388
+ itemHeightPx: "28",
389
+ gap: "lg",
390
+ pauseOnHover: "true",
391
+ linkTarget: "same-tab",
392
+ },
393
+ },
394
+ {
395
+ id: "fixture-section-form",
396
+ type: "form",
397
+ settings: {},
398
+ props: {
399
+ formId: "",
400
+ showTitle: "true",
401
+ },
402
+ },
403
+ {
404
+ id: "fixture-section-immersive-scene",
405
+ type: "immersive-scene",
406
+ settings: {},
407
+ props: {
408
+ playback: "scroll",
409
+ loop: "false",
410
+ transition: "smooth",
411
+ transitionWindow: "0.22",
412
+ textureSize: "64",
413
+ heightVh: "300",
414
+ minHeightPx: "720",
415
+ unitHoldSeconds: "3",
416
+ unitGapSeconds: "1",
417
+ particleSize: "1",
418
+ backgroundColor: "#070a0d",
419
+ unitsJson:
420
+ '[{"id":"fixture-intro","mesh":"sphere","color":"#d8dde5"},{"id":"fixture-focus","mesh":"torus","color":"#f97316"}]',
421
+ copyJson:
422
+ '[{"id":"fixture-intro","title":"Fixture intro","text":"Fixture intro copy."},{"id":"fixture-focus","title":"Fixture focus","text":"Fixture focus copy."}]',
423
+ },
424
+ },
425
+ {
426
+ id: "fixture-section-map",
427
+ type: "map",
428
+ settings: {},
429
+ props: {
430
+ mapPlaceIds: "",
431
+ mapPlaceId: "",
432
+ location: "",
433
+ aspectRatio: "16:9",
434
+ previewWidth: "100",
435
+ zoom: "15",
436
+ url: "map",
437
+ showPreview: "true",
438
+ draggable: "true",
439
+ zoomable: "true",
440
+ rotatable: "false",
441
+ tiltable: "false",
442
+ pinClickable: "true",
443
+ centerLat: "",
444
+ centerLng: "",
445
+ pitch: "0",
446
+ bearing: "0",
447
+ show3DBuildings: "false",
448
+ autoRotate: "false",
449
+ autoRotateSpeed: "1",
450
+ showDirections: "true",
451
+ variant: "default",
452
+ themeId: "",
453
+ preferredScheme: "auto",
454
+ areaLabelsMode: "inherit",
455
+ poiLabelsMode: "inherit",
456
+ caption: "",
457
+ },
458
+ },
459
+ {
460
+ id: "fixture-section-external-video",
461
+ type: "external-video",
462
+ settings: {},
463
+ props: {
464
+ url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
465
+ caption: "Fixture external video",
466
+ aspectRatio: "auto",
467
+ } satisfies ExternalVideoProps,
468
+ },
469
+ {
470
+ id: "fixture-section-columns",
471
+ type: "columns",
472
+ settings: {},
473
+ props: {
474
+ columns: "2",
475
+ gap: "24",
476
+ columnRatios: "1:1",
477
+ mobileStack: "true",
478
+ },
479
+ columns: [
480
+ {
481
+ id: "fixture-column-1",
482
+ sections: [
483
+ {
484
+ id: "fixture-column-rich-text",
485
+ type: "rich-text",
486
+ settings: {},
487
+ props: {},
488
+ content: [
489
+ createParagraphBlock(
490
+ "fixture-column-rich-text-paragraph",
491
+ "Fixture nested rich text block",
492
+ ),
493
+ {
494
+ id: "fixture-column-rich-text-audio",
495
+ type: "file",
496
+ props: {
497
+ fileId: "fixture-nested-audio-file",
498
+ name: "fixture-nested-audio.wav",
499
+ caption: "Fixture nested audio caption",
500
+ previewWidth: "100",
501
+ textAlignment: "left",
502
+ },
503
+ children: [],
504
+ },
505
+ {
506
+ id: "fixture-column-rich-text-video",
507
+ type: "file",
508
+ props: {
509
+ fileId: "fixture-nested-video-file",
510
+ name: "fixture-nested-video.mp4",
511
+ caption: "Fixture nested video caption",
512
+ previewWidth: "100",
513
+ textAlignment: "left",
514
+ },
515
+ children: [],
516
+ },
517
+ {
518
+ id: "fixture-column-rich-text-attachment",
519
+ type: "file",
520
+ props: {
521
+ fileId: "fixture-nested-attachment-file",
522
+ name: "fixture-nested-score.pdf",
523
+ caption: "Fixture nested attachment caption",
524
+ previewWidth: "100",
525
+ textAlignment: "left",
526
+ },
527
+ children: [],
528
+ },
529
+ {
530
+ id: "fixture-column-rich-text-file",
531
+ type: "file",
532
+ props: {
533
+ fileId: "fixture-nested-file",
534
+ name: "fixture-nested-archive.zip",
535
+ caption: "Fixture nested file caption",
536
+ previewWidth: "100",
537
+ textAlignment: "left",
538
+ },
539
+ children: [],
540
+ },
541
+ ],
542
+ },
543
+ ],
544
+ },
545
+ {
546
+ id: "fixture-column-2",
547
+ sections: [
548
+ {
549
+ id: "fixture-column-external-video",
550
+ type: "external-video",
551
+ settings: {},
552
+ props: {
553
+ url: "https://vimeo.com/76979871",
554
+ caption: "Fixture nested external video",
555
+ aspectRatio: "16:9",
556
+ } satisfies ExternalVideoProps,
557
+ },
558
+ ],
559
+ },
560
+ ],
561
+ },
562
+ ];
563
+
564
+ export function createPageBlockFixtureSections(): PageBlockFixtureSection[] {
565
+ return structuredClone(PAGE_BLOCK_FIXTURE_SECTIONS);
566
+ }
567
+
568
+ export function collectPageBlockTypes(
569
+ sections: ReadonlyArray<PageBlockFixtureSection>,
570
+ ): PageBlockType[] {
571
+ const types: PageBlockType[] = [];
572
+
573
+ const visit = (items: ReadonlyArray<PageBlockFixtureSection>) => {
574
+ for (const section of items) {
575
+ types.push(section.type);
576
+ if (section.columns) {
577
+ for (const column of section.columns) {
578
+ visit(column.sections);
579
+ }
580
+ }
581
+ }
582
+ };
583
+
584
+ visit(sections);
585
+ return types;
586
+ }
@@ -0,0 +1,3 @@
1
+ export * from "../collaboration/document-layout.ts";
2
+ export * from "./block-fixtures.ts";
3
+ export * from "./types.ts";
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import type { PageBlockType } from "./block-fixtures.ts";
3
+
4
+ export interface InlineContent {
5
+ type: string;
6
+ text?: string;
7
+ href?: string;
8
+ styles?: Record<string, unknown>;
9
+ props?: Record<string, unknown>;
10
+ content?: InlineContent[];
11
+ }
12
+
13
+ export interface Block {
14
+ id: string;
15
+ type: string;
16
+ props: Record<string, unknown>;
17
+ content?: InlineContent[];
18
+ children?: Block[];
19
+ }
20
+
21
+ export interface SectionSettings {
22
+ backgroundColor?: string;
23
+ paddingTop?: string;
24
+ paddingBottom?: string;
25
+ paddingLeft?: string;
26
+ paddingRight?: string;
27
+ maxWidth?: "full" | "container" | "narrow";
28
+ }
29
+
30
+ export interface Section {
31
+ id: string;
32
+ type: PageBlockType;
33
+ settings: SectionSettings;
34
+ props?: Record<string, unknown>;
35
+ content?: Block[];
36
+ columns?: ColumnData[];
37
+ }
38
+
39
+ export interface ColumnData {
40
+ id: string;
41
+ sections: Section[];
42
+ }
43
+
44
+ export interface PageContent {
45
+ sections: Section[];
46
+ }
47
+
48
+ const pageContentSectionSchema = z.custom<Section>(
49
+ (value) =>
50
+ value !== null && typeof value === "object" && !Array.isArray(value),
51
+ );
52
+
53
+ export const pageContentSchema: z.ZodType<PageContent> = z
54
+ .object({
55
+ sections: z.array(pageContentSectionSchema),
56
+ })
57
+ .strict();
@@ -0,0 +1 @@
1
+ export * from "./types.ts";
@@ -0,0 +1,13 @@
1
+ import { z } from "zod";
2
+ import type { Block } from "../page/types.ts";
3
+
4
+ export type PostContent = Block[];
5
+
6
+ const postContentBlockSchema = z.custom<Block>(
7
+ (value) =>
8
+ value !== null && typeof value === "object" && !Array.isArray(value),
9
+ );
10
+
11
+ export const postContentSchema: z.ZodType<PostContent> = z.array(
12
+ postContentBlockSchema,
13
+ );
@@ -0,0 +1,9 @@
1
+ import { randomUUID } from "node:crypto";
2
+
3
+ export function randomTestUuid(): string {
4
+ return randomUUID();
5
+ }
6
+
7
+ export function randomTestId(prefix: string): string {
8
+ return `${prefix}-${randomUUID()}`;
9
+ }