🪢Added resolvers for lib, dashboard endpoints
This commit is contained in:
139
examples/frontend/components/ComicDetailContainer.tsx
Normal file
139
examples/frontend/components/ComicDetailContainer.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* ComicDetailContainer - GraphQL Version
|
||||
*
|
||||
* This file should replace the existing ComicDetailContainer.tsx
|
||||
* Location: src/client/components/ComicDetail/ComicDetailContainer.tsx
|
||||
*
|
||||
* Key changes from REST version:
|
||||
* 1. Uses executeGraphQLQuery instead of axios directly
|
||||
* 2. Parses JSON strings from sourcedMetadata
|
||||
* 3. Maps GraphQL 'id' to REST '_id' for backward compatibility
|
||||
* 4. Better error and loading states
|
||||
*/
|
||||
|
||||
import React, { ReactElement } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { ComicDetail } from "../ComicDetail/ComicDetail";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { executeGraphQLQuery, transformComicToRestFormat } from "../../services/api/GraphQLApi";
|
||||
import {
|
||||
GET_COMIC_DETAIL_QUERY,
|
||||
ComicDetailQueryResponse
|
||||
} from "../../graphql/queries/comicDetail";
|
||||
|
||||
export const ComicDetailContainer = (): ReactElement | null => {
|
||||
const { comicObjectId } = useParams<{ comicObjectId: string }>();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const {
|
||||
data: comicBookDetailData,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useQuery({
|
||||
queryKey: ["comicBookMetadata", comicObjectId],
|
||||
queryFn: async () => {
|
||||
// Execute GraphQL query
|
||||
const result = await executeGraphQLQuery<ComicDetailQueryResponse>(
|
||||
GET_COMIC_DETAIL_QUERY,
|
||||
{ id: comicObjectId }
|
||||
);
|
||||
|
||||
// Transform to REST format for backward compatibility
|
||||
const transformedComic = transformComicToRestFormat(result.comic);
|
||||
|
||||
// Return in the format expected by ComicDetail component
|
||||
return {
|
||||
data: transformedComic,
|
||||
};
|
||||
},
|
||||
enabled: !!comicObjectId, // Only run query if we have an ID
|
||||
staleTime: 5 * 60 * 1000, // Consider data fresh for 5 minutes
|
||||
retry: 2, // Retry failed requests twice
|
||||
});
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="mx-auto max-w-screen-xl px-4 py-4">
|
||||
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
||||
<strong className="font-bold">Error loading comic: </strong>
|
||||
<span className="block sm:inline">
|
||||
{error instanceof Error ? error.message : 'Unknown error'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="mx-auto max-w-screen-xl px-4 py-4">
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="text-gray-500 dark:text-gray-400">
|
||||
Loading comic details...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
comicBookDetailData?.data && (
|
||||
<ComicDetail
|
||||
data={comicBookDetailData.data}
|
||||
queryClient={queryClient}
|
||||
comicObjectId={comicObjectId}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Alternative implementation with feature flag for gradual rollout
|
||||
* Uncomment this version if you want to toggle between REST and GraphQL
|
||||
*/
|
||||
/*
|
||||
export const ComicDetailContainer = (): ReactElement | null => {
|
||||
const { comicObjectId } = useParams<{ comicObjectId: string }>();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// Feature flag to toggle between REST and GraphQL
|
||||
const USE_GRAPHQL = import.meta.env.VITE_USE_GRAPHQL === 'true';
|
||||
|
||||
const {
|
||||
data: comicBookDetailData,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useQuery({
|
||||
queryKey: ["comicBookMetadata", comicObjectId],
|
||||
queryFn: async () => {
|
||||
if (USE_GRAPHQL) {
|
||||
// GraphQL implementation
|
||||
const result = await executeGraphQLQuery<ComicDetailQueryResponse>(
|
||||
GET_COMIC_DETAIL_QUERY,
|
||||
{ id: comicObjectId }
|
||||
);
|
||||
|
||||
const transformedComic = transformComicToRestFormat(result.comic);
|
||||
|
||||
return {
|
||||
data: transformedComic,
|
||||
};
|
||||
} else {
|
||||
// REST implementation (fallback)
|
||||
const response = await axios({
|
||||
url: `${LIBRARY_SERVICE_BASE_URI}/getComicBookById`,
|
||||
method: "POST",
|
||||
data: { id: comicObjectId },
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
},
|
||||
enabled: !!comicObjectId,
|
||||
});
|
||||
|
||||
// ... rest of the component remains the same
|
||||
};
|
||||
*/
|
||||
248
examples/frontend/graphql-queries/comicDetail.ts
Normal file
248
examples/frontend/graphql-queries/comicDetail.ts
Normal file
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* GraphQL query to fetch complete comic detail data
|
||||
*
|
||||
* This file should be placed in the frontend project at:
|
||||
* src/client/graphql/queries/comicDetail.ts
|
||||
*
|
||||
* Matches the data structure expected by ComicDetail component
|
||||
*/
|
||||
|
||||
export const GET_COMIC_DETAIL_QUERY = `
|
||||
query GetComicDetail($id: ID!) {
|
||||
comic(id: $id) {
|
||||
id
|
||||
|
||||
# Raw file information
|
||||
rawFileDetails {
|
||||
name
|
||||
filePath
|
||||
fileSize
|
||||
extension
|
||||
mimeType
|
||||
containedIn
|
||||
pageCount
|
||||
archive {
|
||||
uncompressed
|
||||
expandedPath
|
||||
}
|
||||
cover {
|
||||
filePath
|
||||
stats
|
||||
}
|
||||
}
|
||||
|
||||
# Inferred metadata from filename parsing
|
||||
inferredMetadata {
|
||||
issue {
|
||||
name
|
||||
number
|
||||
year
|
||||
subtitle
|
||||
}
|
||||
}
|
||||
|
||||
# Sourced metadata from various providers
|
||||
sourcedMetadata {
|
||||
comicInfo
|
||||
comicvine
|
||||
metron
|
||||
gcd
|
||||
locg {
|
||||
name
|
||||
publisher
|
||||
url
|
||||
cover
|
||||
description
|
||||
price
|
||||
rating
|
||||
pulls
|
||||
potw
|
||||
}
|
||||
}
|
||||
|
||||
# Import status
|
||||
importStatus {
|
||||
isImported
|
||||
tagged
|
||||
matchedResult {
|
||||
score
|
||||
}
|
||||
}
|
||||
|
||||
# Acquisition/download information
|
||||
acquisition {
|
||||
source {
|
||||
wanted
|
||||
name
|
||||
}
|
||||
directconnect {
|
||||
downloads {
|
||||
bundleId
|
||||
name
|
||||
size
|
||||
}
|
||||
}
|
||||
torrent {
|
||||
infoHash
|
||||
name
|
||||
announce
|
||||
}
|
||||
}
|
||||
|
||||
# Timestamps
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* TypeScript type for the query response
|
||||
* Generated from GraphQL schema
|
||||
*/
|
||||
export interface ComicDetailQueryResponse {
|
||||
comic: {
|
||||
id: string;
|
||||
rawFileDetails?: {
|
||||
name?: string;
|
||||
filePath?: string;
|
||||
fileSize?: number;
|
||||
extension?: string;
|
||||
mimeType?: string;
|
||||
containedIn?: string;
|
||||
pageCount?: number;
|
||||
archive?: {
|
||||
uncompressed?: boolean;
|
||||
expandedPath?: string;
|
||||
};
|
||||
cover?: {
|
||||
filePath?: string;
|
||||
stats?: any;
|
||||
};
|
||||
};
|
||||
inferredMetadata?: {
|
||||
issue?: {
|
||||
name?: string;
|
||||
number?: number;
|
||||
year?: string;
|
||||
subtitle?: string;
|
||||
};
|
||||
};
|
||||
sourcedMetadata?: {
|
||||
comicInfo?: string; // JSON string - needs parsing
|
||||
comicvine?: string; // JSON string - needs parsing
|
||||
metron?: string; // JSON string - needs parsing
|
||||
gcd?: string; // JSON string - needs parsing
|
||||
locg?: {
|
||||
name?: string;
|
||||
publisher?: string;
|
||||
url?: string;
|
||||
cover?: string;
|
||||
description?: string;
|
||||
price?: string;
|
||||
rating?: number;
|
||||
pulls?: number;
|
||||
potw?: number;
|
||||
};
|
||||
};
|
||||
importStatus?: {
|
||||
isImported?: boolean;
|
||||
tagged?: boolean;
|
||||
matchedResult?: {
|
||||
score?: string;
|
||||
};
|
||||
};
|
||||
acquisition?: {
|
||||
source?: {
|
||||
wanted?: boolean;
|
||||
name?: string;
|
||||
};
|
||||
directconnect?: {
|
||||
downloads?: Array<{
|
||||
bundleId?: number;
|
||||
name?: string;
|
||||
size?: string;
|
||||
}>;
|
||||
};
|
||||
torrent?: Array<{
|
||||
infoHash?: string;
|
||||
name?: string;
|
||||
announce?: string[];
|
||||
}>;
|
||||
};
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal query for basic comic information
|
||||
* Use this when you only need basic details
|
||||
*/
|
||||
export const GET_COMIC_BASIC_QUERY = `
|
||||
query GetComicBasic($id: ID!) {
|
||||
comic(id: $id) {
|
||||
id
|
||||
rawFileDetails {
|
||||
name
|
||||
filePath
|
||||
fileSize
|
||||
pageCount
|
||||
}
|
||||
inferredMetadata {
|
||||
issue {
|
||||
name
|
||||
number
|
||||
year
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Query for comic metadata only (no file details)
|
||||
* Use this when you only need metadata
|
||||
*/
|
||||
export const GET_COMIC_METADATA_QUERY = `
|
||||
query GetComicMetadata($id: ID!) {
|
||||
comic(id: $id) {
|
||||
id
|
||||
sourcedMetadata {
|
||||
comicInfo
|
||||
comicvine
|
||||
metron
|
||||
gcd
|
||||
locg {
|
||||
name
|
||||
publisher
|
||||
description
|
||||
rating
|
||||
}
|
||||
}
|
||||
canonicalMetadata {
|
||||
title {
|
||||
value
|
||||
provenance {
|
||||
source
|
||||
confidence
|
||||
}
|
||||
}
|
||||
series {
|
||||
value
|
||||
provenance {
|
||||
source
|
||||
confidence
|
||||
}
|
||||
}
|
||||
publisher {
|
||||
value
|
||||
provenance {
|
||||
source
|
||||
confidence
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
260
examples/frontend/graphql-queries/libraryQueries.ts
Normal file
260
examples/frontend/graphql-queries/libraryQueries.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* GraphQL queries for library operations
|
||||
* Examples for getComicBooks, getComicBookGroups, getLibraryStatistics, and searchIssue
|
||||
*/
|
||||
|
||||
/**
|
||||
* Query to get comic books with pagination and filtering
|
||||
*/
|
||||
export const GET_COMIC_BOOKS = `
|
||||
query GetComicBooks($paginationOptions: PaginationOptionsInput!, $predicate: PredicateInput) {
|
||||
getComicBooks(paginationOptions: $paginationOptions, predicate: $predicate) {
|
||||
docs {
|
||||
id
|
||||
canonicalMetadata {
|
||||
title {
|
||||
value
|
||||
provenance {
|
||||
source
|
||||
confidence
|
||||
}
|
||||
}
|
||||
series {
|
||||
value
|
||||
}
|
||||
issueNumber {
|
||||
value
|
||||
}
|
||||
publisher {
|
||||
value
|
||||
}
|
||||
coverImage {
|
||||
value
|
||||
}
|
||||
}
|
||||
rawFileDetails {
|
||||
name
|
||||
filePath
|
||||
fileSize
|
||||
extension
|
||||
}
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
totalDocs
|
||||
limit
|
||||
page
|
||||
totalPages
|
||||
hasNextPage
|
||||
hasPrevPage
|
||||
nextPage
|
||||
prevPage
|
||||
pagingCounter
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Query to get comic book groups (volumes)
|
||||
*/
|
||||
export const GET_COMIC_BOOK_GROUPS = `
|
||||
query GetComicBookGroups {
|
||||
getComicBookGroups {
|
||||
id
|
||||
volumes {
|
||||
id
|
||||
name
|
||||
count_of_issues
|
||||
publisher {
|
||||
id
|
||||
name
|
||||
}
|
||||
start_year
|
||||
image {
|
||||
medium_url
|
||||
thumb_url
|
||||
}
|
||||
description
|
||||
site_detail_url
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Query to get library statistics
|
||||
*/
|
||||
export const GET_LIBRARY_STATISTICS = `
|
||||
query GetLibraryStatistics {
|
||||
getLibraryStatistics {
|
||||
totalDocuments
|
||||
comicDirectorySize {
|
||||
totalSize
|
||||
totalSizeInMB
|
||||
totalSizeInGB
|
||||
fileCount
|
||||
}
|
||||
statistics {
|
||||
fileTypes {
|
||||
id
|
||||
data
|
||||
}
|
||||
publisherWithMostComicsInLibrary {
|
||||
id
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Example usage with variables for getComicBooks
|
||||
*/
|
||||
export const exampleGetComicBooksVariables = {
|
||||
paginationOptions: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
sort: "-createdAt", // Sort by creation date, descending
|
||||
lean: false,
|
||||
pagination: true,
|
||||
},
|
||||
predicate: {
|
||||
// Optional: Add filters here
|
||||
// Example: { "canonicalMetadata.publisher.value": "Marvel" }
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Example: Get first page of comics
|
||||
*/
|
||||
export const exampleGetFirstPage = {
|
||||
query: GET_COMIC_BOOKS,
|
||||
variables: {
|
||||
paginationOptions: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
sort: "-createdAt",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Example: Get comics with specific filters
|
||||
*/
|
||||
export const exampleGetFilteredComics = {
|
||||
query: GET_COMIC_BOOKS,
|
||||
variables: {
|
||||
paginationOptions: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
},
|
||||
predicate: {
|
||||
"importStatus.isImported": true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Query to search issues using Elasticsearch
|
||||
*/
|
||||
export const SEARCH_ISSUE = `
|
||||
query SearchIssue($query: SearchIssueQueryInput, $pagination: SearchPaginationInput, $type: SearchType!) {
|
||||
searchIssue(query: $query, pagination: $pagination, type: $type) {
|
||||
hits {
|
||||
total {
|
||||
value
|
||||
relation
|
||||
}
|
||||
max_score
|
||||
hits {
|
||||
_index
|
||||
_id
|
||||
_score
|
||||
_source {
|
||||
id
|
||||
canonicalMetadata {
|
||||
title {
|
||||
value
|
||||
}
|
||||
series {
|
||||
value
|
||||
}
|
||||
issueNumber {
|
||||
value
|
||||
}
|
||||
publisher {
|
||||
value
|
||||
}
|
||||
}
|
||||
rawFileDetails {
|
||||
name
|
||||
filePath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
took
|
||||
timed_out
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Example: Search all comics
|
||||
*/
|
||||
export const exampleSearchAll = {
|
||||
query: SEARCH_ISSUE,
|
||||
variables: {
|
||||
type: "all",
|
||||
pagination: {
|
||||
size: 10,
|
||||
from: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Example: Search by volume name
|
||||
*/
|
||||
export const exampleSearchByVolumeName = {
|
||||
query: SEARCH_ISSUE,
|
||||
variables: {
|
||||
query: {
|
||||
volumeName: "Spider-Man",
|
||||
},
|
||||
type: "volumeName",
|
||||
pagination: {
|
||||
size: 20,
|
||||
from: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Example: Search wanted comics
|
||||
*/
|
||||
export const exampleSearchWanted = {
|
||||
query: SEARCH_ISSUE,
|
||||
variables: {
|
||||
type: "wanted",
|
||||
pagination: {
|
||||
size: 50,
|
||||
from: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Example: Search volumes
|
||||
*/
|
||||
export const exampleSearchVolumes = {
|
||||
query: SEARCH_ISSUE,
|
||||
variables: {
|
||||
type: "volumes",
|
||||
pagination: {
|
||||
size: 10,
|
||||
from: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
165
examples/frontend/services/GraphQLApi.ts
Normal file
165
examples/frontend/services/GraphQLApi.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* GraphQL API Client Utility
|
||||
*
|
||||
* This file should be placed in the frontend project at:
|
||||
* src/client/services/api/GraphQLApi.ts
|
||||
*
|
||||
* Simple wrapper around axios for executing GraphQL queries and mutations
|
||||
* No additional dependencies needed (no Apollo Client)
|
||||
* Works seamlessly with React Query
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
// Update this to match your frontend constants file
|
||||
// import { LIBRARY_SERVICE_BASE_URI } from '../../constants/endpoints';
|
||||
const LIBRARY_SERVICE_BASE_URI = process.env.REACT_APP_LIBRARY_SERVICE_BASE_URI || 'http://localhost:3000/api/library';
|
||||
|
||||
/**
|
||||
* Execute a GraphQL query against the threetwo-core-service GraphQL endpoint
|
||||
*
|
||||
* @param query - GraphQL query string
|
||||
* @param variables - Query variables
|
||||
* @returns Promise with query result data
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const result = await executeGraphQLQuery<ComicDetailQueryResponse>(
|
||||
* GET_COMIC_DETAIL_QUERY,
|
||||
* { id: 'comic-id-123' }
|
||||
* );
|
||||
* console.log(result.comic.rawFileDetails.name);
|
||||
* ```
|
||||
*/
|
||||
export const executeGraphQLQuery = async <T = any>(
|
||||
query: string,
|
||||
variables?: Record<string, any>
|
||||
): Promise<T> => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${LIBRARY_SERVICE_BASE_URI}/graphql`,
|
||||
{
|
||||
query,
|
||||
variables,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// GraphQL can return partial data with errors
|
||||
if (response.data.errors) {
|
||||
console.error('GraphQL errors:', response.data.errors);
|
||||
throw new Error(
|
||||
`GraphQL errors: ${response.data.errors.map((e: any) => e.message).join(', ')}`
|
||||
);
|
||||
}
|
||||
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
console.error('GraphQL query failed:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a GraphQL mutation against the threetwo-core-service GraphQL endpoint
|
||||
*
|
||||
* @param mutation - GraphQL mutation string
|
||||
* @param variables - Mutation variables
|
||||
* @returns Promise with mutation result data
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const result = await executeGraphQLMutation<{ setMetadataField: Comic }>(
|
||||
* SET_METADATA_FIELD_MUTATION,
|
||||
* { comicId: '123', field: 'title', value: 'New Title' }
|
||||
* );
|
||||
* console.log(result.setMetadataField.canonicalMetadata.title);
|
||||
* ```
|
||||
*/
|
||||
export const executeGraphQLMutation = async <T = any>(
|
||||
mutation: string,
|
||||
variables?: Record<string, any>
|
||||
): Promise<T> => {
|
||||
// Mutations use the same endpoint as queries
|
||||
return executeGraphQLQuery<T>(mutation, variables);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to parse JSON strings from sourcedMetadata
|
||||
* GraphQL returns these fields as JSON strings that need parsing
|
||||
*
|
||||
* @param sourcedMetadata - The sourcedMetadata object from GraphQL response
|
||||
* @returns Parsed sourcedMetadata with JSON fields converted to objects
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const comic = result.comic;
|
||||
* comic.sourcedMetadata = parseSourcedMetadata(comic.sourcedMetadata);
|
||||
* // Now comic.sourcedMetadata.comicInfo is an object, not a string
|
||||
* ```
|
||||
*/
|
||||
export const parseSourcedMetadata = (sourcedMetadata: any) => {
|
||||
if (!sourcedMetadata) return sourcedMetadata;
|
||||
|
||||
const parsed = { ...sourcedMetadata };
|
||||
|
||||
// Parse JSON strings
|
||||
if (parsed.comicInfo && typeof parsed.comicInfo === 'string') {
|
||||
try {
|
||||
parsed.comicInfo = JSON.parse(parsed.comicInfo);
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse comicInfo:', e);
|
||||
parsed.comicInfo = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed.comicvine && typeof parsed.comicvine === 'string') {
|
||||
try {
|
||||
parsed.comicvine = JSON.parse(parsed.comicvine);
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse comicvine:', e);
|
||||
parsed.comicvine = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed.metron && typeof parsed.metron === 'string') {
|
||||
try {
|
||||
parsed.metron = JSON.parse(parsed.metron);
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse metron:', e);
|
||||
parsed.metron = {};
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed.gcd && typeof parsed.gcd === 'string') {
|
||||
try {
|
||||
parsed.gcd = JSON.parse(parsed.gcd);
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse gcd:', e);
|
||||
parsed.gcd = {};
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to transform GraphQL comic response to REST format
|
||||
* Ensures backward compatibility with existing components
|
||||
*
|
||||
* @param comic - Comic object from GraphQL response
|
||||
* @returns Comic object in REST format with _id field
|
||||
*/
|
||||
export const transformComicToRestFormat = (comic: any) => {
|
||||
if (!comic) return null;
|
||||
|
||||
return {
|
||||
_id: comic.id,
|
||||
...comic,
|
||||
sourcedMetadata: parseSourcedMetadata(comic.sourcedMetadata),
|
||||
};
|
||||
};
|
||||
87
examples/test-graphql-endpoint.sh
Executable file
87
examples/test-graphql-endpoint.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Test GraphQL Endpoint Script
|
||||
# This script tests the GraphQL endpoint with various queries
|
||||
|
||||
GRAPHQL_URL="http://localhost:3000/graphql"
|
||||
|
||||
echo "🧪 Testing GraphQL Endpoint: $GRAPHQL_URL"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
# Test 1: List Comics
|
||||
echo "📚 Test 1: List Comics (first 5)"
|
||||
echo "--------------------------------"
|
||||
curl -s -X POST $GRAPHQL_URL \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"query": "query { comics(limit: 5) { comics { id rawFileDetails { name pageCount } } totalCount } }"
|
||||
}' | jq '.'
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
# Test 2: Get Single Comic (you need to replace COMIC_ID)
|
||||
echo "📖 Test 2: Get Single Comic"
|
||||
echo "--------------------------------"
|
||||
echo "⚠️ Replace COMIC_ID with an actual comic ID from your database"
|
||||
read -p "Enter Comic ID (or press Enter to skip): " COMIC_ID
|
||||
|
||||
if [ ! -z "$COMIC_ID" ]; then
|
||||
curl -s -X POST $GRAPHQL_URL \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"query\": \"query GetComic(\$id: ID!) { comic(id: \$id) { id rawFileDetails { name filePath fileSize pageCount } sourcedMetadata { locg { name publisher rating } } } }\",
|
||||
\"variables\": { \"id\": \"$COMIC_ID\" }
|
||||
}" | jq '.'
|
||||
else
|
||||
echo "Skipped"
|
||||
fi
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
# Test 3: Get User Preferences
|
||||
echo "⚙️ Test 3: Get User Preferences"
|
||||
echo "--------------------------------"
|
||||
curl -s -X POST $GRAPHQL_URL \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"query": "query { userPreferences(userId: \"default\") { id userId conflictResolution minConfidenceThreshold autoMerge { enabled onImport onMetadataUpdate } } }"
|
||||
}' | jq '.'
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
# Test 4: Search Comics
|
||||
echo "🔍 Test 4: Search Comics"
|
||||
echo "--------------------------------"
|
||||
read -p "Enter search term (or press Enter to skip): " SEARCH_TERM
|
||||
|
||||
if [ ! -z "$SEARCH_TERM" ]; then
|
||||
curl -s -X POST $GRAPHQL_URL \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"query\": \"query SearchComics(\$search: String) { comics(search: \$search, limit: 10) { comics { id rawFileDetails { name } } totalCount } }\",
|
||||
\"variables\": { \"search\": \"$SEARCH_TERM\" }
|
||||
}" | jq '.'
|
||||
else
|
||||
echo "Skipped"
|
||||
fi
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
# Test 5: GraphQL Introspection (get schema info)
|
||||
echo "🔬 Test 5: Introspection - Available Queries"
|
||||
echo "--------------------------------"
|
||||
curl -s -X POST $GRAPHQL_URL \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"query": "{ __schema { queryType { fields { name description } } } }"
|
||||
}' | jq '.data.__schema.queryType.fields[] | {name, description}'
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "✅ GraphQL endpoint tests complete!"
|
||||
echo ""
|
||||
echo "💡 Tips:"
|
||||
echo " - Open http://localhost:3000/graphql in your browser for GraphQL Playground"
|
||||
echo " - Use 'jq' for better JSON formatting (install with: apt-get install jq)"
|
||||
echo " - Check the docs at: docs/FRONTEND_GRAPHQL_INTEGRATION.md"
|
||||
@@ -27,6 +27,202 @@ export const resolvers = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get comic books with advanced pagination and filtering
|
||||
*/
|
||||
getComicBooks: async (
|
||||
_: any,
|
||||
{
|
||||
paginationOptions,
|
||||
predicate = {},
|
||||
}: {
|
||||
paginationOptions: any;
|
||||
predicate?: any;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
const result = await Comic.paginate(predicate, paginationOptions);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("Error fetching comic books:", error);
|
||||
throw new Error("Failed to fetch comic books");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get comic book groups (volumes with multiple issues)
|
||||
*/
|
||||
getComicBookGroups: async () => {
|
||||
try {
|
||||
const volumes = await Comic.aggregate([
|
||||
{
|
||||
$project: {
|
||||
volumeInfo:
|
||||
"$sourcedMetadata.comicvine.volumeInformation",
|
||||
},
|
||||
},
|
||||
{
|
||||
$unwind: "$volumeInfo",
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: "$_id",
|
||||
volumes: {
|
||||
$addToSet: "$volumeInfo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
$unwind: "$volumes",
|
||||
},
|
||||
{ $sort: { updatedAt: -1 } },
|
||||
{ $skip: 0 },
|
||||
{ $limit: 5 },
|
||||
]);
|
||||
|
||||
return volumes.map((vol) => ({
|
||||
id: vol._id.toString(),
|
||||
volumes: vol.volumes,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("Error fetching comic book groups:", error);
|
||||
throw new Error("Failed to fetch comic book groups");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get library statistics
|
||||
*/
|
||||
getLibraryStatistics: async () => {
|
||||
try {
|
||||
const { getSizeOfDirectory } = require("../../utils/file.utils");
|
||||
const { COMICS_DIRECTORY } = require("../../constants/directories");
|
||||
|
||||
const comicDirectorySize = await getSizeOfDirectory(
|
||||
COMICS_DIRECTORY,
|
||||
[".cbz", ".cbr", ".cb7"]
|
||||
);
|
||||
const totalCount = await Comic.countDocuments({});
|
||||
const statistics = await Comic.aggregate([
|
||||
{
|
||||
$facet: {
|
||||
fileTypes: [
|
||||
{
|
||||
$match: {
|
||||
"rawFileDetails.extension": {
|
||||
$in: [".cbr", ".cbz", ".cb7"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: "$rawFileDetails.extension",
|
||||
data: { $push: "$$ROOT._id" },
|
||||
},
|
||||
},
|
||||
],
|
||||
issues: [
|
||||
{
|
||||
$match: {
|
||||
"sourcedMetadata.comicvine.volumeInformation":
|
||||
{
|
||||
$gt: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: "$sourcedMetadata.comicvine.volumeInformation",
|
||||
data: { $push: "$$ROOT._id" },
|
||||
},
|
||||
},
|
||||
],
|
||||
fileLessComics: [
|
||||
{
|
||||
$match: {
|
||||
rawFileDetails: {
|
||||
$exists: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
issuesWithComicInfoXML: [
|
||||
{
|
||||
$match: {
|
||||
"sourcedMetadata.comicInfo": {
|
||||
$exists: true,
|
||||
$gt: { $size: 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
publisherWithMostComicsInLibrary: [
|
||||
{
|
||||
$unwind:
|
||||
"$sourcedMetadata.comicvine.volumeInformation.publisher",
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: "$sourcedMetadata.comicvine.volumeInformation.publisher.name",
|
||||
count: { $sum: 1 },
|
||||
},
|
||||
},
|
||||
{ $sort: { count: -1 } },
|
||||
{ $limit: 1 },
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
totalDocuments: totalCount,
|
||||
comicDirectorySize,
|
||||
statistics,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching library statistics:", error);
|
||||
throw new Error("Failed to fetch library statistics");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Search issues using Elasticsearch
|
||||
*/
|
||||
searchIssue: async (
|
||||
_: any,
|
||||
{
|
||||
query,
|
||||
pagination = { size: 10, from: 0 },
|
||||
type,
|
||||
}: {
|
||||
query?: { volumeName?: string; issueNumber?: string };
|
||||
pagination?: { size?: number; from?: number };
|
||||
type: string;
|
||||
},
|
||||
context: any
|
||||
) => {
|
||||
try {
|
||||
// Get broker from context (set up in GraphQL service)
|
||||
const broker = context?.broker;
|
||||
|
||||
if (!broker) {
|
||||
throw new Error("Broker not available in context");
|
||||
}
|
||||
|
||||
// Call the search service through the broker
|
||||
const result = await broker.call("search.issue", {
|
||||
query: query || {},
|
||||
pagination,
|
||||
type,
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("Error searching issues:", error);
|
||||
throw new Error(`Failed to search issues: ${error.message}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* List comics with pagination and filtering
|
||||
*/
|
||||
|
||||
@@ -239,6 +239,25 @@ export const typeDefs = gql`
|
||||
series: String
|
||||
): ComicConnection!
|
||||
|
||||
# Get comic books with advanced pagination and filtering
|
||||
getComicBooks(
|
||||
paginationOptions: PaginationOptionsInput!
|
||||
predicate: PredicateInput
|
||||
): ComicBooksResult!
|
||||
|
||||
# Get comic book groups (volumes with multiple issues)
|
||||
getComicBookGroups: [ComicBookGroup!]!
|
||||
|
||||
# Get library statistics
|
||||
getLibraryStatistics: LibraryStatistics!
|
||||
|
||||
# Search issues using Elasticsearch
|
||||
searchIssue(
|
||||
query: SearchIssueQueryInput
|
||||
pagination: SearchPaginationInput
|
||||
type: SearchType!
|
||||
): SearchIssueResult!
|
||||
|
||||
# Get user preferences
|
||||
userPreferences(userId: String = "default"): UserPreferences
|
||||
|
||||
@@ -439,4 +458,162 @@ export const typeDefs = gql`
|
||||
message: String
|
||||
canonicalMetadataResolved: Boolean!
|
||||
}
|
||||
|
||||
# Pagination options input
|
||||
input PaginationOptionsInput {
|
||||
page: Int
|
||||
limit: Int
|
||||
sort: String
|
||||
lean: Boolean
|
||||
leanWithId: Boolean
|
||||
offset: Int
|
||||
pagination: Boolean
|
||||
}
|
||||
|
||||
# Predicate input for filtering
|
||||
# Note: This is a placeholder. In practice, predicates are passed as JSON objects
|
||||
# and handled dynamically in the resolver
|
||||
scalar PredicateInput
|
||||
|
||||
# Comic books result with pagination
|
||||
type ComicBooksResult {
|
||||
docs: [Comic!]!
|
||||
totalDocs: Int!
|
||||
limit: Int!
|
||||
page: Int
|
||||
totalPages: Int!
|
||||
hasNextPage: Boolean!
|
||||
hasPrevPage: Boolean!
|
||||
nextPage: Int
|
||||
prevPage: Int
|
||||
pagingCounter: Int!
|
||||
}
|
||||
|
||||
# Comic book group (volume with issues)
|
||||
type ComicBookGroup {
|
||||
id: ID!
|
||||
volumes: VolumeInfo
|
||||
}
|
||||
|
||||
# Volume information
|
||||
type VolumeInfo {
|
||||
id: Int
|
||||
name: String
|
||||
count_of_issues: Int
|
||||
publisher: Publisher
|
||||
start_year: String
|
||||
image: VolumeImage
|
||||
description: String
|
||||
site_detail_url: String
|
||||
}
|
||||
|
||||
# Publisher information
|
||||
type Publisher {
|
||||
id: Int
|
||||
name: String
|
||||
api_detail_url: String
|
||||
}
|
||||
|
||||
# Volume image
|
||||
type VolumeImage {
|
||||
icon_url: String
|
||||
medium_url: String
|
||||
screen_url: String
|
||||
screen_large_url: String
|
||||
small_url: String
|
||||
super_url: String
|
||||
thumb_url: String
|
||||
tiny_url: String
|
||||
original_url: String
|
||||
image_tags: String
|
||||
}
|
||||
|
||||
# Library statistics
|
||||
type LibraryStatistics {
|
||||
totalDocuments: Int!
|
||||
comicDirectorySize: DirectorySize!
|
||||
statistics: [StatisticsFacet!]!
|
||||
}
|
||||
|
||||
# Directory size information
|
||||
type DirectorySize {
|
||||
totalSize: Float!
|
||||
totalSizeInMB: Float!
|
||||
totalSizeInGB: Float!
|
||||
fileCount: Int!
|
||||
}
|
||||
|
||||
# Statistics facet
|
||||
type StatisticsFacet {
|
||||
fileTypes: [FileTypeStats!]
|
||||
issues: [IssueStats!]
|
||||
fileLessComics: [Comic!]
|
||||
issuesWithComicInfoXML: [Comic!]
|
||||
publisherWithMostComicsInLibrary: [PublisherStats!]
|
||||
}
|
||||
|
||||
# File type statistics
|
||||
type FileTypeStats {
|
||||
id: String!
|
||||
data: [ID!]!
|
||||
}
|
||||
|
||||
# Issue statistics
|
||||
type IssueStats {
|
||||
id: VolumeInfo
|
||||
data: [ID!]!
|
||||
}
|
||||
|
||||
# Publisher statistics
|
||||
type PublisherStats {
|
||||
id: String!
|
||||
count: Int!
|
||||
}
|
||||
# Search issue query input
|
||||
input SearchIssueQueryInput {
|
||||
volumeName: String
|
||||
issueNumber: String
|
||||
}
|
||||
|
||||
# Search pagination input
|
||||
input SearchPaginationInput {
|
||||
size: Int
|
||||
from: Int
|
||||
}
|
||||
|
||||
# Search type enum
|
||||
enum SearchType {
|
||||
all
|
||||
volumeName
|
||||
wanted
|
||||
volumes
|
||||
}
|
||||
|
||||
# Search issue result
|
||||
type SearchIssueResult {
|
||||
hits: SearchHits!
|
||||
took: Int
|
||||
timed_out: Boolean
|
||||
}
|
||||
|
||||
# Search hits
|
||||
type SearchHits {
|
||||
total: SearchTotal!
|
||||
max_score: Float
|
||||
hits: [SearchHit!]!
|
||||
}
|
||||
|
||||
# Search total
|
||||
type SearchTotal {
|
||||
value: Int!
|
||||
relation: String!
|
||||
}
|
||||
|
||||
# Search hit
|
||||
type SearchHit {
|
||||
_index: String!
|
||||
_id: String!
|
||||
_score: Float
|
||||
_source: Comic!
|
||||
}
|
||||
`;
|
||||
|
||||
583
package-lock.json
generated
583
package-lock.json
generated
@@ -39,11 +39,12 @@
|
||||
"leven": "^3.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mkdirp": "^0.5.5",
|
||||
"moleculer-apollo-server": "^0.4.0",
|
||||
"moleculer-bullmq": "^3.0.0",
|
||||
"moleculer-db": "^0.8.23",
|
||||
"moleculer-db-adapter-mongoose": "^0.9.2",
|
||||
"moleculer-io": "^2.2.0",
|
||||
"moleculer-web": "^0.10.8",
|
||||
"moleculer-web": "^0.10.5",
|
||||
"mongoosastic-ts": "^6.0.3",
|
||||
"mongoose": "^6.10.4",
|
||||
"mongoose-paginate-v2": "^1.3.18",
|
||||
@@ -4265,6 +4266,18 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@whatwg-node/promise-helpers": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz",
|
||||
"integrity": "sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.9.8",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz",
|
||||
@@ -5718,6 +5731,18 @@
|
||||
"yup": "0.32.9"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-inspect": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.1.tgz",
|
||||
"integrity": "sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -5782,6 +5807,12 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/dataloader": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz",
|
||||
"integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
@@ -8052,6 +8083,15 @@
|
||||
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/graphql-subscriptions": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-3.0.0.tgz",
|
||||
"integrity": "sha512-kZCdevgmzDjGAOqH7GlDmQXYAkuHoKpMlJrqF40HMPhUhM5ZWSFSxCwD/nSi6AkaijmMfsFhoJRGJ27UseCvRA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"graphql": "^15.7.2 || ^16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/graphql-tag": {
|
||||
"version": "2.12.6",
|
||||
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz",
|
||||
@@ -8067,6 +8107,32 @@
|
||||
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/graphql-ws": {
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.7.tgz",
|
||||
"integrity": "sha512-yoLRW+KRlDmnnROdAu7sX77VNLC0bsFoZyGQJLy1cF+X/SkLg/fWkRGrEEYQK8o2cafJ2wmEaMqMEZB3U3DYDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@fastify/websocket": "^10 || ^11",
|
||||
"crossws": "~0.3",
|
||||
"graphql": "^15.10.1 || ^16",
|
||||
"ws": "^8"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@fastify/websocket": {
|
||||
"optional": true
|
||||
},
|
||||
"crossws": {
|
||||
"optional": true
|
||||
},
|
||||
"ws": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
@@ -10946,6 +11012,438 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/moleculer-apollo-server/-/moleculer-apollo-server-0.4.0.tgz",
|
||||
"integrity": "sha512-uHI8XgYyczOMAhS4OdGgq/5jO+JmqRsuJPkcQqXRMXGJk1WjAy35kHkRsJBImFGfLlR4YKlsBVAPqEIs22QAFg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apollo/server": "^5.0.0",
|
||||
"@graphql-tools/schema": "^10.0.25",
|
||||
"dataloader": "^2.2.3",
|
||||
"graphql-subscriptions": "^3.0.0",
|
||||
"graphql-ws": "^6.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"object-hash": "^3.0.0",
|
||||
"ws": "^8.18.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.x.x"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^16.0.0",
|
||||
"moleculer": "^0.14.0 || ^0.15.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/server": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/server/-/server-5.4.0.tgz",
|
||||
"integrity": "sha512-E0/2C5Rqp7bWCjaDh4NzYuEPDZ+dltTf2c0FI6GCKJA6GBetVferX3h1//1rS4+NxD36wrJsGGJK+xyT/M3ysg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apollo/cache-control-types": "^1.0.3",
|
||||
"@apollo/server-gateway-interface": "^2.0.0",
|
||||
"@apollo/usage-reporting-protobuf": "^4.1.1",
|
||||
"@apollo/utils.createhash": "^3.0.0",
|
||||
"@apollo/utils.fetcher": "^3.0.0",
|
||||
"@apollo/utils.isnodelike": "^3.0.0",
|
||||
"@apollo/utils.keyvaluecache": "^4.0.0",
|
||||
"@apollo/utils.logger": "^3.0.0",
|
||||
"@apollo/utils.usagereporting": "^2.1.0",
|
||||
"@apollo/utils.withrequired": "^3.0.0",
|
||||
"@graphql-tools/schema": "^10.0.0",
|
||||
"async-retry": "^1.2.1",
|
||||
"body-parser": "^2.2.2",
|
||||
"content-type": "^1.0.5",
|
||||
"cors": "^2.8.5",
|
||||
"finalhandler": "^2.1.0",
|
||||
"loglevel": "^1.6.8",
|
||||
"lru-cache": "^11.1.0",
|
||||
"negotiator": "^1.0.0",
|
||||
"uuid": "^11.1.0",
|
||||
"whatwg-mimetype": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^16.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/server-gateway-interface": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/server-gateway-interface/-/server-gateway-interface-2.0.0.tgz",
|
||||
"integrity": "sha512-3HEMD6fSantG2My3jWkb9dvfkF9vJ4BDLRjMgsnD790VINtuPaEp+h3Hg9HOHiWkML6QsOhnaRqZ+gvhp3y8Nw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apollo/usage-reporting-protobuf": "^4.1.1",
|
||||
"@apollo/utils.fetcher": "^3.0.0",
|
||||
"@apollo/utils.keyvaluecache": "^4.0.0",
|
||||
"@apollo/utils.logger": "^3.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "14.x || 15.x || 16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/utils.createhash": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/utils.createhash/-/utils.createhash-3.0.1.tgz",
|
||||
"integrity": "sha512-CKrlySj4eQYftBE5MJ8IzKwIibQnftDT7yGfsJy5KSEEnLlPASX0UTpbKqkjlVEwPPd4mEwI7WOM7XNxEuO05A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apollo/utils.isnodelike": "^3.0.0",
|
||||
"sha.js": "^2.4.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/utils.fetcher": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/utils.fetcher/-/utils.fetcher-3.1.0.tgz",
|
||||
"integrity": "sha512-Z3QAyrsQkvrdTuHAFwWDNd+0l50guwoQUoaDQssLOjkmnmVuvXlJykqlEJolio+4rFwBnWdoY1ByFdKaQEcm7A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/utils.isnodelike": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/utils.isnodelike/-/utils.isnodelike-3.0.0.tgz",
|
||||
"integrity": "sha512-xrjyjfkzunZ0DeF6xkHaK5IKR8F1FBq6qV+uZ+h9worIF/2YSzA0uoBxGv6tbTeo9QoIQnRW4PVFzGix5E7n/g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/utils.keyvaluecache": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-4.0.0.tgz",
|
||||
"integrity": "sha512-mKw1myRUkQsGPNB+9bglAuhviodJ2L2MRYLTafCMw5BIo7nbvCPNCkLnIHjZ1NOzH7SnMAr5c9LmXiqsgYqLZw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apollo/utils.logger": "^3.0.0",
|
||||
"lru-cache": "^11.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/utils.logger": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-3.0.0.tgz",
|
||||
"integrity": "sha512-M8V8JOTH0F2qEi+ktPfw4RL7MvUycDfKp7aEap2eWXfL5SqWHN6jTLbj5f5fj1cceHpyaUSOZlvlaaryaxZAmg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@apollo/utils.withrequired": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/utils.withrequired/-/utils.withrequired-3.0.0.tgz",
|
||||
"integrity": "sha512-aaxeavfJ+RHboh7c2ofO5HHtQobGX4AgUujXP4CXpREHp9fQ9jPi6K9T1jrAKe7HIipoP0OJ1gd6JamSkFIpvA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@graphql-tools/merge": {
|
||||
"version": "9.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.1.7.tgz",
|
||||
"integrity": "sha512-Y5E1vTbTabvcXbkakdFUt4zUIzB1fyaEnVmIWN0l0GMed2gdD01TpZWLUm4RNAxpturvolrb24oGLQrBbPLSoQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@graphql-tools/utils": "^11.0.0",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@graphql-tools/schema": {
|
||||
"version": "10.0.31",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.31.tgz",
|
||||
"integrity": "sha512-ZewRgWhXef6weZ0WiP7/MV47HXiuFbFpiDUVLQl6mgXsWSsGELKFxQsyUCBos60Qqy1JEFAIu3Ns6GGYjGkqkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@graphql-tools/merge": "^9.1.7",
|
||||
"@graphql-tools/utils": "^11.0.0",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/@graphql-tools/utils": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-11.0.0.tgz",
|
||||
"integrity": "sha512-bM1HeZdXA2C3LSIeLOnH/bcqSgbQgKEDrjxODjqi3y58xai2TkNrtYcQSoWzGbt9VMN1dORGjR7Vem8SPnUFQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@graphql-typed-document-node/core": "^3.1.1",
|
||||
"@whatwg-node/promise-helpers": "^1.0.0",
|
||||
"cross-inspect": "1.0.1",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/body-parser": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
|
||||
"integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "^3.1.2",
|
||||
"content-type": "^1.0.5",
|
||||
"debug": "^4.4.3",
|
||||
"http-errors": "^2.0.0",
|
||||
"iconv-lite": "^0.7.0",
|
||||
"on-finished": "^2.4.1",
|
||||
"qs": "^6.14.1",
|
||||
"raw-body": "^3.0.1",
|
||||
"type-is": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/finalhandler": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
|
||||
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.4.0",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"on-finished": "^2.4.1",
|
||||
"parseurl": "^1.3.3",
|
||||
"statuses": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/http-errors": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
||||
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"depd": "~2.0.0",
|
||||
"inherits": "~2.0.4",
|
||||
"setprototypeof": "~1.2.0",
|
||||
"statuses": "~2.0.2",
|
||||
"toidentifier": "~1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/iconv-lite": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
|
||||
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/lru-cache": {
|
||||
"version": "11.2.6",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz",
|
||||
"integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/media-typer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
||||
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/mime-types": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
|
||||
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/negotiator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
||||
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/qs": {
|
||||
"version": "6.15.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
|
||||
"integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/raw-body": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
|
||||
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "~3.1.2",
|
||||
"http-errors": "~2.0.1",
|
||||
"iconv-lite": "~0.7.0",
|
||||
"unpipe": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/statuses": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/type-is": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
"media-typer": "^1.1.0",
|
||||
"mime-types": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/uuid": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/whatwg-mimetype": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
||||
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-apollo-server/node_modules/ws": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
||||
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/moleculer-bullmq": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/moleculer-bullmq/-/moleculer-bullmq-3.0.0.tgz",
|
||||
@@ -14084,10 +14582,20 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-hash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
|
||||
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -15787,14 +16295,69 @@
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"object-inspect": "^1.13.1"
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-list": "^1.0.0",
|
||||
"side-channel-map": "^1.0.1",
|
||||
"side-channel-weakmap": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-list": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-map": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-weakmap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-map": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/server": "^4.12.2",
|
||||
"moleculer-apollo-server": "^0.4.0",
|
||||
"@bluelovers/fast-glob": "https://github.com/rishighan/fast-glob-v2-api.git",
|
||||
"@elastic/elasticsearch": "^8.13.1",
|
||||
"@jorgeferrero/stream-to-buffer": "^2.0.6",
|
||||
|
||||
Reference in New Issue
Block a user