@eightyfourthousand/client-graphql 2026.3.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 (54) hide show
  1. package/codegen.ts +34 -0
  2. package/package.json +25 -0
  3. package/project.json +21 -0
  4. package/src/index.ts +79 -0
  5. package/src/lib/client-ssr.ts +44 -0
  6. package/src/lib/client.ts +58 -0
  7. package/src/lib/config.ts +21 -0
  8. package/src/lib/functions/get-bibliography-entry.ts +40 -0
  9. package/src/lib/functions/get-glossary-entry.ts +136 -0
  10. package/src/lib/functions/get-glossary-instance.ts +48 -0
  11. package/src/lib/functions/get-glossary-terms.ts +44 -0
  12. package/src/lib/functions/get-passage.ts +78 -0
  13. package/src/lib/functions/get-term-passages.ts +53 -0
  14. package/src/lib/functions/get-translation-blocks-around.ts +131 -0
  15. package/src/lib/functions/get-translation-blocks.ts +160 -0
  16. package/src/lib/functions/get-translation-imprint.ts +114 -0
  17. package/src/lib/functions/get-translation-metadata.ts +99 -0
  18. package/src/lib/functions/get-translation-passages-around.ts +153 -0
  19. package/src/lib/functions/get-translation-passages.ts +168 -0
  20. package/src/lib/functions/get-translation-titles.ts +55 -0
  21. package/src/lib/functions/get-translation-toc.ts +115 -0
  22. package/src/lib/functions/get-translation-uuids.ts +63 -0
  23. package/src/lib/functions/get-translations-metadata.ts +81 -0
  24. package/src/lib/functions/get-work-bibliography.ts +47 -0
  25. package/src/lib/functions/get-work-folios.ts +52 -0
  26. package/src/lib/functions/get-work-glossary-terms-around.ts +126 -0
  27. package/src/lib/functions/get-work-glossary-terms.ts +150 -0
  28. package/src/lib/functions/get-work-glossary.ts +54 -0
  29. package/src/lib/functions/get-works.ts +111 -0
  30. package/src/lib/functions/has-permission.ts +38 -0
  31. package/src/lib/functions/index.ts +33 -0
  32. package/src/lib/functions/save-passages.ts +76 -0
  33. package/src/lib/generated/graphql.ts +1318 -0
  34. package/src/lib/graphql/fragments/alignment.graphql +7 -0
  35. package/src/lib/graphql/fragments/annotation.graphql +7 -0
  36. package/src/lib/graphql/fragments/imprint.graphql +34 -0
  37. package/src/lib/graphql/fragments/passage.graphql +29 -0
  38. package/src/lib/graphql/fragments/title.graphql +6 -0
  39. package/src/lib/graphql/fragments/toc.graphql +40 -0
  40. package/src/lib/graphql/fragments/work.graphql +10 -0
  41. package/src/lib/graphql/queries/passages.graphql +116 -0
  42. package/src/lib/graphql/queries/work.graphql +38 -0
  43. package/src/lib/graphql/queries/works.graphql +23 -0
  44. package/src/lib/mappers/alignment.ts +34 -0
  45. package/src/lib/mappers/annotation.ts +204 -0
  46. package/src/lib/mappers/imprint.ts +79 -0
  47. package/src/lib/mappers/index.ts +7 -0
  48. package/src/lib/mappers/passage.ts +80 -0
  49. package/src/lib/mappers/title.ts +35 -0
  50. package/src/lib/mappers/toc.ts +49 -0
  51. package/src/lib/mappers/work.ts +38 -0
  52. package/src/ssr.ts +73 -0
  53. package/tsconfig.json +17 -0
  54. package/tsconfig.lib.json +14 -0
@@ -0,0 +1,7 @@
1
+ fragment AlignmentFields on Alignment {
2
+ folioUuid
3
+ toh
4
+ tibetan
5
+ folioNumber
6
+ volumeNumber
7
+ }
@@ -0,0 +1,7 @@
1
+ fragment AnnotationFields on Annotation {
2
+ uuid
3
+ type
4
+ start
5
+ end
6
+ metadata
7
+ }
@@ -0,0 +1,34 @@
1
+ fragment LicenseFields on License {
2
+ name
3
+ link
4
+ description
5
+ }
6
+
7
+ fragment TitlesByLanguageFields on TitlesByLanguage {
8
+ tibetan
9
+ english
10
+ wylie
11
+ sanskrit
12
+ }
13
+
14
+ fragment ImprintFields on Imprint {
15
+ toh
16
+ section
17
+ version
18
+ restriction
19
+ publishYear
20
+ tibetanAuthors
21
+ isAuthorContested
22
+ sourceDescription
23
+ publisherStatement
24
+ tibetanTranslators
25
+ license {
26
+ ...LicenseFields
27
+ }
28
+ mainTitles {
29
+ ...TitlesByLanguageFields
30
+ }
31
+ longTitles {
32
+ ...TitlesByLanguageFields
33
+ }
34
+ }
@@ -0,0 +1,29 @@
1
+ fragment PassageFields on Passage {
2
+ uuid
3
+ workUuid
4
+ content
5
+ label
6
+ sort
7
+ type
8
+ xmlId
9
+ }
10
+
11
+ fragment PassageWithAnnotations on Passage {
12
+ ...PassageFields
13
+ annotations {
14
+ ...AnnotationFields
15
+ }
16
+ alignments {
17
+ ...AlignmentFields
18
+ }
19
+ }
20
+
21
+ fragment PassageWithJson on Passage {
22
+ uuid
23
+ workUuid
24
+ label
25
+ sort
26
+ type
27
+ xmlId
28
+ json
29
+ }
@@ -0,0 +1,6 @@
1
+ fragment TitleFields on Title {
2
+ uuid
3
+ content
4
+ language
5
+ type
6
+ }
@@ -0,0 +1,40 @@
1
+ fragment TocEntryFields on TocEntry {
2
+ uuid
3
+ content
4
+ label
5
+ sort
6
+ level
7
+ section
8
+ }
9
+
10
+ # Recursive fragment for TOC entries up to 6 levels deep
11
+ fragment TocEntryNested on TocEntry {
12
+ ...TocEntryFields
13
+ children {
14
+ ...TocEntryFields
15
+ children {
16
+ ...TocEntryFields
17
+ children {
18
+ ...TocEntryFields
19
+ children {
20
+ ...TocEntryFields
21
+ children {
22
+ ...TocEntryFields
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ fragment TocFields on Toc {
31
+ frontMatter {
32
+ ...TocEntryNested
33
+ }
34
+ body {
35
+ ...TocEntryNested
36
+ }
37
+ backMatter {
38
+ ...TocEntryNested
39
+ }
40
+ }
@@ -0,0 +1,10 @@
1
+ fragment WorkFields on Work {
2
+ uuid
3
+ title
4
+ toh
5
+ publicationDate
6
+ publicationVersion
7
+ pages
8
+ restriction
9
+ section
10
+ }
@@ -0,0 +1,116 @@
1
+ query GetPassages(
2
+ $uuid: ID!
3
+ $cursor: String
4
+ $limit: Int
5
+ $direction: PaginationDirection
6
+ $filter: PassageFilter
7
+ ) {
8
+ work(uuid: $uuid) {
9
+ uuid
10
+ passages(
11
+ cursor: $cursor
12
+ limit: $limit
13
+ direction: $direction
14
+ filter: $filter
15
+ ) {
16
+ nodes {
17
+ ...PassageWithAnnotations
18
+ }
19
+ pageInfo {
20
+ nextCursor
21
+ prevCursor
22
+ hasMoreAfter
23
+ hasMoreBefore
24
+ }
25
+ }
26
+ }
27
+ }
28
+
29
+ query GetPassagesBasic(
30
+ $uuid: ID!
31
+ $cursor: String
32
+ $limit: Int
33
+ $direction: PaginationDirection
34
+ $filter: PassageFilter
35
+ ) {
36
+ work(uuid: $uuid) {
37
+ uuid
38
+ passages(
39
+ cursor: $cursor
40
+ limit: $limit
41
+ direction: $direction
42
+ filter: $filter
43
+ ) {
44
+ nodes {
45
+ ...PassageFields
46
+ }
47
+ pageInfo {
48
+ nextCursor
49
+ prevCursor
50
+ hasMoreAfter
51
+ hasMoreBefore
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ query GetPassagesWithJson(
58
+ $uuid: ID!
59
+ $cursor: String
60
+ $limit: Int
61
+ $direction: PaginationDirection
62
+ $filter: PassageFilter
63
+ ) {
64
+ work(uuid: $uuid) {
65
+ uuid
66
+ passages(
67
+ cursor: $cursor
68
+ limit: $limit
69
+ direction: $direction
70
+ filter: $filter
71
+ ) {
72
+ nodes {
73
+ ...PassageWithJson
74
+ }
75
+ pageInfo {
76
+ nextCursor
77
+ prevCursor
78
+ hasMoreAfter
79
+ hasMoreBefore
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ query GetPassagesAroundWithJson(
86
+ $uuid: ID!
87
+ $cursor: String!
88
+ $limit: Int
89
+ $filter: PassageFilter
90
+ ) {
91
+ work(uuid: $uuid) {
92
+ uuid
93
+ passages(
94
+ cursor: $cursor
95
+ limit: $limit
96
+ direction: AROUND
97
+ filter: $filter
98
+ ) {
99
+ nodes {
100
+ ...PassageWithJson
101
+ }
102
+ pageInfo {
103
+ nextCursor
104
+ prevCursor
105
+ hasMoreAfter
106
+ hasMoreBefore
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ query GetPassage($uuid: ID!) {
113
+ passage(uuid: $uuid) {
114
+ ...PassageWithAnnotations
115
+ }
116
+ }
@@ -0,0 +1,38 @@
1
+ query GetWorkByUuid($uuid: ID!) {
2
+ work(uuid: $uuid) {
3
+ ...WorkFields
4
+ }
5
+ }
6
+
7
+ query GetWorkByToh($toh: String!) {
8
+ work(toh: $toh) {
9
+ ...WorkFields
10
+ }
11
+ }
12
+
13
+ query GetWorkWithTitles($uuid: ID!) {
14
+ work(uuid: $uuid) {
15
+ ...WorkFields
16
+ titles {
17
+ ...TitleFields
18
+ }
19
+ }
20
+ }
21
+
22
+ query GetWorkWithImprint($uuid: ID!, $toh: String) {
23
+ work(uuid: $uuid, toh: $toh) {
24
+ ...WorkFields
25
+ imprint {
26
+ ...ImprintFields
27
+ }
28
+ }
29
+ }
30
+
31
+ query GetWorkWithToc($uuid: ID!) {
32
+ work(uuid: $uuid) {
33
+ ...WorkFields
34
+ toc {
35
+ ...TocFields
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,23 @@
1
+ query GetAllWorks($cursor: String, $limit: Int) {
2
+ works(cursor: $cursor, limit: $limit) {
3
+ items {
4
+ ...WorkFields
5
+ }
6
+ pageInfo {
7
+ nextCursor
8
+ hasMoreAfter
9
+ }
10
+ }
11
+ }
12
+
13
+ query GetWorkUuids($cursor: String, $limit: Int) {
14
+ works(cursor: $cursor, limit: $limit) {
15
+ items {
16
+ uuid
17
+ }
18
+ pageInfo {
19
+ nextCursor
20
+ hasMoreAfter
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,34 @@
1
+ import type { Alignment, TohokuCatalogEntry } from '@eightyfourthousand/data-access';
2
+
3
+ /**
4
+ * GraphQL Alignment type from generated code
5
+ */
6
+ export type GraphQLAlignment = {
7
+ folioUuid: string;
8
+ toh: string;
9
+ tibetan: string;
10
+ folioNumber: number;
11
+ volumeNumber: number;
12
+ };
13
+
14
+ /**
15
+ * Convert a GraphQL alignment to the internal Alignment type
16
+ */
17
+ export function alignmentFromGraphQL(gqlAlignment: GraphQLAlignment): Alignment {
18
+ return {
19
+ folioUuid: gqlAlignment.folioUuid,
20
+ toh: gqlAlignment.toh as TohokuCatalogEntry,
21
+ tibetan: gqlAlignment.tibetan,
22
+ folioNumber: gqlAlignment.folioNumber,
23
+ volumeNumber: gqlAlignment.volumeNumber,
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Convert an array of GraphQL alignments to internal Alignment types
29
+ */
30
+ export function alignmentsFromGraphQL(
31
+ gqlAlignments: GraphQLAlignment[],
32
+ ): Alignment[] {
33
+ return gqlAlignments.map(alignmentFromGraphQL);
34
+ }
@@ -0,0 +1,204 @@
1
+ import {
2
+ type Annotation,
3
+ type Annotations,
4
+ type AnnotationType,
5
+ type HeadingClass,
6
+ type ExtendedTranslationLanguage,
7
+ ANNOTATION_TYPE_DTO_TO_TYPE,
8
+ } from '@eightyfourthousand/data-access';
9
+
10
+ /**
11
+ * GraphQL Annotation type from generated code
12
+ */
13
+ export type GraphQLAnnotation = {
14
+ uuid: string;
15
+ type: string;
16
+ start: number;
17
+ end: number;
18
+ metadata?: Record<string, unknown> | null;
19
+ };
20
+
21
+ /**
22
+ * Map from DTO-style type names (kebab-case) to internal type names (camelCase)
23
+ */
24
+ const typeMap: Record<string, AnnotationType> = {
25
+ ...ANNOTATION_TYPE_DTO_TO_TYPE,
26
+ // Also handle camelCase types (from GraphQL)
27
+ endNoteLink: 'endNoteLink',
28
+ glossaryInstance: 'glossaryInstance',
29
+ hasAbbreviation: 'hasAbbreviation',
30
+ inlineTitle: 'inlineTitle',
31
+ internalLink: 'internalLink',
32
+ leadingSpace: 'leadingSpace',
33
+ lineGroup: 'lineGroup',
34
+ listItem: 'listItem',
35
+ tableBodyData: 'tableBodyData',
36
+ tableBodyHeader: 'tableBodyHeader',
37
+ tableBodyRow: 'tableBodyRow',
38
+ };
39
+
40
+ /**
41
+ * Convert a GraphQL annotation to the internal Annotation type
42
+ */
43
+ export function annotationFromGraphQL(
44
+ gqlAnnotation: GraphQLAnnotation,
45
+ passageUuid: string,
46
+ ): Annotation {
47
+ const type = typeMap[gqlAnnotation.type] || 'unknown';
48
+ const metadata = gqlAnnotation.metadata || {};
49
+
50
+ const base = {
51
+ uuid: gqlAnnotation.uuid,
52
+ type,
53
+ start: gqlAnnotation.start,
54
+ end: gqlAnnotation.end,
55
+ passageUuid,
56
+ validated: true,
57
+ };
58
+
59
+ // Extract type-specific fields from metadata
60
+ switch (type) {
61
+ case 'heading':
62
+ return {
63
+ ...base,
64
+ type: 'heading',
65
+ level: (metadata.level as number) ?? 1,
66
+ class: metadata.class as HeadingClass | undefined,
67
+ };
68
+
69
+ case 'link':
70
+ return {
71
+ ...base,
72
+ type: 'link',
73
+ href: (metadata.href as string) ?? '',
74
+ text: (metadata.text as string) ?? '',
75
+ };
76
+
77
+ case 'internalLink':
78
+ return {
79
+ ...base,
80
+ type: 'internalLink',
81
+ linkType: (metadata.linkType as string) ?? '',
82
+ href: metadata.href as string | undefined,
83
+ label: metadata.label as string | undefined,
84
+ entity: metadata.entity as string | undefined,
85
+ isPending: metadata.isPending as boolean | undefined,
86
+ isSameWork: metadata.isSameWork as boolean | undefined,
87
+ subtype: metadata.subtype as string | undefined,
88
+ linkToh: metadata.linkToh as string | undefined,
89
+ };
90
+
91
+ case 'span':
92
+ return {
93
+ ...base,
94
+ type: 'span',
95
+ textStyle: metadata.textStyle as string | undefined,
96
+ lang: metadata.lang as ExtendedTranslationLanguage | undefined,
97
+ };
98
+
99
+ case 'mantra':
100
+ return {
101
+ ...base,
102
+ type: 'mantra',
103
+ lang: (metadata.lang as ExtendedTranslationLanguage) ?? 'Sa-Ltn',
104
+ };
105
+
106
+ case 'inlineTitle':
107
+ return {
108
+ ...base,
109
+ type: 'inlineTitle',
110
+ lang: (metadata.lang as ExtendedTranslationLanguage) ?? 'Sa-Ltn',
111
+ };
112
+
113
+ case 'audio':
114
+ return {
115
+ ...base,
116
+ type: 'audio',
117
+ src: (metadata.src as string) ?? '',
118
+ mediaType: (metadata.mediaType as string) ?? '',
119
+ };
120
+
121
+ case 'image':
122
+ return {
123
+ ...base,
124
+ type: 'image',
125
+ src: (metadata.src as string) ?? '',
126
+ };
127
+
128
+ case 'list':
129
+ return {
130
+ ...base,
131
+ type: 'list',
132
+ spacing: metadata.spacing as string | undefined,
133
+ nesting: metadata.nesting as number | undefined,
134
+ itemStyle: metadata.itemStyle as string | undefined,
135
+ };
136
+
137
+ case 'glossaryInstance':
138
+ return {
139
+ ...base,
140
+ type: 'glossaryInstance',
141
+ authority: (metadata.authority as string) ?? '',
142
+ glossary: (metadata.glossary as string) ?? '',
143
+ };
144
+
145
+ case 'endNoteLink':
146
+ return {
147
+ ...base,
148
+ type: 'endNoteLink',
149
+ endNote: (metadata.endNote as string) ?? '',
150
+ label: metadata.label as string | undefined,
151
+ };
152
+
153
+ case 'abbreviation':
154
+ return {
155
+ ...base,
156
+ type: 'abbreviation',
157
+ abbreviation: (metadata.abbreviation as string) ?? '',
158
+ };
159
+
160
+ case 'hasAbbreviation':
161
+ return {
162
+ ...base,
163
+ type: 'hasAbbreviation',
164
+ abbreviation: (metadata.abbreviation as string) ?? '',
165
+ };
166
+
167
+ case 'quote':
168
+ return {
169
+ ...base,
170
+ type: 'quote',
171
+ quote: metadata.quote as string | undefined,
172
+ };
173
+
174
+ case 'quoted':
175
+ return {
176
+ ...base,
177
+ type: 'quoted',
178
+ quote: metadata.quote as string | undefined,
179
+ };
180
+
181
+ default:
182
+ // For types with no additional fields
183
+ return base as Annotation;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Convert an array of GraphQL annotations to internal Annotation types
189
+ */
190
+ export function annotationsFromGraphQL(
191
+ gqlAnnotations: GraphQLAnnotation[],
192
+ passageUuid: string,
193
+ ): Annotations {
194
+ // Filter out ignored annotation types
195
+ const ignoredTypes = [
196
+ 'deprecated-internal-link',
197
+ 'quoted',
198
+ 'reference',
199
+ 'unknown',
200
+ ];
201
+ const filtered = gqlAnnotations.filter((a) => !ignoredTypes.includes(a.type));
202
+
203
+ return filtered.map((a) => annotationFromGraphQL(a, passageUuid));
204
+ }
@@ -0,0 +1,79 @@
1
+ import type { Imprint, SemVer, TranslationLanguage } from '@eightyfourthousand/data-access';
2
+
3
+ /**
4
+ * GraphQL TitlesByLanguage type
5
+ */
6
+ type GraphQLTitlesByLanguage = {
7
+ tibetan?: string | null;
8
+ english?: string | null;
9
+ wylie?: string | null;
10
+ sanskrit?: string | null;
11
+ };
12
+
13
+ /**
14
+ * GraphQL Imprint type
15
+ */
16
+ export type GraphQLImprint = {
17
+ toh: string;
18
+ section?: string | null;
19
+ version?: string | null;
20
+ restriction?: boolean | null;
21
+ publishYear?: string | null;
22
+ tibetanAuthors?: string[] | null;
23
+ isAuthorContested: boolean;
24
+ sourceDescription?: string | null;
25
+ publisherStatement?: string | null;
26
+ tibetanTranslators?: string | null;
27
+ license: {
28
+ name?: string | null;
29
+ link?: string | null;
30
+ description?: string | null;
31
+ } | null;
32
+ mainTitles?: GraphQLTitlesByLanguage | null;
33
+ longTitles?: GraphQLTitlesByLanguage | null;
34
+ };
35
+
36
+ /**
37
+ * Map GraphQL TitlesByLanguage to internal TranslationLanguage keyed record
38
+ */
39
+ function titlesFromGraphQL(
40
+ gqlTitles?: GraphQLTitlesByLanguage | null,
41
+ ): Partial<{ [key in TranslationLanguage]: string }> | undefined {
42
+ if (!gqlTitles) return undefined;
43
+
44
+ const result: Partial<{ [key in TranslationLanguage]: string }> = {};
45
+ if (gqlTitles.tibetan) result['bo'] = gqlTitles.tibetan;
46
+ if (gqlTitles.english) result['en'] = gqlTitles.english;
47
+ if (gqlTitles.wylie) result['Bo-Ltn'] = gqlTitles.wylie;
48
+ if (gqlTitles.sanskrit) result['Sa-Ltn'] = gqlTitles.sanskrit;
49
+ return Object.keys(result).length > 0 ? result : undefined;
50
+ }
51
+
52
+ /**
53
+ * Convert a GraphQL Imprint to the internal Imprint type
54
+ */
55
+ export function imprintFromGraphQL(
56
+ gqlImprint: GraphQLImprint,
57
+ workUuid: string,
58
+ ): Imprint {
59
+ return {
60
+ uuid: workUuid,
61
+ toh: gqlImprint.toh,
62
+ section: gqlImprint.section || undefined,
63
+ version: (gqlImprint.version as SemVer) || undefined,
64
+ restriction: gqlImprint.restriction || undefined,
65
+ publishYear: gqlImprint.publishYear || undefined,
66
+ tibetanAuthors: gqlImprint.tibetanAuthors || undefined,
67
+ isAuthorContested: gqlImprint.isAuthorContested,
68
+ sourceDescription: gqlImprint.sourceDescription || undefined,
69
+ publisherStatement: gqlImprint.publisherStatement || undefined,
70
+ tibetanTranslators: gqlImprint.tibetanTranslators || undefined,
71
+ license: {
72
+ link: gqlImprint.license?.link || undefined,
73
+ name: gqlImprint.license?.name || undefined,
74
+ description: gqlImprint.license?.description || undefined,
75
+ },
76
+ mainTitles: titlesFromGraphQL(gqlImprint.mainTitles),
77
+ longTitles: titlesFromGraphQL(gqlImprint.longTitles),
78
+ };
79
+ }
@@ -0,0 +1,7 @@
1
+ export * from './alignment';
2
+ export * from './annotation';
3
+ export * from './imprint';
4
+ export * from './passage';
5
+ export * from './title';
6
+ export * from './toc';
7
+ export * from './work';