@eightyfourthousand/data-access 2026.3.0 → 2026.4.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.
@@ -1,122 +0,0 @@
1
- import {
2
- ANNOTATIONS_TO_IGNORE,
3
- DataClient,
4
- Passage,
5
- PassageDTO,
6
- annotationsFromDTO,
7
- passageFromDTO,
8
- passagesToDTO,
9
- passagesToRowDTO,
10
- } from './types';
11
-
12
- export const getPassage = async ({
13
- client,
14
- uuid,
15
- }: {
16
- client: DataClient;
17
- uuid: string;
18
- }) => {
19
- const { data } = await client
20
- .rpc('get_passage_with_annotations', {
21
- uuid_input: uuid,
22
- })
23
- .single();
24
-
25
- if (!data) {
26
- console.warn(`No passage found for uuid: ${uuid}`);
27
- return undefined;
28
- }
29
-
30
- const dto = data as PassageDTO;
31
- return passageFromDTO(
32
- dto,
33
- annotationsFromDTO(dto?.annotations || [], dto?.content.length || 0),
34
- );
35
- };
36
-
37
- export const getPassageUuidByXmlId = async ({
38
- client,
39
- xmlId,
40
- }: {
41
- client: DataClient;
42
- xmlId: string;
43
- }) => {
44
- const { data, error } = await client
45
- .from('passages')
46
- .select('uuid, workUuid:work_uuid')
47
- .eq('xmlId', xmlId)
48
- .single();
49
-
50
- if (error) {
51
- console.error(`Error fetching passage uuid for xmlId: ${xmlId}`, error);
52
- return;
53
- }
54
-
55
- return data?.uuid;
56
- };
57
-
58
- export const savePassages = async ({
59
- client,
60
- passages,
61
- }: {
62
- client: DataClient;
63
- passages: Passage[];
64
- }) => {
65
- /**
66
- * 1. Extract all annotations from savePassages
67
- * 2. Query the database for all current annotations for the savePassages
68
- * 3. Determine which annotations need to be deleted or upserted
69
- * 4. Upsert the passages
70
- * 5. Upsert the annotations
71
- * 6. Delete the annotations that are no longer present
72
- */
73
- const dtos = passagesToDTO(passages);
74
- const passageRowDtos = passagesToRowDTO(passages);
75
- const passageUuids = passages.map((p) => p.uuid);
76
- const annotations = dtos.flatMap((p) => p.annotations || []);
77
-
78
- const { data: existingAnnotations } = await client
79
- .from('passage_annotations')
80
- .select(`uuid`)
81
- .in('passage_uuid', passageUuids)
82
- .not('type', 'in', `(${ANNOTATIONS_TO_IGNORE.join(',')})`);
83
-
84
- const annotationsToDelete = existingAnnotations?.filter(
85
- (ea) => !annotations.find((a) => a.uuid === ea.uuid),
86
- );
87
-
88
- const { error: passageError } = await client
89
- .from('passages')
90
- .upsert(passageRowDtos, { onConflict: 'uuid' });
91
-
92
- if (passageError) {
93
- console.error('Error saving passages:', passageError);
94
- return;
95
- }
96
-
97
- if (annotations.length > 0) {
98
- const { error: annotationError } = await client
99
- .from('passage_annotations')
100
- .upsert(annotations, { onConflict: 'uuid' });
101
-
102
- if (annotationError) {
103
- console.error('Error saving annotations:', annotationError);
104
- throw annotationError;
105
- }
106
- }
107
-
108
- if (annotationsToDelete && annotationsToDelete.length > 0) {
109
- const { error: deleteError } = await client
110
- .from('passage_annotations')
111
- .delete()
112
- .in(
113
- 'uuid',
114
- annotationsToDelete.map((a) => a.uuid),
115
- );
116
-
117
- if (deleteError) {
118
- console.error('Error deleting annotations:', deleteError);
119
- throw deleteError;
120
- }
121
- }
122
- };
@@ -1,107 +0,0 @@
1
- import {
2
- DataClient,
3
- ProjectContributor,
4
- ProjectContributorsDTO,
5
- projectContributorsFromDTO,
6
- } from './types';
7
- import {
8
- Project,
9
- ProjectAsset,
10
- ProjectStageDetail,
11
- ProjectStageDetailsDTO,
12
- ProjectTableDTO,
13
- ProjectViewDTO,
14
- projectFromTableDTO,
15
- projectFromViewDTO,
16
- projectStageDetailsFromDTO,
17
- } from './types/project';
18
-
19
- export const getProjects = async ({ client }: { client: DataClient }) => {
20
- const { data } = await client.rpc('get_projects');
21
-
22
- const dtos = (data as ProjectViewDTO[]) || [];
23
- const projects = dtos.map(projectFromViewDTO);
24
-
25
- return { projects };
26
- };
27
-
28
- export const getProjectByUuid = async ({
29
- client,
30
- uuid,
31
- }: {
32
- client: DataClient;
33
- uuid: string;
34
- }): Promise<Project> => {
35
- const { data } = await client.rpc('get_project', { uuid_input: uuid });
36
-
37
- return projectFromTableDTO(data as ProjectTableDTO);
38
- };
39
-
40
- export const getProjectStages = async ({
41
- client,
42
- uuid,
43
- }: {
44
- client: DataClient;
45
- uuid: string;
46
- }): Promise<ProjectStageDetail[]> => {
47
- const { data } = await client.rpc('get_project_stages', { uuid_input: uuid });
48
- return projectStageDetailsFromDTO(data as ProjectStageDetailsDTO[]);
49
- };
50
-
51
- export const getProjectAssets = async ({
52
- client,
53
- projectUuid,
54
- stageUuid,
55
- }: {
56
- client: DataClient;
57
- projectUuid?: string;
58
- stageUuid?: string;
59
- }): Promise<ProjectAsset[]> => {
60
- if (!projectUuid && !stageUuid) {
61
- console.error('One of projectUuid or stageUuid is required');
62
- return [];
63
- }
64
-
65
- const { data } = await client.rpc('get_project_assets', {
66
- project_uuid_input: projectUuid,
67
- stage_uuid_input: stageUuid,
68
- });
69
- return data || [];
70
- };
71
-
72
- export const getProjectContributors = async ({
73
- client,
74
- projectUuid,
75
- stageUuid,
76
- }: {
77
- client: DataClient;
78
- projectUuid?: string;
79
- stageUuid?: string;
80
- }): Promise<ProjectContributor[]> => {
81
- if (!projectUuid && !stageUuid) {
82
- console.error('One of projectUuid or stageUuid is required');
83
- return [];
84
- }
85
-
86
- const uuid = stageUuid ? stageUuid : projectUuid;
87
- const key = stageUuid ? 'stage_uuid' : 'project_uuid';
88
-
89
- const { data } = await client
90
- .from('project_contributors')
91
- .select(
92
- `
93
- uuid,
94
- stageUuid:stage_uuid,
95
- projectUuid:project_uuid,
96
- ...authorities!contributor_uuid(
97
- contributorUuid:uuid,
98
- name:headword
99
- ),
100
- startDate:start_date,
101
- endDate:end_date,
102
- role:type
103
- `,
104
- )
105
- .eq(key, uuid);
106
- return projectContributorsFromDTO(data as ProjectContributorsDTO);
107
- };
@@ -1,148 +0,0 @@
1
- import { TohokuCatalogEntry } from './toh';
2
- import { ExtendedTranslationLanguage } from './language';
3
-
4
- export type CanonNodeType =
5
- | 'root'
6
- | 'canonicalSection'
7
- | 'nonCanonicalSection'
8
- | 'textGrouping';
9
-
10
- export type CanonDTO = {
11
- uuid: string;
12
- created_at: string;
13
- label: string;
14
- parent_uuid?: string;
15
- xmlId: string;
16
- parent_xmlId?: string;
17
- sort: number;
18
- description: string;
19
- type: CanonNodeType;
20
- public_description?: string;
21
- article_uuid?: string;
22
- };
23
-
24
- export type CanonHead = {
25
- children: CanonNode[];
26
- };
27
-
28
- export type CanonNode = {
29
- uuid: string;
30
- label?: string;
31
- xmlId?: string;
32
- parentXmlId?: string;
33
- parentUuid?: string;
34
- sort: number;
35
- description?: string;
36
- type: CanonNodeType;
37
- publicDescription?: string;
38
- articleUuid?: string;
39
- children?: CanonNode[];
40
- createdAt?: string;
41
- };
42
-
43
- export type CanonArticleDTO = {
44
- uuid: string;
45
- title: string;
46
- body: string;
47
- image?: string;
48
- caption?: string;
49
- };
50
-
51
- export type CanonArticle = CanonArticleDTO;
52
-
53
- export type CanonArticleTitleDTO = {
54
- title: string;
55
- language: ExtendedTranslationLanguage;
56
- };
57
-
58
- export type CanonArticleTitle = CanonArticleTitleDTO;
59
-
60
- export type CanonDetailDTO = {
61
- uuid: string;
62
- label: string;
63
- description: string;
64
- type: CanonNodeType;
65
- article?: CanonArticleDTO;
66
- titles: CanonArticleTitleDTO[];
67
- };
68
- export type CanonDetail = CanonDetailDTO & {
69
- article?: CanonArticle;
70
- titles: CanonArticleTitle[];
71
- };
72
-
73
- export type CanonWorkStatus = 'published' | 'in-progress' | 'not-started';
74
-
75
- export type CanonWorkDTO = {
76
- uuid: string;
77
- toh: TohokuCatalogEntry;
78
- title: string;
79
- published: boolean;
80
- status: CanonWorkStatus;
81
- pages: number;
82
- };
83
-
84
- export type CanonWork = CanonWorkDTO;
85
-
86
- export type CanonWorksDTO = {
87
- works: CanonWorkDTO[];
88
- };
89
-
90
- export const canonNodeFromDTO = (dto: CanonDTO): CanonNode => {
91
- return {
92
- uuid: dto.uuid,
93
- label: dto.label,
94
- xmlId: dto.xmlId,
95
- parentXmlId: dto.parent_xmlId,
96
- parentUuid: dto.parent_uuid,
97
- sort: dto.sort,
98
- description: dto.description,
99
- type: dto.type,
100
- publicDescription: dto.public_description,
101
- articleUuid: dto.article_uuid,
102
- createdAt: dto.created_at,
103
- };
104
- };
105
-
106
- export const canonTreeFromDTOs = (dtos: CanonDTO[]): CanonHead => {
107
- const nodes: Record<string, CanonNode> = {};
108
- dtos.forEach((dto) => {
109
- nodes[dto.uuid] = canonNodeFromDTO(dto);
110
- });
111
-
112
- const tree: CanonNode[] = [];
113
-
114
- Object.values(nodes).forEach((node) => {
115
- if (node.parentUuid) {
116
- const parent = nodes[node.parentUuid];
117
- if (parent) {
118
- parent.children = parent.children || [];
119
- parent.children.push(node);
120
- }
121
- } else {
122
- tree.push(node);
123
- }
124
- });
125
-
126
- // Sort children by their sort order
127
- const sortChildren = (children: CanonNode[]) => {
128
- children.sort((a, b) => a.sort - b.sort);
129
- children.forEach((child) => {
130
- if (child.children) {
131
- sortChildren(child.children);
132
- }
133
- });
134
- };
135
- sortChildren(tree);
136
-
137
- return {
138
- children: tree,
139
- };
140
- };
141
-
142
- export const canonDetailFromDTO = (dto: CanonDetailDTO): CanonDetail => {
143
- return dto as CanonDetail;
144
- };
145
-
146
- export const caononWorksFromDTO = (dto: CanonWorksDTO): CanonWork[] => {
147
- return dto.works as CanonWork[];
148
- };
@@ -1,84 +0,0 @@
1
- export type ContributorRole =
2
- | 'englishAdvisor'
3
- | 'englishAssociateEditor'
4
- | 'englishCopyEditor'
5
- | 'englishDharmaMaster'
6
- | 'englishFinalReviewer'
7
- | 'englishMarkup'
8
- | 'englishProjectEditor'
9
- | 'englishProjectManager'
10
- | 'englishProofReader'
11
- | 'englishReviser'
12
- | 'englishTranslator'
13
- | 'englishTranslationSponsor'
14
- | 'englishTranslationTeam'
15
- | 'tibetanTranslator';
16
-
17
- export type Contributor = {
18
- name: string;
19
- role: ContributorRole;
20
- };
21
-
22
- export type ProjectContributor = Contributor & {
23
- uuid: string;
24
- contributorUuid: string;
25
- startDate?: Date;
26
- endDate?: Date;
27
- projectUuid: string;
28
- stageUuid?: string;
29
- };
30
-
31
- export type Contributors = Contributor[];
32
- export type ProjectContributors = ProjectContributor[];
33
-
34
- export type ContributorDTO = {
35
- name: string;
36
- role: ContributorRole;
37
- };
38
-
39
- export type ContributorsDTO = ContributorDTO[];
40
-
41
- export type ProjectContributorDTO = {
42
- uuid: string;
43
- projectUuid: string;
44
- stageUuid?: string;
45
- contributorUuid: string;
46
- name: string;
47
- role: ContributorRole;
48
- startDate: string;
49
- endDate: string;
50
- };
51
-
52
- export type ProjectContributorsDTO = ProjectContributorDTO[];
53
-
54
- export const contributorFromDTO = (dto: ContributorDTO): Contributor => {
55
- return {
56
- name: dto.name,
57
- role: dto.role,
58
- };
59
- };
60
-
61
- export const contributorsFromDTO = (dto?: ContributorsDTO): Contributors => {
62
- return dto?.map(contributorFromDTO) || [];
63
- };
64
-
65
- export const projectContributorFromDTO = (
66
- dto: ProjectContributorDTO,
67
- ): ProjectContributor => {
68
- return {
69
- uuid: dto.uuid,
70
- name: dto.name,
71
- contributorUuid: dto.contributorUuid,
72
- role: dto.role,
73
- startDate: new Date(dto.startDate),
74
- endDate: new Date(dto.endDate),
75
- projectUuid: dto.projectUuid,
76
- stageUuid: dto.stageUuid,
77
- };
78
- };
79
-
80
- export const projectContributorsFromDTO = (
81
- dto?: ProjectContributorsDTO,
82
- ): ProjectContributors => {
83
- return dto?.map(projectContributorFromDTO) || [];
84
- };
@@ -1,200 +0,0 @@
1
- import { SemVer } from './semver';
2
-
3
- export const PROJECT_STAGE_LABELS = [
4
- '1',
5
- '1.a',
6
- '2',
7
- '2.a',
8
- '2.b',
9
- '2.c',
10
- '2.d',
11
- '2.e',
12
- '2.f',
13
- '2.g',
14
- '2.h',
15
- '3',
16
- '4',
17
- '0',
18
- ];
19
-
20
- export const STAGE_DESCRIPTIONS: Record<ProjectStageLabel, string> = {
21
- '1': 'Published and in app',
22
- '1.a': 'Published',
23
- '2': 'Marked up and awaiting final proofing',
24
- '2.a': 'Markup in progress',
25
- '2.b': 'Awaiting markup',
26
- '2.c': "Awaiting editor's OK form markup",
27
- '2.d': 'Copy editing complete',
28
- '2.e': 'Copy editing in progress',
29
- '2.f': 'Review complete',
30
- '2.g': 'In editorial review',
31
- '2.h': 'Awaiting editorial review',
32
- '3': 'In translation',
33
- '4': 'Application pending',
34
- '0': 'Not started',
35
- };
36
-
37
- export const STAGE_COLORS: Record<ProjectStageLabel, string> = {
38
- '1': 'emerald',
39
- '1.a': 'emerald',
40
- '2': 'ochre',
41
- '2.a': 'ochre',
42
- '2.b': 'ochre',
43
- '2.c': 'ochre',
44
- '2.d': 'ochre',
45
- '2.e': 'ochre',
46
- '2.f': 'ochre',
47
- '2.g': 'ochre',
48
- '2.h': 'ochre',
49
- '3': 'navy',
50
- '4': 'brick',
51
- '0': 'muted text-muted-foreground',
52
- };
53
-
54
- export const CANON_TYPES = ['kangyur', 'tengyur'];
55
-
56
- export type ProjectStageLabel = (typeof PROJECT_STAGE_LABELS)[number];
57
-
58
- export type CanonType = (typeof CANON_TYPES)[number];
59
-
60
- export type ProjectStage = {
61
- label: ProjectStageLabel;
62
- description: string;
63
- date: Date;
64
- targetDate?: Date;
65
- color: string;
66
- };
67
-
68
- export type ProjectViewDTO = {
69
- uuid: string;
70
- toh: string;
71
- title: string;
72
- translator: string;
73
- stage: ProjectStageLabel;
74
- stage_date: string;
75
- pages: number;
76
- type?: string;
77
- };
78
-
79
- export type ProjectTableDTO = {
80
- uuid: string;
81
- notes: string;
82
- contractDate: string;
83
- contractId: string;
84
- workUuid: string;
85
- pages: number;
86
- publicationDate: string;
87
- version: string;
88
- stage: ProjectStageLabel;
89
- restriction: boolean;
90
- title: string;
91
- toh: string;
92
- mainTranslator: string;
93
- translationGroup: string;
94
- };
95
-
96
- export type Project = {
97
- uuid: string;
98
- toh: string;
99
- title: string;
100
- translator?: string;
101
- translationGroup?: string;
102
- stage: ProjectStage;
103
- pages: number;
104
- notes?: string;
105
- contractDate?: Date;
106
- contractId?: string;
107
- workUuid?: string;
108
- version?: SemVer;
109
- canons?: string;
110
- };
111
-
112
- export type ProjectStageDetailsDTO = {
113
- uuid: string;
114
- stage: ProjectStageLabel;
115
- stageDate: string;
116
- targetDate?: string;
117
- };
118
-
119
- export type ProjectStageDetail = {
120
- uuid: string;
121
- stage: ProjectStage;
122
- targetDate?: Date;
123
- };
124
-
125
- export type ProjectStageDetails = ProjectStageDetail[];
126
-
127
- export type ProjectAssetDTO = {
128
- uuid: string;
129
- projectUuid: string;
130
- stageUuid?: string;
131
- filename: string;
132
- url: string;
133
- note?: string;
134
- };
135
-
136
- export type ProjectAsset = ProjectAssetDTO;
137
-
138
- export function projectStageDetailFromDTO(
139
- dto: ProjectStageDetailsDTO,
140
- ): ProjectStageDetail {
141
- return {
142
- uuid: dto.uuid,
143
- stage: {
144
- label: dto.stage,
145
- description: STAGE_DESCRIPTIONS[dto.stage] || '',
146
- date: new Date(dto.stageDate),
147
- targetDate: dto.targetDate ? new Date(dto.targetDate) : undefined,
148
- color: STAGE_COLORS[dto.stage] || 'grey',
149
- },
150
- };
151
- }
152
-
153
- export function projectStageDetailsFromDTO(
154
- dto?: ProjectStageDetailsDTO[],
155
- ): ProjectStageDetails {
156
- return dto?.map(projectStageDetailFromDTO) || [];
157
- }
158
-
159
- export function projectFromViewDTO(dto: ProjectViewDTO): Project {
160
- return {
161
- uuid: dto.uuid,
162
- toh: dto.toh,
163
- title: dto.title,
164
- translator: dto.translator,
165
- stage: {
166
- label: dto.stage,
167
- description: STAGE_DESCRIPTIONS[dto.stage] || '',
168
- date: new Date(dto.stage_date),
169
- color: STAGE_COLORS[dto.stage] || 'grey',
170
- },
171
- pages: dto.pages,
172
- canons: dto.type,
173
- };
174
- }
175
-
176
- export function projectFromTableDTO(dto: ProjectTableDTO): Project {
177
- const stage = dto.stage;
178
- const contractDate = dto.contractDate
179
- ? new Date(dto.contractDate)
180
- : undefined;
181
- return {
182
- uuid: dto.uuid,
183
- toh: dto.toh,
184
- title: dto.title,
185
- stage: {
186
- label: stage,
187
- description: STAGE_DESCRIPTIONS[stage] || '',
188
- date: new Date(dto.publicationDate),
189
- color: STAGE_COLORS[stage] || 'grey',
190
- },
191
- pages: dto.pages,
192
- notes: dto.notes,
193
- contractId: dto.contractId,
194
- contractDate,
195
- workUuid: dto.workUuid,
196
- version: dto.version as SemVer,
197
- translator: dto.mainTranslator,
198
- translationGroup: dto.translationGroup,
199
- };
200
- }