@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.
- package/codegen.ts +34 -0
- package/package.json +25 -0
- package/project.json +21 -0
- package/src/index.ts +79 -0
- package/src/lib/client-ssr.ts +44 -0
- package/src/lib/client.ts +58 -0
- package/src/lib/config.ts +21 -0
- package/src/lib/functions/get-bibliography-entry.ts +40 -0
- package/src/lib/functions/get-glossary-entry.ts +136 -0
- package/src/lib/functions/get-glossary-instance.ts +48 -0
- package/src/lib/functions/get-glossary-terms.ts +44 -0
- package/src/lib/functions/get-passage.ts +78 -0
- package/src/lib/functions/get-term-passages.ts +53 -0
- package/src/lib/functions/get-translation-blocks-around.ts +131 -0
- package/src/lib/functions/get-translation-blocks.ts +160 -0
- package/src/lib/functions/get-translation-imprint.ts +114 -0
- package/src/lib/functions/get-translation-metadata.ts +99 -0
- package/src/lib/functions/get-translation-passages-around.ts +153 -0
- package/src/lib/functions/get-translation-passages.ts +168 -0
- package/src/lib/functions/get-translation-titles.ts +55 -0
- package/src/lib/functions/get-translation-toc.ts +115 -0
- package/src/lib/functions/get-translation-uuids.ts +63 -0
- package/src/lib/functions/get-translations-metadata.ts +81 -0
- package/src/lib/functions/get-work-bibliography.ts +47 -0
- package/src/lib/functions/get-work-folios.ts +52 -0
- package/src/lib/functions/get-work-glossary-terms-around.ts +126 -0
- package/src/lib/functions/get-work-glossary-terms.ts +150 -0
- package/src/lib/functions/get-work-glossary.ts +54 -0
- package/src/lib/functions/get-works.ts +111 -0
- package/src/lib/functions/has-permission.ts +38 -0
- package/src/lib/functions/index.ts +33 -0
- package/src/lib/functions/save-passages.ts +76 -0
- package/src/lib/generated/graphql.ts +1318 -0
- package/src/lib/graphql/fragments/alignment.graphql +7 -0
- package/src/lib/graphql/fragments/annotation.graphql +7 -0
- package/src/lib/graphql/fragments/imprint.graphql +34 -0
- package/src/lib/graphql/fragments/passage.graphql +29 -0
- package/src/lib/graphql/fragments/title.graphql +6 -0
- package/src/lib/graphql/fragments/toc.graphql +40 -0
- package/src/lib/graphql/fragments/work.graphql +10 -0
- package/src/lib/graphql/queries/passages.graphql +116 -0
- package/src/lib/graphql/queries/work.graphql +38 -0
- package/src/lib/graphql/queries/works.graphql +23 -0
- package/src/lib/mappers/alignment.ts +34 -0
- package/src/lib/mappers/annotation.ts +204 -0
- package/src/lib/mappers/imprint.ts +79 -0
- package/src/lib/mappers/index.ts +7 -0
- package/src/lib/mappers/passage.ts +80 -0
- package/src/lib/mappers/title.ts +35 -0
- package/src/lib/mappers/toc.ts +49 -0
- package/src/lib/mappers/work.ts +38 -0
- package/src/ssr.ts +73 -0
- package/tsconfig.json +17 -0
- package/tsconfig.lib.json +14 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type {
|
|
4
|
+
BodyItemType,
|
|
5
|
+
PaginationDirection,
|
|
6
|
+
PassagesPage,
|
|
7
|
+
} from '@eightyfourthousand/data-access';
|
|
8
|
+
import { passagesPageFromGraphQL } from '../mappers';
|
|
9
|
+
|
|
10
|
+
const GET_PASSAGES = gql`
|
|
11
|
+
fragment AnnotationFields on Annotation {
|
|
12
|
+
uuid
|
|
13
|
+
type
|
|
14
|
+
start
|
|
15
|
+
end
|
|
16
|
+
metadata
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fragment AlignmentFields on Alignment {
|
|
20
|
+
folioUuid
|
|
21
|
+
toh
|
|
22
|
+
tibetan
|
|
23
|
+
folioNumber
|
|
24
|
+
volumeNumber
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fragment PassageWithAnnotations on Passage {
|
|
28
|
+
uuid
|
|
29
|
+
workUuid
|
|
30
|
+
content
|
|
31
|
+
label
|
|
32
|
+
sort
|
|
33
|
+
type
|
|
34
|
+
xmlId
|
|
35
|
+
annotations {
|
|
36
|
+
...AnnotationFields
|
|
37
|
+
}
|
|
38
|
+
alignments {
|
|
39
|
+
...AlignmentFields
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
query GetPassages(
|
|
44
|
+
$uuid: ID!
|
|
45
|
+
$cursor: String
|
|
46
|
+
$limit: Int
|
|
47
|
+
$direction: PaginationDirection
|
|
48
|
+
$filter: PassageFilter
|
|
49
|
+
) {
|
|
50
|
+
work(uuid: $uuid) {
|
|
51
|
+
uuid
|
|
52
|
+
passages(
|
|
53
|
+
cursor: $cursor
|
|
54
|
+
limit: $limit
|
|
55
|
+
direction: $direction
|
|
56
|
+
filter: $filter
|
|
57
|
+
) {
|
|
58
|
+
nodes {
|
|
59
|
+
...PassageWithAnnotations
|
|
60
|
+
}
|
|
61
|
+
pageInfo {
|
|
62
|
+
nextCursor
|
|
63
|
+
prevCursor
|
|
64
|
+
hasMoreAfter
|
|
65
|
+
hasMoreBefore
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
type GetPassagesResponse = {
|
|
73
|
+
work: {
|
|
74
|
+
uuid: string;
|
|
75
|
+
passages: {
|
|
76
|
+
nodes: Array<{
|
|
77
|
+
uuid: string;
|
|
78
|
+
workUuid: string;
|
|
79
|
+
content: string;
|
|
80
|
+
label: string;
|
|
81
|
+
sort: number;
|
|
82
|
+
type: string;
|
|
83
|
+
xmlId?: string | null;
|
|
84
|
+
annotations: Array<{
|
|
85
|
+
uuid: string;
|
|
86
|
+
type: string;
|
|
87
|
+
start: number;
|
|
88
|
+
end: number;
|
|
89
|
+
metadata?: Record<string, unknown> | null;
|
|
90
|
+
}>;
|
|
91
|
+
alignments: Array<{
|
|
92
|
+
folioUuid: string;
|
|
93
|
+
toh: string;
|
|
94
|
+
tibetan: string;
|
|
95
|
+
folioNumber: number;
|
|
96
|
+
volumeNumber: number;
|
|
97
|
+
}>;
|
|
98
|
+
}>;
|
|
99
|
+
pageInfo: {
|
|
100
|
+
nextCursor?: string | null;
|
|
101
|
+
prevCursor?: string | null;
|
|
102
|
+
hasMoreAfter: boolean;
|
|
103
|
+
hasMoreBefore: boolean;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
} | null;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Map internal pagination direction to GraphQL enum
|
|
111
|
+
*/
|
|
112
|
+
function mapDirection(
|
|
113
|
+
direction?: PaginationDirection,
|
|
114
|
+
): 'FORWARD' | 'BACKWARD' | undefined {
|
|
115
|
+
if (!direction) return undefined;
|
|
116
|
+
return direction === 'forward' ? 'FORWARD' : 'BACKWARD';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get paginated passages for a translation work.
|
|
121
|
+
*
|
|
122
|
+
* NOTE: maxCharacters is not supported by the GraphQL API yet.
|
|
123
|
+
* This parameter is accepted for API compatibility but is ignored.
|
|
124
|
+
*/
|
|
125
|
+
export async function getTranslationPassages({
|
|
126
|
+
client,
|
|
127
|
+
uuid,
|
|
128
|
+
type,
|
|
129
|
+
cursor,
|
|
130
|
+
maxPassages = 100,
|
|
131
|
+
maxCharacters: _maxCharacters,
|
|
132
|
+
direction,
|
|
133
|
+
}: {
|
|
134
|
+
client: GraphQLClient;
|
|
135
|
+
uuid: string;
|
|
136
|
+
type?: BodyItemType;
|
|
137
|
+
cursor?: string;
|
|
138
|
+
maxPassages?: number;
|
|
139
|
+
maxCharacters?: number;
|
|
140
|
+
direction?: PaginationDirection;
|
|
141
|
+
}): Promise<PassagesPage> {
|
|
142
|
+
try {
|
|
143
|
+
const response = await client.request<GetPassagesResponse>(GET_PASSAGES, {
|
|
144
|
+
uuid,
|
|
145
|
+
cursor,
|
|
146
|
+
limit: maxPassages,
|
|
147
|
+
direction: mapDirection(direction),
|
|
148
|
+
filter: type ? { type } : undefined,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
if (!response.work) {
|
|
152
|
+
return {
|
|
153
|
+
passages: [],
|
|
154
|
+
hasMoreAfter: false,
|
|
155
|
+
hasMoreBefore: false,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return passagesPageFromGraphQL(response.work.passages, response.work.uuid);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('Error fetching translation passages:', error);
|
|
162
|
+
return {
|
|
163
|
+
passages: [],
|
|
164
|
+
hasMoreAfter: false,
|
|
165
|
+
hasMoreBefore: false,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { Titles } from '@eightyfourthousand/data-access';
|
|
4
|
+
import { titlesFromGraphQL } from '../mappers';
|
|
5
|
+
|
|
6
|
+
const GET_WORK_TITLES = gql`
|
|
7
|
+
query GetWorkWithTitles($uuid: ID!) {
|
|
8
|
+
work(uuid: $uuid) {
|
|
9
|
+
titles {
|
|
10
|
+
uuid
|
|
11
|
+
content
|
|
12
|
+
language
|
|
13
|
+
type
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
type GetWorkTitlesResponse = {
|
|
20
|
+
work: {
|
|
21
|
+
titles: Array<{
|
|
22
|
+
uuid: string;
|
|
23
|
+
content: string;
|
|
24
|
+
language: string;
|
|
25
|
+
type: string;
|
|
26
|
+
}>;
|
|
27
|
+
} | null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get all titles for a work.
|
|
32
|
+
*/
|
|
33
|
+
export async function getTranslationTitles({
|
|
34
|
+
client,
|
|
35
|
+
uuid,
|
|
36
|
+
}: {
|
|
37
|
+
client: GraphQLClient;
|
|
38
|
+
uuid: string;
|
|
39
|
+
}): Promise<Titles> {
|
|
40
|
+
try {
|
|
41
|
+
const response = await client.request<GetWorkTitlesResponse>(
|
|
42
|
+
GET_WORK_TITLES,
|
|
43
|
+
{ uuid },
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (!response.work) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return titlesFromGraphQL(response.work.titles);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('Error fetching translation titles:', error);
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { Toc } from '@eightyfourthousand/data-access';
|
|
4
|
+
import { tocFromGraphQL } from '../mappers';
|
|
5
|
+
|
|
6
|
+
const GET_WORK_WITH_TOC = gql`
|
|
7
|
+
fragment TocEntryFields on TocEntry {
|
|
8
|
+
uuid
|
|
9
|
+
content
|
|
10
|
+
label
|
|
11
|
+
sort
|
|
12
|
+
level
|
|
13
|
+
section
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fragment TocEntryNested on TocEntry {
|
|
17
|
+
...TocEntryFields
|
|
18
|
+
children {
|
|
19
|
+
...TocEntryFields
|
|
20
|
+
children {
|
|
21
|
+
...TocEntryFields
|
|
22
|
+
children {
|
|
23
|
+
...TocEntryFields
|
|
24
|
+
children {
|
|
25
|
+
...TocEntryFields
|
|
26
|
+
children {
|
|
27
|
+
...TocEntryFields
|
|
28
|
+
children {
|
|
29
|
+
...TocEntryFields
|
|
30
|
+
children {
|
|
31
|
+
...TocEntryFields
|
|
32
|
+
children {
|
|
33
|
+
...TocEntryFields
|
|
34
|
+
children {
|
|
35
|
+
...TocEntryFields
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fragment TocFields on Toc {
|
|
48
|
+
frontMatter {
|
|
49
|
+
...TocEntryNested
|
|
50
|
+
}
|
|
51
|
+
body {
|
|
52
|
+
...TocEntryNested
|
|
53
|
+
}
|
|
54
|
+
backMatter {
|
|
55
|
+
...TocEntryNested
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
query GetWorkWithToc($uuid: ID!) {
|
|
60
|
+
work(uuid: $uuid) {
|
|
61
|
+
uuid
|
|
62
|
+
toc {
|
|
63
|
+
...TocFields
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
type GetWorkWithTocResponse = {
|
|
70
|
+
work: {
|
|
71
|
+
uuid: string;
|
|
72
|
+
toc: {
|
|
73
|
+
frontMatter: TocEntryNode[];
|
|
74
|
+
body: TocEntryNode[];
|
|
75
|
+
backMatter: TocEntryNode[];
|
|
76
|
+
} | null;
|
|
77
|
+
} | null;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
type TocEntryNode = {
|
|
81
|
+
uuid: string;
|
|
82
|
+
content: string;
|
|
83
|
+
label?: string | null;
|
|
84
|
+
sort: number;
|
|
85
|
+
level: number;
|
|
86
|
+
section: string;
|
|
87
|
+
children?: TocEntryNode[] | null;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get the table of contents for a translation work.
|
|
92
|
+
*/
|
|
93
|
+
export async function getTranslationToc({
|
|
94
|
+
client,
|
|
95
|
+
uuid,
|
|
96
|
+
}: {
|
|
97
|
+
client: GraphQLClient;
|
|
98
|
+
uuid: string;
|
|
99
|
+
}): Promise<Toc | undefined> {
|
|
100
|
+
try {
|
|
101
|
+
const response = await client.request<GetWorkWithTocResponse>(
|
|
102
|
+
GET_WORK_WITH_TOC,
|
|
103
|
+
{ uuid },
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
if (!response.work?.toc) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return tocFromGraphQL(response.work.toc);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('Error fetching translation TOC:', error);
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_PAGE_SIZE = 200;
|
|
5
|
+
|
|
6
|
+
const GET_WORK_UUIDS = gql`
|
|
7
|
+
query GetWorkUuids($cursor: String, $limit: Int, $filter: WorkFilter) {
|
|
8
|
+
works(cursor: $cursor, limit: $limit, filter: $filter) {
|
|
9
|
+
items {
|
|
10
|
+
uuid
|
|
11
|
+
}
|
|
12
|
+
pageInfo {
|
|
13
|
+
nextCursor
|
|
14
|
+
hasMoreAfter
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
type GetWorkUuidsResponse = {
|
|
21
|
+
works: {
|
|
22
|
+
items: Array<{ uuid: string }>;
|
|
23
|
+
pageInfo: {
|
|
24
|
+
nextCursor: string | null;
|
|
25
|
+
hasMoreAfter: boolean;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type WorkFilter = {
|
|
31
|
+
maxPages?: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get work UUIDs with optional filtering.
|
|
36
|
+
* @param client - GraphQL client
|
|
37
|
+
* @param filter - Optional filter criteria (e.g., maxPages)
|
|
38
|
+
* @param limit - Optional limit on total results (fetches all pages if not specified)
|
|
39
|
+
*/
|
|
40
|
+
export async function getTranslationUuids({
|
|
41
|
+
client,
|
|
42
|
+
filter,
|
|
43
|
+
limit,
|
|
44
|
+
}: {
|
|
45
|
+
client: GraphQLClient;
|
|
46
|
+
filter?: WorkFilter;
|
|
47
|
+
limit?: number;
|
|
48
|
+
}): Promise<string[]> {
|
|
49
|
+
try {
|
|
50
|
+
// Single request - no pagination needed for static params
|
|
51
|
+
const response: GetWorkUuidsResponse =
|
|
52
|
+
await client.request<GetWorkUuidsResponse>(GET_WORK_UUIDS, {
|
|
53
|
+
cursor: null,
|
|
54
|
+
limit: limit ?? DEFAULT_PAGE_SIZE,
|
|
55
|
+
filter,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return response.works.items.map((w) => w.uuid);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error('Error fetching translation UUIDs:', error);
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { Work } from '@eightyfourthousand/data-access';
|
|
4
|
+
import { worksFromGraphQL } from '../mappers';
|
|
5
|
+
|
|
6
|
+
const GET_ALL_WORKS = gql`
|
|
7
|
+
query GetAllWorks($cursor: String, $limit: Int) {
|
|
8
|
+
works(cursor: $cursor, limit: $limit) {
|
|
9
|
+
items {
|
|
10
|
+
uuid
|
|
11
|
+
title
|
|
12
|
+
toh
|
|
13
|
+
publicationDate
|
|
14
|
+
publicationVersion
|
|
15
|
+
pages
|
|
16
|
+
restriction
|
|
17
|
+
section
|
|
18
|
+
}
|
|
19
|
+
pageInfo {
|
|
20
|
+
nextCursor
|
|
21
|
+
hasMoreAfter
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
type GraphQLWork = {
|
|
28
|
+
uuid: string;
|
|
29
|
+
title: string;
|
|
30
|
+
toh: string[];
|
|
31
|
+
publicationDate: string;
|
|
32
|
+
publicationVersion: string;
|
|
33
|
+
pages: number;
|
|
34
|
+
restriction: boolean;
|
|
35
|
+
section: string;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type GetAllWorksResponse = {
|
|
39
|
+
works: {
|
|
40
|
+
items: GraphQLWork[];
|
|
41
|
+
pageInfo: {
|
|
42
|
+
nextCursor: string | null;
|
|
43
|
+
hasMoreAfter: boolean;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get metadata for all published translation works (fetches all pages).
|
|
50
|
+
*/
|
|
51
|
+
export async function getTranslationsMetadata({
|
|
52
|
+
client,
|
|
53
|
+
limit = 200,
|
|
54
|
+
}: {
|
|
55
|
+
client: GraphQLClient;
|
|
56
|
+
limit?: number;
|
|
57
|
+
}): Promise<Work[]> {
|
|
58
|
+
try {
|
|
59
|
+
const allWorks: GraphQLWork[] = [];
|
|
60
|
+
let cursor: string | null = null;
|
|
61
|
+
|
|
62
|
+
// Fetch all pages
|
|
63
|
+
do {
|
|
64
|
+
const response: GetAllWorksResponse =
|
|
65
|
+
await client.request<GetAllWorksResponse>(GET_ALL_WORKS, {
|
|
66
|
+
cursor,
|
|
67
|
+
limit,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
allWorks.push(...response.works.items);
|
|
71
|
+
cursor = response.works.pageInfo.hasMoreAfter
|
|
72
|
+
? response.works.pageInfo.nextCursor
|
|
73
|
+
: null;
|
|
74
|
+
} while (cursor !== null);
|
|
75
|
+
|
|
76
|
+
return worksFromGraphQL(allWorks);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('Error fetching translations metadata:', error);
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { BibliographyEntries } from '@eightyfourthousand/data-access';
|
|
4
|
+
|
|
5
|
+
const GET_WORK_BIBLIOGRAPHY = gql`
|
|
6
|
+
query GetWorkBibliography($uuid: ID!) {
|
|
7
|
+
work(uuid: $uuid) {
|
|
8
|
+
bibliography {
|
|
9
|
+
heading
|
|
10
|
+
entries {
|
|
11
|
+
uuid
|
|
12
|
+
html
|
|
13
|
+
workUuid
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
type GetWorkBibliographyResponse = {
|
|
21
|
+
work: {
|
|
22
|
+
bibliography: BibliographyEntries;
|
|
23
|
+
} | null;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get bibliography entries for a specific work.
|
|
28
|
+
*/
|
|
29
|
+
export async function getWorkBibliography({
|
|
30
|
+
client,
|
|
31
|
+
uuid,
|
|
32
|
+
}: {
|
|
33
|
+
client: GraphQLClient;
|
|
34
|
+
uuid: string;
|
|
35
|
+
}): Promise<BibliographyEntries> {
|
|
36
|
+
try {
|
|
37
|
+
const response = await client.request<GetWorkBibliographyResponse>(
|
|
38
|
+
GET_WORK_BIBLIOGRAPHY,
|
|
39
|
+
{ uuid },
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return response.work?.bibliography ?? [];
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Error fetching work bibliography:', error);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { Folio } from '@eightyfourthousand/data-access';
|
|
4
|
+
|
|
5
|
+
const GET_WORK_FOLIOS = gql`
|
|
6
|
+
query GetWorkFolios($uuid: ID!, $toh: String!, $page: Int, $size: Int) {
|
|
7
|
+
work(uuid: $uuid) {
|
|
8
|
+
folios(toh: $toh, page: $page, size: $size) {
|
|
9
|
+
uuid
|
|
10
|
+
content
|
|
11
|
+
volume
|
|
12
|
+
folio
|
|
13
|
+
side
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
type GetWorkFoliosResponse = {
|
|
20
|
+
work: {
|
|
21
|
+
folios: Folio[];
|
|
22
|
+
} | null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get folios for a specific work, filtered by toh and paginated.
|
|
27
|
+
*/
|
|
28
|
+
export async function getWorkFolios({
|
|
29
|
+
client,
|
|
30
|
+
uuid,
|
|
31
|
+
toh,
|
|
32
|
+
page = 0,
|
|
33
|
+
size = 10,
|
|
34
|
+
}: {
|
|
35
|
+
client: GraphQLClient;
|
|
36
|
+
uuid: string;
|
|
37
|
+
toh: string;
|
|
38
|
+
page?: number;
|
|
39
|
+
size?: number;
|
|
40
|
+
}): Promise<Folio[]> {
|
|
41
|
+
try {
|
|
42
|
+
const response = await client.request<GetWorkFoliosResponse>(
|
|
43
|
+
GET_WORK_FOLIOS,
|
|
44
|
+
{ uuid, toh, page, size },
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
return response.work?.folios ?? [];
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Error fetching work folios:', error);
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { GlossaryTermInstance } from '@eightyfourthousand/data-access';
|
|
4
|
+
import type { GlossaryTermsPage } from './get-work-glossary-terms';
|
|
5
|
+
|
|
6
|
+
const GET_WORK_GLOSSARY_TERMS_AROUND = gql`
|
|
7
|
+
query GetWorkGlossaryTermsAround(
|
|
8
|
+
$uuid: ID!
|
|
9
|
+
$cursor: String!
|
|
10
|
+
$limit: Int
|
|
11
|
+
$withAttestations: Boolean
|
|
12
|
+
) {
|
|
13
|
+
work(uuid: $uuid) {
|
|
14
|
+
glossaryTerms(
|
|
15
|
+
cursor: $cursor
|
|
16
|
+
limit: $limit
|
|
17
|
+
direction: AROUND
|
|
18
|
+
withAttestations: $withAttestations
|
|
19
|
+
) {
|
|
20
|
+
nodes {
|
|
21
|
+
uuid
|
|
22
|
+
authority
|
|
23
|
+
definition
|
|
24
|
+
termNumber
|
|
25
|
+
names {
|
|
26
|
+
english
|
|
27
|
+
tibetan
|
|
28
|
+
sanskrit
|
|
29
|
+
pali
|
|
30
|
+
chinese
|
|
31
|
+
wylie
|
|
32
|
+
}
|
|
33
|
+
passages(first: 10) {
|
|
34
|
+
items {
|
|
35
|
+
uuid
|
|
36
|
+
type
|
|
37
|
+
label
|
|
38
|
+
}
|
|
39
|
+
nextCursor
|
|
40
|
+
hasMore
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
pageInfo {
|
|
44
|
+
nextCursor
|
|
45
|
+
prevCursor
|
|
46
|
+
hasMoreAfter
|
|
47
|
+
hasMoreBefore
|
|
48
|
+
}
|
|
49
|
+
totalCount
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
type GetWorkGlossaryTermsAroundResponse = {
|
|
56
|
+
work: {
|
|
57
|
+
glossaryTerms: {
|
|
58
|
+
nodes: GlossaryTermInstance[];
|
|
59
|
+
pageInfo: {
|
|
60
|
+
nextCursor?: string | null;
|
|
61
|
+
prevCursor?: string | null;
|
|
62
|
+
hasMoreAfter: boolean;
|
|
63
|
+
hasMoreBefore: boolean;
|
|
64
|
+
};
|
|
65
|
+
totalCount: number;
|
|
66
|
+
};
|
|
67
|
+
} | null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get glossary terms around a specific term UUID.
|
|
72
|
+
* Used for navigating to a glossary entry that hasn't been loaded yet.
|
|
73
|
+
*/
|
|
74
|
+
export async function getWorkGlossaryTermsAround({
|
|
75
|
+
client,
|
|
76
|
+
uuid,
|
|
77
|
+
termUuid,
|
|
78
|
+
limit,
|
|
79
|
+
withAttestations = false,
|
|
80
|
+
}: {
|
|
81
|
+
client: GraphQLClient;
|
|
82
|
+
uuid: string;
|
|
83
|
+
termUuid: string;
|
|
84
|
+
limit?: number;
|
|
85
|
+
withAttestations?: boolean;
|
|
86
|
+
}): Promise<GlossaryTermsPage> {
|
|
87
|
+
try {
|
|
88
|
+
const response = await client.request<GetWorkGlossaryTermsAroundResponse>(
|
|
89
|
+
GET_WORK_GLOSSARY_TERMS_AROUND,
|
|
90
|
+
{
|
|
91
|
+
uuid,
|
|
92
|
+
cursor: termUuid,
|
|
93
|
+
limit,
|
|
94
|
+
withAttestations,
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (!response.work) {
|
|
99
|
+
return {
|
|
100
|
+
terms: [],
|
|
101
|
+
hasMoreAfter: false,
|
|
102
|
+
hasMoreBefore: false,
|
|
103
|
+
totalCount: 0,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const { glossaryTerms } = response.work;
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
terms: glossaryTerms.nodes,
|
|
111
|
+
nextCursor: glossaryTerms.pageInfo.nextCursor ?? undefined,
|
|
112
|
+
prevCursor: glossaryTerms.pageInfo.prevCursor ?? undefined,
|
|
113
|
+
hasMoreAfter: glossaryTerms.pageInfo.hasMoreAfter,
|
|
114
|
+
hasMoreBefore: glossaryTerms.pageInfo.hasMoreBefore,
|
|
115
|
+
totalCount: glossaryTerms.totalCount,
|
|
116
|
+
};
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('Error fetching glossary terms around:', error);
|
|
119
|
+
return {
|
|
120
|
+
terms: [],
|
|
121
|
+
hasMoreAfter: false,
|
|
122
|
+
hasMoreBefore: false,
|
|
123
|
+
totalCount: 0,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|