@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,150 @@
1
+ import type { GraphQLClient } from 'graphql-request';
2
+ import { gql } from 'graphql-request';
3
+ import type { GlossaryTermInstance, PaginationDirection } from '@eightyfourthousand/data-access';
4
+
5
+ const GET_WORK_GLOSSARY_TERMS = gql`
6
+ query GetWorkGlossaryTerms(
7
+ $uuid: ID!
8
+ $cursor: String
9
+ $limit: Int
10
+ $direction: PaginationDirection
11
+ $withAttestations: Boolean
12
+ ) {
13
+ work(uuid: $uuid) {
14
+ glossaryTerms(
15
+ cursor: $cursor
16
+ limit: $limit
17
+ direction: $direction
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 GetWorkGlossaryTermsResponse = {
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
+ * Result of fetching glossary terms with pagination info
72
+ */
73
+ export type GlossaryTermsPage = {
74
+ terms: GlossaryTermInstance[];
75
+ nextCursor?: string;
76
+ prevCursor?: string;
77
+ hasMoreAfter: boolean;
78
+ hasMoreBefore: boolean;
79
+ totalCount: number;
80
+ };
81
+
82
+ /**
83
+ * Map internal pagination direction to GraphQL enum
84
+ */
85
+ function mapDirection(
86
+ direction?: PaginationDirection,
87
+ ): 'FORWARD' | 'BACKWARD' | undefined {
88
+ if (!direction) return undefined;
89
+ return direction === 'forward' ? 'FORWARD' : 'BACKWARD';
90
+ }
91
+
92
+ /**
93
+ * Get paginated glossary terms for a work.
94
+ */
95
+ export async function getWorkGlossaryTerms({
96
+ client,
97
+ uuid,
98
+ cursor,
99
+ limit = 50,
100
+ direction,
101
+ withAttestations = false,
102
+ }: {
103
+ client: GraphQLClient;
104
+ uuid: string;
105
+ cursor?: string;
106
+ limit?: number;
107
+ direction?: PaginationDirection;
108
+ withAttestations?: boolean;
109
+ }): Promise<GlossaryTermsPage> {
110
+ try {
111
+ const response = await client.request<GetWorkGlossaryTermsResponse>(
112
+ GET_WORK_GLOSSARY_TERMS,
113
+ {
114
+ uuid,
115
+ cursor,
116
+ limit,
117
+ direction: mapDirection(direction),
118
+ withAttestations,
119
+ },
120
+ );
121
+
122
+ if (!response.work) {
123
+ return {
124
+ terms: [],
125
+ hasMoreAfter: false,
126
+ hasMoreBefore: false,
127
+ totalCount: 0,
128
+ };
129
+ }
130
+
131
+ const { glossaryTerms } = response.work;
132
+
133
+ return {
134
+ terms: glossaryTerms.nodes,
135
+ nextCursor: glossaryTerms.pageInfo.nextCursor ?? undefined,
136
+ prevCursor: glossaryTerms.pageInfo.prevCursor ?? undefined,
137
+ hasMoreAfter: glossaryTerms.pageInfo.hasMoreAfter,
138
+ hasMoreBefore: glossaryTerms.pageInfo.hasMoreBefore,
139
+ totalCount: glossaryTerms.totalCount,
140
+ };
141
+ } catch (error) {
142
+ console.error('Error fetching work glossary terms:', error);
143
+ return {
144
+ terms: [],
145
+ hasMoreAfter: false,
146
+ hasMoreBefore: false,
147
+ totalCount: 0,
148
+ };
149
+ }
150
+ }
@@ -0,0 +1,54 @@
1
+ import type { GraphQLClient } from 'graphql-request';
2
+ import { gql } from 'graphql-request';
3
+ import type { GlossaryTermInstance } from '@eightyfourthousand/data-access';
4
+
5
+ const GET_WORK_GLOSSARY = gql`
6
+ query GetWorkGlossary($uuid: ID!, $withAttestations: Boolean) {
7
+ work(uuid: $uuid) {
8
+ glossary(withAttestations: $withAttestations) {
9
+ uuid
10
+ authority
11
+ definition
12
+ names {
13
+ english
14
+ tibetan
15
+ sanskrit
16
+ pali
17
+ chinese
18
+ wylie
19
+ }
20
+ }
21
+ }
22
+ }
23
+ `;
24
+
25
+ type GetWorkGlossaryResponse = {
26
+ work: {
27
+ glossary: GlossaryTermInstance[];
28
+ } | null;
29
+ };
30
+
31
+ /**
32
+ * Get glossary term instances for a specific work.
33
+ */
34
+ export async function getWorkGlossary({
35
+ client,
36
+ uuid,
37
+ withAttestations = false,
38
+ }: {
39
+ client: GraphQLClient;
40
+ uuid: string;
41
+ withAttestations?: boolean;
42
+ }): Promise<GlossaryTermInstance[]> {
43
+ try {
44
+ const response = await client.request<GetWorkGlossaryResponse>(
45
+ GET_WORK_GLOSSARY,
46
+ { uuid, withAttestations },
47
+ );
48
+
49
+ return response.work?.glossary ?? [];
50
+ } catch (error) {
51
+ console.error('Error fetching work glossary:', error);
52
+ return [];
53
+ }
54
+ }
@@ -0,0 +1,111 @@
1
+ import type { GraphQLClient } from 'graphql-request';
2
+ import { gql } from 'graphql-request';
3
+ import type { Work } from '@eightyfourthousand/data-access';
4
+
5
+ const GET_WORKS = gql`
6
+ query GetWorks($cursor: String, $limit: Int) {
7
+ works(cursor: $cursor, limit: $limit) {
8
+ items {
9
+ uuid
10
+ title
11
+ toh
12
+ publicationDate
13
+ publicationVersion
14
+ pages
15
+ restriction
16
+ section
17
+ }
18
+ pageInfo {
19
+ nextCursor
20
+ prevCursor
21
+ hasMoreAfter
22
+ hasMoreBefore
23
+ }
24
+ totalCount
25
+ }
26
+ }
27
+ `;
28
+
29
+ type GraphQLWork = {
30
+ uuid: string;
31
+ title: string;
32
+ toh: string[];
33
+ publicationDate: string;
34
+ publicationVersion: string;
35
+ pages: number;
36
+ restriction: boolean;
37
+ section: string;
38
+ };
39
+
40
+ type PageInfo = {
41
+ nextCursor: string | null;
42
+ prevCursor: string | null;
43
+ hasMoreAfter: boolean;
44
+ hasMoreBefore: boolean;
45
+ };
46
+
47
+ type GetWorksResponse = {
48
+ works: {
49
+ items: GraphQLWork[];
50
+ pageInfo: PageInfo;
51
+ totalCount: number;
52
+ };
53
+ };
54
+
55
+ export type WorksPage = {
56
+ items: Work[];
57
+ pageInfo: PageInfo;
58
+ totalCount: number;
59
+ };
60
+
61
+ function workFromGraphQL(gqlWork: GraphQLWork): Work {
62
+ return {
63
+ uuid: gqlWork.uuid,
64
+ title: gqlWork.title,
65
+ toh: gqlWork.toh as Work['toh'],
66
+ publicationDate: new Date(gqlWork.publicationDate),
67
+ publicationVersion:
68
+ gqlWork.publicationVersion as Work['publicationVersion'],
69
+ pages: gqlWork.pages,
70
+ restriction: gqlWork.restriction,
71
+ section: gqlWork.section,
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Get paginated works.
77
+ */
78
+ export async function getWorks({
79
+ client,
80
+ cursor,
81
+ limit = 50,
82
+ }: {
83
+ client: GraphQLClient;
84
+ cursor?: string;
85
+ limit?: number;
86
+ }): Promise<WorksPage> {
87
+ try {
88
+ const response = await client.request<GetWorksResponse>(GET_WORKS, {
89
+ cursor,
90
+ limit,
91
+ });
92
+
93
+ return {
94
+ items: response.works.items.map(workFromGraphQL),
95
+ pageInfo: response.works.pageInfo,
96
+ totalCount: response.works.totalCount,
97
+ };
98
+ } catch (error) {
99
+ console.error('Error fetching works:', error);
100
+ return {
101
+ items: [],
102
+ pageInfo: {
103
+ nextCursor: null,
104
+ prevCursor: null,
105
+ hasMoreAfter: false,
106
+ hasMoreBefore: false,
107
+ },
108
+ totalCount: 0,
109
+ };
110
+ }
111
+ }
@@ -0,0 +1,38 @@
1
+ import type { GraphQLClient } from 'graphql-request';
2
+ import { gql } from 'graphql-request';
3
+
4
+ // Permission enum matching the GraphQL schema
5
+ export type Permission =
6
+ | 'PROJECTS_READ'
7
+ | 'PROJECTS_EDIT'
8
+ | 'PROJECTS_ADMIN'
9
+ | 'EDITOR_READ'
10
+ | 'EDITOR_EDIT'
11
+ | 'EDITOR_ADMIN';
12
+
13
+ const HAS_PERMISSION_QUERY = gql`
14
+ query HasPermission($permission: Permission!) {
15
+ hasPermission(permission: $permission)
16
+ }
17
+ `;
18
+
19
+ interface HasPermissionResponse {
20
+ hasPermission: boolean;
21
+ }
22
+
23
+ /**
24
+ * Check if the current user has a specific permission
25
+ */
26
+ export const hasPermission = async ({
27
+ client,
28
+ permission,
29
+ }: {
30
+ client: GraphQLClient;
31
+ permission: Permission;
32
+ }): Promise<boolean> => {
33
+ const response = await client.request<HasPermissionResponse>(
34
+ HAS_PERMISSION_QUERY,
35
+ { permission },
36
+ );
37
+ return response.hasPermission;
38
+ };
@@ -0,0 +1,33 @@
1
+ export { getPassage } from './get-passage';
2
+ export { getTranslationPassages } from './get-translation-passages';
3
+ export { getTranslationPassagesAround } from './get-translation-passages-around';
4
+ export {
5
+ getTranslationBlocks,
6
+ type TranslationBlocksPage,
7
+ } from './get-translation-blocks';
8
+ export { getTranslationBlocksAround } from './get-translation-blocks-around';
9
+ export { getTranslationTitles } from './get-translation-titles';
10
+ export {
11
+ getTranslationMetadataByUuid,
12
+ getTranslationMetadataByToh,
13
+ } from './get-translation-metadata';
14
+ export { getTranslationsMetadata } from './get-translations-metadata';
15
+ export { getTranslationUuids } from './get-translation-uuids';
16
+ export { getTranslationToc } from './get-translation-toc';
17
+ export { getTranslationImprint } from './get-translation-imprint';
18
+ export { getGlossaryTerms } from './get-glossary-terms';
19
+ export { getGlossaryEntry } from './get-glossary-entry';
20
+ export { getGlossaryInstance } from './get-glossary-instance';
21
+ export { getWorkGlossary } from './get-work-glossary';
22
+ export {
23
+ getWorkGlossaryTerms,
24
+ type GlossaryTermsPage,
25
+ } from './get-work-glossary-terms';
26
+ export { getWorkGlossaryTermsAround } from './get-work-glossary-terms-around';
27
+ export { getTermPassages, type GlossaryPassagesPage } from './get-term-passages';
28
+ export { getBibliographyEntry } from './get-bibliography-entry';
29
+ export { getWorkBibliography } from './get-work-bibliography';
30
+ export { getWorkFolios } from './get-work-folios';
31
+ export { getWorks, type WorksPage } from './get-works';
32
+ export { hasPermission, type Permission } from './has-permission';
33
+ export { savePassages } from './save-passages';
@@ -0,0 +1,76 @@
1
+ import type { GraphQLClient } from 'graphql-request';
2
+ import { gql } from 'graphql-request';
3
+ import type { Passage } from '@eightyfourthousand/data-access';
4
+
5
+ const SAVE_PASSAGES_MUTATION = gql`
6
+ mutation SavePassages($passages: [PassageInput!]!, $deletedUuids: [ID!]) {
7
+ savePassages(passages: $passages, deletedUuids: $deletedUuids) {
8
+ success
9
+ savedCount
10
+ deletedCount
11
+ error
12
+ }
13
+ }
14
+ `;
15
+
16
+ interface SavePassagesResponse {
17
+ savePassages: {
18
+ success: boolean;
19
+ savedCount: number;
20
+ deletedCount?: number;
21
+ error?: string;
22
+ };
23
+ }
24
+
25
+ interface PassageInput {
26
+ uuid: string;
27
+ workUuid: string;
28
+ content: string;
29
+ label: string;
30
+ sort: number;
31
+ type: string;
32
+ xmlId?: string;
33
+ annotations: unknown[];
34
+ }
35
+
36
+ /**
37
+ * Convert a Passage to the GraphQL input format
38
+ */
39
+ const passageToInput = (passage: Passage): PassageInput => ({
40
+ uuid: passage.uuid,
41
+ workUuid: passage.workUuid,
42
+ content: passage.content,
43
+ label: passage.label,
44
+ sort: passage.sort,
45
+ type: passage.type,
46
+ xmlId: passage.xmlId,
47
+ annotations: passage.annotations,
48
+ });
49
+
50
+ /**
51
+ * Save one or more passages via GraphQL mutation.
52
+ * Requires editor.edit permission.
53
+ */
54
+ export const savePassages = async ({
55
+ client,
56
+ passages,
57
+ deletedUuids,
58
+ }: {
59
+ client: GraphQLClient;
60
+ passages: Passage[];
61
+ deletedUuids?: string[];
62
+ }): Promise<{
63
+ success: boolean;
64
+ savedCount: number;
65
+ deletedCount?: number;
66
+ error?: string;
67
+ }> => {
68
+ const passageInputs = passages.map(passageToInput);
69
+
70
+ const response = await client.request<SavePassagesResponse>(
71
+ SAVE_PASSAGES_MUTATION,
72
+ { passages: passageInputs, deletedUuids },
73
+ );
74
+
75
+ return response.savePassages;
76
+ };