@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
package/codegen.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CodegenConfig } from '@graphql-codegen/cli';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
// Resolve paths from repo root
|
|
5
|
+
const repoRoot = join(__dirname, '../..');
|
|
6
|
+
const schemaPath = join(repoRoot, 'apps/api-graphql/src/graphql/schema/**/*.graphql');
|
|
7
|
+
const documentsPath = join(__dirname, 'src/lib/graphql/**/*.graphql');
|
|
8
|
+
const outputPath = join(__dirname, 'src/lib/generated/graphql.ts');
|
|
9
|
+
|
|
10
|
+
const config: CodegenConfig = {
|
|
11
|
+
schema: schemaPath,
|
|
12
|
+
documents: documentsPath,
|
|
13
|
+
generates: {
|
|
14
|
+
[outputPath]: {
|
|
15
|
+
plugins: [
|
|
16
|
+
'typescript',
|
|
17
|
+
'typescript-operations',
|
|
18
|
+
'typescript-graphql-request',
|
|
19
|
+
],
|
|
20
|
+
config: {
|
|
21
|
+
rawRequest: false,
|
|
22
|
+
inlineFragmentTypes: 'combine',
|
|
23
|
+
skipTypename: false,
|
|
24
|
+
exportFragmentSpreadSubTypes: true,
|
|
25
|
+
dedupeFragments: true,
|
|
26
|
+
enumsAsTypes: true,
|
|
27
|
+
useTypeImports: true,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
ignoreNoDocuments: false,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default config;
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eightyfourthousand/client-graphql",
|
|
3
|
+
"version": "2026.3.0",
|
|
4
|
+
"description": "GraphQL client helpers and typed query functions for 84000 applications.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/84000/84000-apps.git",
|
|
9
|
+
"directory": "libs/client-graphql"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/84000/84000-apps",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/84000/84000-apps/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@eightyfourthousand/data-access": "^2026.3.0"
|
|
21
|
+
},
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"keywords": [],
|
|
24
|
+
"author": ""
|
|
25
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "client-graphql",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "libs/client-graphql/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "@nx/js:tsc",
|
|
10
|
+
"outputs": ["{options.outputPath}"],
|
|
11
|
+
"options": {
|
|
12
|
+
"outputPath": "dist/libs/client-graphql",
|
|
13
|
+
"main": "libs/client-graphql/src/index.ts",
|
|
14
|
+
"tsConfig": "libs/client-graphql/tsconfig.lib.json",
|
|
15
|
+
"rootDir": "libs/client-graphql/src",
|
|
16
|
+
"generateExportsField": true,
|
|
17
|
+
"additionalEntryPoints": ["libs/client-graphql/src/ssr.ts"]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Client
|
|
2
|
+
export {
|
|
3
|
+
createGraphQLClient,
|
|
4
|
+
resetGraphQLClient,
|
|
5
|
+
setAccessTokenProvider,
|
|
6
|
+
} from './lib/client';
|
|
7
|
+
|
|
8
|
+
// Functions
|
|
9
|
+
export {
|
|
10
|
+
getPassage,
|
|
11
|
+
getTranslationPassages,
|
|
12
|
+
getTranslationPassagesAround,
|
|
13
|
+
getTranslationBlocks,
|
|
14
|
+
getTranslationBlocksAround,
|
|
15
|
+
getTranslationTitles,
|
|
16
|
+
getTranslationMetadataByUuid,
|
|
17
|
+
getTranslationMetadataByToh,
|
|
18
|
+
getTranslationsMetadata,
|
|
19
|
+
getTranslationUuids,
|
|
20
|
+
getTranslationToc,
|
|
21
|
+
getTranslationImprint,
|
|
22
|
+
getGlossaryTerms,
|
|
23
|
+
getGlossaryEntry,
|
|
24
|
+
getGlossaryInstance,
|
|
25
|
+
getWorkGlossary,
|
|
26
|
+
getWorkGlossaryTerms,
|
|
27
|
+
getWorkGlossaryTermsAround,
|
|
28
|
+
type GlossaryTermsPage,
|
|
29
|
+
getTermPassages,
|
|
30
|
+
type GlossaryPassagesPage,
|
|
31
|
+
getBibliographyEntry,
|
|
32
|
+
getWorkBibliography,
|
|
33
|
+
getWorkFolios,
|
|
34
|
+
getWorks,
|
|
35
|
+
hasPermission,
|
|
36
|
+
savePassages,
|
|
37
|
+
type TranslationBlocksPage,
|
|
38
|
+
type WorksPage,
|
|
39
|
+
type Permission,
|
|
40
|
+
} from './lib/functions';
|
|
41
|
+
|
|
42
|
+
// Re-export types from @eightyfourthousand/data-access for convenience
|
|
43
|
+
export type {
|
|
44
|
+
Passage,
|
|
45
|
+
Passages,
|
|
46
|
+
PassagesPage,
|
|
47
|
+
PaginationDirection,
|
|
48
|
+
BodyItemType,
|
|
49
|
+
Annotation,
|
|
50
|
+
Annotations,
|
|
51
|
+
Alignment,
|
|
52
|
+
Work,
|
|
53
|
+
Title,
|
|
54
|
+
Titles,
|
|
55
|
+
TitleType,
|
|
56
|
+
Toc,
|
|
57
|
+
TocEntry,
|
|
58
|
+
Imprint,
|
|
59
|
+
GlossaryTermInstance,
|
|
60
|
+
GlossaryLandingItem,
|
|
61
|
+
GlossaryPageItem,
|
|
62
|
+
BibliographyEntry,
|
|
63
|
+
BibliographyEntryItem,
|
|
64
|
+
BibliographyEntries,
|
|
65
|
+
Folio,
|
|
66
|
+
} from '@eightyfourthousand/data-access';
|
|
67
|
+
|
|
68
|
+
// Re-export constants for passage filters
|
|
69
|
+
export {
|
|
70
|
+
BODY_ITEM_TYPES,
|
|
71
|
+
FRONT_MATTER,
|
|
72
|
+
FRONT_MATTER_FILTER,
|
|
73
|
+
BODY_MATTER,
|
|
74
|
+
BODY_MATTER_FILTER,
|
|
75
|
+
BACK_MATTER,
|
|
76
|
+
BACK_MATTER_FILTER,
|
|
77
|
+
COMPARE_MODE,
|
|
78
|
+
COMPARE_MODE_FILTER,
|
|
79
|
+
} from '@eightyfourthousand/data-access';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { GraphQLClient } from 'graphql-request';
|
|
3
|
+
import { cookies } from 'next/headers';
|
|
4
|
+
import { getGraphQLUrl } from './config';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create a GraphQL client for server-side requests (SSR/RSC).
|
|
8
|
+
* Reads auth cookies from the request and forwards them to the GraphQL API.
|
|
9
|
+
*
|
|
10
|
+
* Must be called within a Server Component or Server Action context.
|
|
11
|
+
*/
|
|
12
|
+
export async function createServerGraphQLClient(): Promise<GraphQLClient> {
|
|
13
|
+
const url = getGraphQLUrl();
|
|
14
|
+
|
|
15
|
+
// Get all cookies from the request
|
|
16
|
+
const cookieStore = await cookies();
|
|
17
|
+
const allCookies = cookieStore.getAll();
|
|
18
|
+
|
|
19
|
+
// Build cookie header string with encoded values to ensure HTTP header compatibility
|
|
20
|
+
// Cookie values may contain non-ASCII characters which are invalid in HTTP headers (ByteString)
|
|
21
|
+
const cookieHeader = allCookies
|
|
22
|
+
.map((cookie) => `${cookie.name}=${encodeURIComponent(cookie.value)}`)
|
|
23
|
+
.join('; ');
|
|
24
|
+
|
|
25
|
+
const client = new GraphQLClient(url, {
|
|
26
|
+
headers: {
|
|
27
|
+
// Forward cookies for authentication
|
|
28
|
+
...(cookieHeader ? { cookie: cookieHeader } : {}),
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return client;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a GraphQL client for build-time requests (generateStaticParams).
|
|
37
|
+
* Does not use cookies since there's no request context during builds.
|
|
38
|
+
*
|
|
39
|
+
* Use this in generateStaticParams and other build-time contexts.
|
|
40
|
+
*/
|
|
41
|
+
export function createBuildGraphQLClient(): GraphQLClient {
|
|
42
|
+
const url = getGraphQLUrl();
|
|
43
|
+
return new GraphQLClient(url);
|
|
44
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { getGraphQLUrl } from './config';
|
|
3
|
+
|
|
4
|
+
let clientInstance: GraphQLClient | null = null;
|
|
5
|
+
let getAccessToken: (() => Promise<string | null>) | null = null;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Set the access token provider function.
|
|
9
|
+
* This should be called once at app initialization.
|
|
10
|
+
*/
|
|
11
|
+
export function setAccessTokenProvider(
|
|
12
|
+
provider: () => Promise<string | null>
|
|
13
|
+
): void {
|
|
14
|
+
getAccessToken = provider;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a GraphQL client for browser-side requests.
|
|
19
|
+
* Uses Authorization header with dynamic token retrieval for cross-domain requests.
|
|
20
|
+
*/
|
|
21
|
+
export function createGraphQLClient(): GraphQLClient {
|
|
22
|
+
if (clientInstance) {
|
|
23
|
+
return clientInstance;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const url = getGraphQLUrl();
|
|
27
|
+
|
|
28
|
+
clientInstance = new GraphQLClient(url, {
|
|
29
|
+
// Dynamic headers - called on each request
|
|
30
|
+
requestMiddleware: async (request) => {
|
|
31
|
+
const headers: Record<string, string> = {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
'apollo-require-preflight': 'true',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if (getAccessToken) {
|
|
37
|
+
const token = await getAccessToken();
|
|
38
|
+
if (token) {
|
|
39
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
...request,
|
|
45
|
+
headers,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return clientInstance;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Reset the client instance (useful for testing)
|
|
55
|
+
*/
|
|
56
|
+
export function resetGraphQLClient(): void {
|
|
57
|
+
clientInstance = null;
|
|
58
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL API configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get the GraphQL API URL from environment variables
|
|
7
|
+
* Falls back to localhost for development
|
|
8
|
+
*/
|
|
9
|
+
export function getGraphQLUrl(): string {
|
|
10
|
+
const url = process.env.NEXT_PUBLIC_GRAPHQL_URL;
|
|
11
|
+
|
|
12
|
+
if (!url) {
|
|
13
|
+
// Default to localhost in development
|
|
14
|
+
if (process.env.NODE_ENV === 'development') {
|
|
15
|
+
return 'http://localhost:3001/api/graphql';
|
|
16
|
+
}
|
|
17
|
+
throw new Error('NEXT_PUBLIC_GRAPHQL_URL environment variable is not set');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return url;
|
|
21
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { BibliographyEntryItem } from '@eightyfourthousand/data-access';
|
|
4
|
+
|
|
5
|
+
const GET_BIBLIOGRAPHY_ENTRY = gql`
|
|
6
|
+
query GetBibliographyEntry($uuid: ID!) {
|
|
7
|
+
bibliographyEntry(uuid: $uuid) {
|
|
8
|
+
uuid
|
|
9
|
+
html
|
|
10
|
+
workUuid
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
type GetBibliographyEntryResponse = {
|
|
16
|
+
bibliographyEntry: BibliographyEntryItem | null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get a single bibliography entry by UUID.
|
|
21
|
+
*/
|
|
22
|
+
export async function getBibliographyEntry({
|
|
23
|
+
client,
|
|
24
|
+
uuid,
|
|
25
|
+
}: {
|
|
26
|
+
client: GraphQLClient;
|
|
27
|
+
uuid: string;
|
|
28
|
+
}): Promise<BibliographyEntryItem | null> {
|
|
29
|
+
try {
|
|
30
|
+
const response = await client.request<GetBibliographyEntryResponse>(
|
|
31
|
+
GET_BIBLIOGRAPHY_ENTRY,
|
|
32
|
+
{ uuid },
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return response.bibliographyEntry;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error('Error fetching bibliography entry:', error);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { GlossaryPageItem, TohokuCatalogEntry } from '@eightyfourthousand/data-access';
|
|
4
|
+
|
|
5
|
+
const GET_GLOSSARY_ENTRY = gql`
|
|
6
|
+
query GetGlossaryEntry($uuid: ID!) {
|
|
7
|
+
glossaryEntry(uuid: $uuid) {
|
|
8
|
+
authorityUuid
|
|
9
|
+
headword
|
|
10
|
+
language
|
|
11
|
+
classifications
|
|
12
|
+
definition
|
|
13
|
+
xmlId
|
|
14
|
+
english
|
|
15
|
+
tibetan
|
|
16
|
+
sanskrit
|
|
17
|
+
pali
|
|
18
|
+
chinese
|
|
19
|
+
relatedInstances {
|
|
20
|
+
workUuid
|
|
21
|
+
toh
|
|
22
|
+
definition
|
|
23
|
+
canon
|
|
24
|
+
english
|
|
25
|
+
tibetan
|
|
26
|
+
sanskrit
|
|
27
|
+
pali
|
|
28
|
+
chinese
|
|
29
|
+
creators
|
|
30
|
+
}
|
|
31
|
+
relatedEntities {
|
|
32
|
+
sourceHeadword
|
|
33
|
+
sourceUuid
|
|
34
|
+
targetHeadword
|
|
35
|
+
targetUuid
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
type GraphQLGlossaryEntry = {
|
|
42
|
+
authorityUuid: string;
|
|
43
|
+
headword: string;
|
|
44
|
+
language: string;
|
|
45
|
+
classifications: string[];
|
|
46
|
+
definition: string | null;
|
|
47
|
+
xmlId: string | null;
|
|
48
|
+
english: string[];
|
|
49
|
+
tibetan: string[];
|
|
50
|
+
sanskrit: string[];
|
|
51
|
+
pali: string[];
|
|
52
|
+
chinese: string[];
|
|
53
|
+
relatedInstances: Array<{
|
|
54
|
+
workUuid: string;
|
|
55
|
+
toh: string;
|
|
56
|
+
definition: string | null;
|
|
57
|
+
canon: string | null;
|
|
58
|
+
english: string[];
|
|
59
|
+
tibetan: string[];
|
|
60
|
+
sanskrit: string[];
|
|
61
|
+
pali: string[];
|
|
62
|
+
chinese: string[];
|
|
63
|
+
creators: string[];
|
|
64
|
+
}>;
|
|
65
|
+
relatedEntities: Array<{
|
|
66
|
+
sourceHeadword: string;
|
|
67
|
+
sourceUuid: string;
|
|
68
|
+
targetHeadword: string;
|
|
69
|
+
targetUuid: string;
|
|
70
|
+
}>;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type GetGlossaryEntryResponse = {
|
|
74
|
+
glossaryEntry: GraphQLGlossaryEntry | null;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Map GraphQL glossary entry to the GlossaryPageItem type.
|
|
79
|
+
*/
|
|
80
|
+
function glossaryEntryFromGraphQL(
|
|
81
|
+
entry: GraphQLGlossaryEntry,
|
|
82
|
+
): GlossaryPageItem {
|
|
83
|
+
return {
|
|
84
|
+
authorityUuid: entry.authorityUuid,
|
|
85
|
+
headword: entry.headword,
|
|
86
|
+
language: entry.language as GlossaryPageItem['language'],
|
|
87
|
+
classifications: entry.classifications,
|
|
88
|
+
definition: entry.definition ?? undefined,
|
|
89
|
+
xmlId: entry.xmlId ?? undefined,
|
|
90
|
+
english: entry.english,
|
|
91
|
+
tibetan: entry.tibetan,
|
|
92
|
+
sanskrit: entry.sanskrit,
|
|
93
|
+
pali: entry.pali,
|
|
94
|
+
chinese: entry.chinese,
|
|
95
|
+
relatedInstances: entry.relatedInstances.map((instance) => ({
|
|
96
|
+
workUuid: instance.workUuid,
|
|
97
|
+
toh: instance.toh as TohokuCatalogEntry,
|
|
98
|
+
definition: instance.definition ?? undefined,
|
|
99
|
+
canon: instance.canon ?? undefined,
|
|
100
|
+
english: instance.english,
|
|
101
|
+
tibetan: instance.tibetan,
|
|
102
|
+
sanskrit: instance.sanskrit,
|
|
103
|
+
pali: instance.pali,
|
|
104
|
+
chinese: instance.chinese,
|
|
105
|
+
creators: instance.creators,
|
|
106
|
+
})),
|
|
107
|
+
relatedEntities: entry.relatedEntities,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get a single glossary entry by UUID (for the detail page).
|
|
113
|
+
*/
|
|
114
|
+
export async function getGlossaryEntry({
|
|
115
|
+
client,
|
|
116
|
+
uuid,
|
|
117
|
+
}: {
|
|
118
|
+
client: GraphQLClient;
|
|
119
|
+
uuid: string;
|
|
120
|
+
}): Promise<GlossaryPageItem | null> {
|
|
121
|
+
try {
|
|
122
|
+
const response = await client.request<GetGlossaryEntryResponse>(
|
|
123
|
+
GET_GLOSSARY_ENTRY,
|
|
124
|
+
{ uuid },
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (!response.glossaryEntry) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return glossaryEntryFromGraphQL(response.glossaryEntry);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('Error fetching glossary entry:', error);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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_GLOSSARY_INSTANCE = gql`
|
|
6
|
+
query GetGlossaryInstance($uuid: ID!) {
|
|
7
|
+
glossaryInstance(uuid: $uuid) {
|
|
8
|
+
uuid
|
|
9
|
+
authority
|
|
10
|
+
definition
|
|
11
|
+
names {
|
|
12
|
+
english
|
|
13
|
+
tibetan
|
|
14
|
+
sanskrit
|
|
15
|
+
pali
|
|
16
|
+
chinese
|
|
17
|
+
wylie
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
type GetGlossaryInstanceResponse = {
|
|
24
|
+
glossaryInstance: GlossaryTermInstance | null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get a single glossary instance by UUID.
|
|
29
|
+
*/
|
|
30
|
+
export async function getGlossaryInstance({
|
|
31
|
+
client,
|
|
32
|
+
uuid,
|
|
33
|
+
}: {
|
|
34
|
+
client: GraphQLClient;
|
|
35
|
+
uuid: string;
|
|
36
|
+
}): Promise<GlossaryTermInstance | null> {
|
|
37
|
+
try {
|
|
38
|
+
const response = await client.request<GetGlossaryInstanceResponse>(
|
|
39
|
+
GET_GLOSSARY_INSTANCE,
|
|
40
|
+
{ uuid },
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return response.glossaryInstance;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Error fetching glossary instance:', error);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { GlossaryLandingItem } from '@eightyfourthousand/data-access';
|
|
4
|
+
|
|
5
|
+
const GET_GLOSSARY_TERMS = gql`
|
|
6
|
+
query GetGlossaryTerms($uuids: [ID!]) {
|
|
7
|
+
glossaryTerms(uuids: $uuids) {
|
|
8
|
+
uuid
|
|
9
|
+
headword
|
|
10
|
+
type
|
|
11
|
+
language
|
|
12
|
+
nameVariants
|
|
13
|
+
definition
|
|
14
|
+
numGlossaryEntries
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
type GetGlossaryTermsResponse = {
|
|
20
|
+
glossaryTerms: GlossaryLandingItem[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get all glossary terms for the landing page, optionally filtered by UUIDs.
|
|
25
|
+
*/
|
|
26
|
+
export async function getGlossaryTerms({
|
|
27
|
+
client,
|
|
28
|
+
uuids,
|
|
29
|
+
}: {
|
|
30
|
+
client: GraphQLClient;
|
|
31
|
+
uuids?: string[];
|
|
32
|
+
}): Promise<GlossaryLandingItem[]> {
|
|
33
|
+
try {
|
|
34
|
+
const response = await client.request<GetGlossaryTermsResponse>(
|
|
35
|
+
GET_GLOSSARY_TERMS,
|
|
36
|
+
{ uuids },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return response.glossaryTerms;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('Error fetching glossary terms:', error);
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
import type { Passage } from '@eightyfourthousand/data-access';
|
|
4
|
+
import { passageFromGraphQL, type GraphQLPassage } from '../mappers';
|
|
5
|
+
|
|
6
|
+
const GET_PASSAGE = gql`
|
|
7
|
+
fragment AnnotationFields on Annotation {
|
|
8
|
+
uuid
|
|
9
|
+
type
|
|
10
|
+
start
|
|
11
|
+
end
|
|
12
|
+
metadata
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fragment AlignmentFields on Alignment {
|
|
16
|
+
folioUuid
|
|
17
|
+
toh
|
|
18
|
+
tibetan
|
|
19
|
+
folioNumber
|
|
20
|
+
volumeNumber
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fragment PassageFields on Passage {
|
|
24
|
+
uuid
|
|
25
|
+
workUuid
|
|
26
|
+
content
|
|
27
|
+
label
|
|
28
|
+
sort
|
|
29
|
+
type
|
|
30
|
+
xmlId
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fragment PassageWithAnnotations on Passage {
|
|
34
|
+
...PassageFields
|
|
35
|
+
annotations {
|
|
36
|
+
...AnnotationFields
|
|
37
|
+
}
|
|
38
|
+
alignments {
|
|
39
|
+
...AlignmentFields
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
query GetPassage($uuid: ID!) {
|
|
44
|
+
passage(uuid: $uuid) {
|
|
45
|
+
...PassageWithAnnotations
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
type GetPassageResponse = {
|
|
51
|
+
passage: GraphQLPassage | null;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get a single passage by UUID.
|
|
56
|
+
*/
|
|
57
|
+
export async function getPassage({
|
|
58
|
+
client,
|
|
59
|
+
uuid,
|
|
60
|
+
}: {
|
|
61
|
+
client: GraphQLClient;
|
|
62
|
+
uuid: string;
|
|
63
|
+
}): Promise<Passage | undefined> {
|
|
64
|
+
try {
|
|
65
|
+
const response = await client.request<GetPassageResponse>(GET_PASSAGE, {
|
|
66
|
+
uuid,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (!response.passage) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return passageFromGraphQL(response.passage);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Error fetching passage:', error);
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { GraphQLClient } from 'graphql-request';
|
|
2
|
+
import { gql } from 'graphql-request';
|
|
3
|
+
|
|
4
|
+
const GET_TERM_PASSAGES = gql`
|
|
5
|
+
query GetTermPassages($uuid: ID!, $first: Int, $after: String) {
|
|
6
|
+
glossaryTermPassages(uuid: $uuid, first: $first, after: $after) {
|
|
7
|
+
items {
|
|
8
|
+
uuid
|
|
9
|
+
type
|
|
10
|
+
label
|
|
11
|
+
sort
|
|
12
|
+
}
|
|
13
|
+
nextCursor
|
|
14
|
+
hasMore
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
export type GlossaryPassagesPage = {
|
|
20
|
+
items: Array<{ uuid: string; type: string; label: string; sort: number }>;
|
|
21
|
+
nextCursor: string | null;
|
|
22
|
+
hasMore: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type GetTermPassagesResponse = {
|
|
26
|
+
glossaryTermPassages: GlossaryPassagesPage;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Fetch a page of passage references for a single glossary term instance.
|
|
31
|
+
*/
|
|
32
|
+
export async function getTermPassages({
|
|
33
|
+
client,
|
|
34
|
+
uuid,
|
|
35
|
+
first = 10,
|
|
36
|
+
after,
|
|
37
|
+
}: {
|
|
38
|
+
client: GraphQLClient;
|
|
39
|
+
uuid: string;
|
|
40
|
+
first?: number;
|
|
41
|
+
after?: string;
|
|
42
|
+
}): Promise<GlossaryPassagesPage> {
|
|
43
|
+
try {
|
|
44
|
+
const response = await client.request<GetTermPassagesResponse>(
|
|
45
|
+
GET_TERM_PASSAGES,
|
|
46
|
+
{ uuid, first, after },
|
|
47
|
+
);
|
|
48
|
+
return response.glossaryTermPassages;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('Error fetching term passages:', error);
|
|
51
|
+
return { items: [], nextCursor: null, hasMore: false };
|
|
52
|
+
}
|
|
53
|
+
}
|