Files
medusa-store/packages/gatsby-source-medusa/src/gatsby-node.ts
Kasper Fabricius Kristensen cbdc5b7774 fix(gatsby-source-medusa): Unsupported exports warning and schema (#1463)
**What**

- Moves `sourceUpdatedNodes` and `sourceAllNodes` to a separate file, to prevent warning of unsupported exports. See #1455.
- Adds warnings if `GET /store/products`, `GET /store/regions`, and `GET /store/collections` return empty arrays. This should help new users more easily figure out why their storefronts does not work as expected.
- Adds schema to plugin, so that node types for products, regions and collections are always created. This will prevent errors such as `allMedusaRegions query failed` from happening in the storefront, as the query will be valid as the type exists, even if it returns nothing. This should make the gatsby plugin/starter easier to use. This error is an reoccurring issue in our discord, when new users try to run the Gatsby starter without seeding the storefront beforehand. 

Resolves #1455 

Co-authored-by: Sebastian Rindom <7554214+srindom@users.noreply.github.com>
2022-07-13 12:42:06 +00:00

240 lines
5.6 KiB
TypeScript

import {
CreateResolversArgs,
GatsbyCache,
Node,
PluginOptionsSchemaArgs,
Reporter,
SourceNodesArgs,
Store,
} from "gatsby"
import {
createRemoteFileNode,
CreateRemoteFileNodeArgs,
} from "gatsby-source-filesystem"
import { sourceAllNodes, sourceUpdatedNodes } from "./source-nodes"
export function pluginOptionsSchema({ Joi }: PluginOptionsSchemaArgs): any {
return Joi.object({
storeUrl: Joi.string().required(),
apiKey: Joi.string().optional(),
})
}
export async function onPostBuild({ cache }: { cache: any }): Promise<void> {
await cache.set("timestamp", Date.now())
}
export async function sourceNodes(
gatsbyApi: SourceNodesArgs,
pluginOptions: MedusaPluginOptions
): Promise<void> {
const { cache } = gatsbyApi
const lastBuildTime = await cache.get("timestamp")
if (lastBuildTime !== undefined) {
await sourceUpdatedNodes(gatsbyApi, pluginOptions, lastBuildTime)
} else {
gatsbyApi.reporter.info(`Cache is cold, running a clean build.`)
await sourceAllNodes(gatsbyApi, pluginOptions)
}
gatsbyApi.reporter.info(`Finished sourcing nodes`)
}
export function createResolvers({ createResolvers }: CreateResolversArgs): any {
const resolvers = {
MedusaProducts: {
images: {
type: ["MedusaImages"],
resolve: async (
source: any,
_args: any,
context: any,
_info: any
): Promise<any> => {
const { entries } = await context.nodeModel.findAll({
query: {
filter: { parent: { id: { eq: source.id } } },
},
type: "MedusaImages",
})
return entries
},
},
},
}
createResolvers(resolvers)
}
export async function createSchemaCustomization({
actions: { createTypes },
}: {
actions: { createTypes: any }
schema: any
}): Promise<void> {
createTypes(`
type MedusaProducts implements Node {
id: ID!
title: String!
subtitle: String
description: String
handle: String!
is_giftcard: Boolean!
status: String!
thumbnail: File @link(from: "fields.localThumbnail")
options: [MedusaProductOptions]!
variants: [MedusaProductVariants]!
collection: MedusaCollections @link(from: "collection_id")
collection_id: String
profile_id: String!
discountable: Boolean!
published_at: Date!
created_at: Date!
updated_at: Date!
weight: Int
length: Int
width: Int
}
type MedusaImages implements Node {
id: ID!
url: String!
created_at: Date!
updated_at: Date!
image: File @link(from: "fields.localImage")
}
type MedusaCollections implements Node {
id: ID!
handle: String!
title: String!
created_at: Date!
updated_at: Date!
}
type MedusaProductOptions @dontInfer {
id: ID!
title: String!
product_id: String!
values: [MedusaProductOptionValues]!
created_at: Date!
updated_at: Date!
}
type MedusaProductOptionValues @dontInfer {
id: ID!
value: String!
created_at: Date!
updated_at: Date!
option_id: String!
variant_id: String!
}
type MedusaProductVariants @dontInfer {
id: ID!
title: String!
product_id: String!
prices: [MedusaMoneyAmounts]!
sku: String
barcode: String
upc: String
variant_rank: Int
inventory_quantity: Int!
allow_backorder: Boolean!
manage_inventory: Boolean!
hs_code: String
origin_country: String
mid_code: String
material: String
weight: Int
length: Int
height: Int
width: Int
options: [MedusaProductOptionValues]!
created_at: Date!
updated_at: Date!
}
type MedusaMoneyAmounts @dontInfer {
id: ID!
amount: Int!
currency_code: String!
created_at: Date!
updated_at: Date!
variant_id: String!
}
type MedusaRegions implements Node {
id: ID!
name: String!
currency_code: String!
tax_rate: Int!
tax_code: String
automatic_taxes: Boolean!
created_at: Date!
updated_at: Date!
countries: [MedusaCountries]!
}
type MedusaCountries implements Node {
id: ID!
name: String!
iso_2: String!
iso_3: String!
num_code: Int!
display_name: String!
region_id: String!
}
`)
}
export async function onCreateNode({
actions: { createNode, createNodeField },
cache,
createNodeId,
node,
store,
reporter,
}: {
actions: { createNode: any; createNodeField: any }
cache: GatsbyCache
createNodeId: any
node: Node
store: Store
reporter: Reporter
}): Promise<void> {
if (node.internal.type === `MedusaProducts`) {
if (node.thumbnail !== null) {
const thumbnailNode: Node | null = await createRemoteFileNode({
url: `${node.thumbnail}`,
parentNodeId: node.id,
createNode,
createNodeId,
cache,
store,
reporter,
} as CreateRemoteFileNodeArgs)
if (thumbnailNode) {
createNodeField({
node,
name: `localThumbnail`,
value: thumbnailNode.id,
})
}
}
}
if (node.internal.type === `MedusaImages`) {
const imageNode: Node | null = await createRemoteFileNode({
url: `${node.url}`,
parentNodeId: node.id,
createNode,
createNodeId,
cache,
store,
reporter,
} as CreateRemoteFileNodeArgs)
if (imageNode) {
createNodeField({
node,
name: `localImage`,
value: imageNode.id,
})
}
}
}