feat: gatsby source medusa (#924)
This commit is contained in:
committed by
GitHub
parent
d0d8dd7bf6
commit
b8ff364276
11
packages/gatsby-source-medusa/.babelrc
Normal file
11
packages/gatsby-source-medusa/.babelrc
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"presets": [["babel-preset-gatsby-package"]],
|
||||
"overrides": [
|
||||
{
|
||||
"test": [],
|
||||
"presets": [
|
||||
["babel-preset-gatsby-package", { "browser": true, "esm": true }]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
10
packages/gatsby-source-medusa/.gitignore
vendored
Normal file
10
packages/gatsby-source-medusa/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
node_modules
|
||||
|
||||
.DS_Store
|
||||
|
||||
*.js
|
||||
*.js.map
|
||||
*.d.ts
|
||||
!/types/*.d.ts
|
||||
|
||||
!jest.config.js
|
||||
6
packages/gatsby-source-medusa/.npmignore
Normal file
6
packages/gatsby-source-medusa/.npmignore
Normal file
@@ -0,0 +1,6 @@
|
||||
src
|
||||
.prettierrc
|
||||
.env
|
||||
.babelrc.js
|
||||
.eslintrc
|
||||
.gitignore
|
||||
21
packages/gatsby-source-medusa/LICENSE
Normal file
21
packages/gatsby-source-medusa/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Medusa
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
72
packages/gatsby-source-medusa/README.md
Normal file
72
packages/gatsby-source-medusa/README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
<p align="center">
|
||||
<a href="https://www.medusa-commerce.com">
|
||||
<img alt="Medusa" src="https://user-images.githubusercontent.com/7554214/129161578-19b83dc8-fac5-4520-bd48-53cba676edd2.png" width="100" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
gatsby-source-medusa
|
||||
</h1>
|
||||
<p align="center">
|
||||
Medusa is an open-source headless commerce engine that enables developers to create amazing digital commerce experiences. This is a Gatsby source plugin for building websites using Medusa as a data source.
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/medusajs/medusa/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Medusa is released under the MIT license." />
|
||||
</a>
|
||||
<a href="https://github.com/medusajs/medusa/blob/master/CONTRIBUTING.md">
|
||||
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="PRs welcome!" />
|
||||
</a>
|
||||
<a href="https://discord.gg/xpCwq3Kfn8">
|
||||
<img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
|
||||
</a>
|
||||
<a href="https://twitter.com/intent/follow?screen_name=medusajs">
|
||||
<img src="https://img.shields.io/twitter/follow/medusajs.svg?label=Follow%20@medusajs" alt="Follow @medusajs" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Note
|
||||
|
||||
This plugin is still under development. Please report any issues or suggestions on the GitHub issues page.
|
||||
|
||||
## Quickstart
|
||||
|
||||
This takes you through the minimal steps to see your Medusa data in your Gatsby site's GraphiQL explorer.
|
||||
|
||||
### 1. Installation
|
||||
|
||||
Install the source plugin to your Gatsby project using your favorite package manager.
|
||||
|
||||
```shell
|
||||
npm install gatsby-source-medusa
|
||||
```
|
||||
|
||||
```shell
|
||||
yarn add gatsby-source-medusa
|
||||
```
|
||||
|
||||
### 2. Configuration
|
||||
|
||||
Add the plugin to your `gatsby-config.js`:
|
||||
|
||||
```js:title=gatsby-config.js
|
||||
require("dotenv").config()
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
{
|
||||
resolve: "gatsby-source-medusa",
|
||||
options: {
|
||||
storeUrl: process.env.MEDUSA_URL,
|
||||
authToken: process.env.MEDUSA_AUTH_TOKEN //This is optional
|
||||
},
|
||||
},
|
||||
...,
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
The plugin accepts two options `storeUrl` and `authToken`. The `storeUrl` option is required and should point to the server where your Medusa instance is hosted (this could be `localhost:9000` in development). The `authToken` option is optional, and if you add it the plugin will also source orders from your store.
|
||||
|
||||
## You should now be ready to begin querying your data
|
||||
|
||||
You should now be able to view your stores `MedusaProducts`, `MedusaRegions`, `MedusaCollections`, and `MedusaOrders` (if enabled) in your Gatsby site's GraphiQL explorer.
|
||||
@@ -0,0 +1,19 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`helper functions should return return a new node from processNode 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"children": Array [],
|
||||
"description": "A test product",
|
||||
"id": "prod_test_1234",
|
||||
"internal": Object {
|
||||
"content": "{\\"id\\":\\"prod_test_1234\\",\\"title\\":\\"Test Shirt\\",\\"description\\":\\"A test product\\",\\"unit_price\\":2500}",
|
||||
"contentDigest": "digest_string",
|
||||
"type": "MedusaProduct",
|
||||
},
|
||||
"parent": null,
|
||||
"title": "Test Shirt",
|
||||
"unit_price": 2500,
|
||||
},
|
||||
]
|
||||
`;
|
||||
20
packages/gatsby-source-medusa/__tests__/process-node.test.ts
Normal file
20
packages/gatsby-source-medusa/__tests__/process-node.test.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
const { processNode } = require("../src/process-node.ts");
|
||||
|
||||
describe("helper functions", () => {
|
||||
it("should return return a new node from processNode", () => {
|
||||
const fieldName = "product";
|
||||
const node = {
|
||||
id: "prod_test_1234",
|
||||
title: "Test Shirt",
|
||||
description: "A test product",
|
||||
unit_price: 2500,
|
||||
};
|
||||
|
||||
const createContentDigest = jest.fn(() => "digest_string");
|
||||
const processNodeResult = processNode(node, fieldName, createContentDigest);
|
||||
|
||||
expect(createContentDigest).toBeCalled();
|
||||
|
||||
expect(processNodeResult).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
46
packages/gatsby-source-medusa/package.json
Normal file
46
packages/gatsby-source-medusa/package.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "gatsby-source-medusa",
|
||||
"version": "0.0.44",
|
||||
"description": "Gatsby source plugin for building websites using Medusa Commerce as a data source",
|
||||
"scripts": {
|
||||
"test": "jest --watchAll",
|
||||
"watch": "tsc-watch --outDir .",
|
||||
"build": "tsc --outDir ."
|
||||
},
|
||||
"keywords": [
|
||||
"gatsby",
|
||||
"gatsby-plugin",
|
||||
"gatsby-source",
|
||||
"gatsby-source-medusa",
|
||||
"medusa",
|
||||
"medusa-commerce"
|
||||
],
|
||||
"author": "Kasper Kristensen <kasper@medusa-commerce.com> (https://www.medusa-commerce.com/)",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa.git",
|
||||
"directory": "packages/gatsby-source-medusa"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/medusajs/medusa/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0",
|
||||
"babel-preset-gatsby-package": "^2.0.0",
|
||||
"gatsby-core-utils": "^3.3.0",
|
||||
"gatsby-plugin-image": "^2.3.0",
|
||||
"gatsby-source-filesystem": "^4.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.0.1",
|
||||
"babel-plugin-polyfill-corejs2": "^0.3.0",
|
||||
"gatsby": "^4.1.0",
|
||||
"jest": "^27.0.6",
|
||||
"tsc-watch": "^4.5.0",
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"gatsby": "^4.1.0"
|
||||
}
|
||||
}
|
||||
128
packages/gatsby-source-medusa/src/client.ts
Normal file
128
packages/gatsby-source-medusa/src/client.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import axios, { AxiosPromise, AxiosRequestConfig } from "axios"
|
||||
import { Reporter } from "gatsby-cli/lib/reporter/reporter"
|
||||
|
||||
function medusaRequest(
|
||||
storeURL: string,
|
||||
path = "",
|
||||
headers = {}
|
||||
): AxiosPromise {
|
||||
const options: AxiosRequestConfig = {
|
||||
method: "GET",
|
||||
withCredentials: true,
|
||||
url: path,
|
||||
headers: headers,
|
||||
}
|
||||
|
||||
const client = axios.create({ baseURL: storeURL })
|
||||
|
||||
return client(options)
|
||||
}
|
||||
|
||||
export const createClient = (
|
||||
options: MedusaPluginOptions,
|
||||
reporter: Reporter
|
||||
): any => {
|
||||
const { storeUrl, authToken } = options
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} date used fetch products updated since the specified date
|
||||
* @return {Promise<any[]>}
|
||||
*/
|
||||
async function products(date?: string): Promise<any[]> {
|
||||
let products: any[] = []
|
||||
let offset = 0
|
||||
let count = 1
|
||||
do {
|
||||
await medusaRequest(storeUrl, `/store/products?offset=${offset}`)
|
||||
.then(({ data }) => {
|
||||
products = [...products, ...data.products]
|
||||
count = data.count
|
||||
offset = data.products.length
|
||||
})
|
||||
.catch((error) => {
|
||||
reporter.error(
|
||||
`"The following error status was produced while attempting to fetch products: ${error}`
|
||||
)
|
||||
return []
|
||||
})
|
||||
} while (products.length < count)
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} date used fetch regions updated since the specified date
|
||||
* @return {Promise<any[]>}
|
||||
*/
|
||||
async function regions(date?: string): Promise<any[]> {
|
||||
const regions = await medusaRequest(storeUrl, `/store/regions`)
|
||||
.then(({ data }) => {
|
||||
return data.regions
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn(`
|
||||
"The following error status was produced while attempting to fetch regions: ${error}
|
||||
`)
|
||||
return []
|
||||
})
|
||||
return regions
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} date used fetch regions updated since the specified date
|
||||
* @return {Promise<any[]>}
|
||||
*/
|
||||
async function orders(date?: string): Promise<any[]> {
|
||||
const orders = await medusaRequest(storeUrl, `/admin/orders`, {
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
})
|
||||
.then(({ data }) => {
|
||||
return data.orders
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn(`
|
||||
The following error status was produced while attempting to fetch orders: ${error}. \n
|
||||
Make sure that the auth token you provided is valid.
|
||||
`)
|
||||
return []
|
||||
})
|
||||
return orders
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} date used fetch regions updated since the specified date
|
||||
* @return {Promise<any[]>}
|
||||
*/
|
||||
async function collections(date?: string): Promise<any[]> {
|
||||
let collections: any[] = []
|
||||
let offset = 0
|
||||
let count = 1
|
||||
do {
|
||||
await medusaRequest(storeUrl, `/store/collections?offset=${offset}`)
|
||||
.then(({ data }) => {
|
||||
collections = [...collections, ...data.collections]
|
||||
count = data.count
|
||||
offset = data.collections.length
|
||||
})
|
||||
.catch((error) => {
|
||||
reporter.error(
|
||||
`"The following error status was produced while attempting to fetch products: ${error}`
|
||||
)
|
||||
return []
|
||||
})
|
||||
} while (collections.length < count)
|
||||
|
||||
return collections
|
||||
}
|
||||
|
||||
return {
|
||||
products,
|
||||
collections,
|
||||
regions,
|
||||
orders,
|
||||
}
|
||||
}
|
||||
227
packages/gatsby-source-medusa/src/gatsby-node.ts
Normal file
227
packages/gatsby-source-medusa/src/gatsby-node.ts
Normal file
@@ -0,0 +1,227 @@
|
||||
import {
|
||||
CreateResolversArgs,
|
||||
GatsbyCache,
|
||||
Node,
|
||||
PluginOptionsSchemaArgs,
|
||||
Reporter,
|
||||
SourceNodesArgs,
|
||||
Store,
|
||||
} from "gatsby"
|
||||
import { createRemoteFileNode } from "gatsby-source-filesystem"
|
||||
import { makeSourceFromOperation } from "./make-source-from-operation"
|
||||
import { createOperations } from "./operations"
|
||||
|
||||
export function pluginOptionsSchema({ Joi }: PluginOptionsSchemaArgs): any {
|
||||
return Joi.object({
|
||||
storeUrl: Joi.string().required(),
|
||||
apiKey: Joi.string().optional(),
|
||||
})
|
||||
}
|
||||
|
||||
async function sourceAllNodes(
|
||||
gatsbyApi: SourceNodesArgs,
|
||||
pluginOptions: MedusaPluginOptions
|
||||
): Promise<void> {
|
||||
const {
|
||||
createProductsOperation,
|
||||
createRegionsOperation,
|
||||
createOrdersOperation,
|
||||
createCollectionsOperation,
|
||||
} = createOperations(pluginOptions, gatsbyApi)
|
||||
|
||||
const operations = [
|
||||
createProductsOperation,
|
||||
createRegionsOperation,
|
||||
createCollectionsOperation,
|
||||
]
|
||||
|
||||
// if auth token is provided then source orders
|
||||
if (pluginOptions.apiKey) {
|
||||
operations.push(createOrdersOperation)
|
||||
}
|
||||
|
||||
const sourceFromOperation = makeSourceFromOperation(gatsbyApi)
|
||||
|
||||
for (const op of operations) {
|
||||
await sourceFromOperation(op)
|
||||
}
|
||||
}
|
||||
|
||||
const medusaNodeTypes = [
|
||||
"MedusaRegions",
|
||||
"MedusaProducts",
|
||||
"MedusaOrders",
|
||||
"MedusaCollections",
|
||||
]
|
||||
|
||||
async function sourceUpdatedNodes(
|
||||
gatsbyApi: SourceNodesArgs,
|
||||
pluginOptions: MedusaPluginOptions
|
||||
): Promise<void> {
|
||||
const {
|
||||
incrementalProductsOperation,
|
||||
incrementalRegionsOperation,
|
||||
incrementalOrdersOperation,
|
||||
incrementalCollectionsOperation,
|
||||
} = createOperations(pluginOptions, gatsbyApi)
|
||||
|
||||
const lastBuildTime = new Date(
|
||||
gatsbyApi.store.getState().status.plugins?.[`gatsby-source-medusa`]?.[
|
||||
`lastBuildTime`
|
||||
]
|
||||
)
|
||||
|
||||
for (const nodeType of medusaNodeTypes) {
|
||||
gatsbyApi
|
||||
.getNodesByType(nodeType)
|
||||
.forEach((node) => gatsbyApi.actions.touchNode(node))
|
||||
}
|
||||
|
||||
const operations = [
|
||||
incrementalProductsOperation(lastBuildTime),
|
||||
incrementalRegionsOperation(lastBuildTime),
|
||||
incrementalCollectionsOperation(lastBuildTime),
|
||||
]
|
||||
|
||||
if (pluginOptions.apiKey) {
|
||||
operations.push(incrementalOrdersOperation(lastBuildTime))
|
||||
}
|
||||
|
||||
const sourceFromOperation = makeSourceFromOperation(gatsbyApi)
|
||||
|
||||
for (const op of operations) {
|
||||
await sourceFromOperation(op)
|
||||
}
|
||||
}
|
||||
|
||||
export async function sourceNodes(
|
||||
gatsbyApi: SourceNodesArgs,
|
||||
pluginOptions: MedusaPluginOptions
|
||||
): Promise<void> {
|
||||
const pluginStatus =
|
||||
gatsbyApi.store.getState().status.plugins?.[`gatsby-source-medusa`]
|
||||
|
||||
const lastBuildTime = pluginStatus?.[`lastBuildTime`]
|
||||
|
||||
if (lastBuildTime !== undefined) {
|
||||
gatsbyApi.reporter.info(
|
||||
`Cache is warm, but incremental builds are currently not supported. Running a clean build.`
|
||||
)
|
||||
await sourceAllNodes(gatsbyApi, pluginOptions)
|
||||
} else {
|
||||
gatsbyApi.reporter.info(`Cache is cold, running a clean build.`)
|
||||
await sourceAllNodes(gatsbyApi, pluginOptions)
|
||||
}
|
||||
|
||||
gatsbyApi.reporter.info(`Finished sourcing nodes, caching last build time`)
|
||||
gatsbyApi.actions.setPluginStatus(
|
||||
pluginStatus !== undefined
|
||||
? {
|
||||
...pluginStatus,
|
||||
[`lastBuildTime`]: Date.now(),
|
||||
}
|
||||
: {
|
||||
[`lastBuildTime`]: Date.now(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
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 {
|
||||
thumbnail: File @link(from: "fields.localThumbnail")
|
||||
}
|
||||
|
||||
type MedusaImages implements Node {
|
||||
image: File @link(from: "fields.localImage")
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
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,
|
||||
})
|
||||
|
||||
if (imageNode) {
|
||||
createNodeField({
|
||||
node,
|
||||
name: `localImage`,
|
||||
value: imageNode.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { SourceNodesArgs } from "gatsby"
|
||||
import { processNode } from "./process-node"
|
||||
|
||||
export function makeSourceFromOperation(gatsbyApi: SourceNodesArgs) {
|
||||
return async function sourceFromOperation(
|
||||
op: IMedusaOperation
|
||||
): Promise<void> {
|
||||
const { reporter, actions } = gatsbyApi
|
||||
|
||||
reporter.info(`Initiating operation query ${op.name}`)
|
||||
const nodes = await op.execute()
|
||||
|
||||
nodes.map((rawNode) => {
|
||||
const nodeArr = processNode(
|
||||
rawNode,
|
||||
op.name,
|
||||
gatsbyApi.createContentDigest
|
||||
)
|
||||
|
||||
nodeArr.forEach((node) => {
|
||||
actions.createNode(node)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
34
packages/gatsby-source-medusa/src/operations.ts
Normal file
34
packages/gatsby-source-medusa/src/operations.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { SourceNodesArgs } from "gatsby"
|
||||
import { createClient } from "./client"
|
||||
|
||||
export function createOperations(
|
||||
options: MedusaPluginOptions,
|
||||
{ reporter }: SourceNodesArgs
|
||||
): IOperations {
|
||||
const client = createClient(options, reporter)
|
||||
|
||||
function createOperation(
|
||||
name: "products" | "collections" | "regions" | "orders",
|
||||
queryString?: string
|
||||
): IMedusaOperation {
|
||||
return {
|
||||
execute: (): Promise<any[]> => client[name](queryString),
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
createProductsOperation: createOperation("products"),
|
||||
createCollectionsOperation: createOperation("collections"),
|
||||
createRegionsOperation: createOperation("regions"),
|
||||
createOrdersOperation: createOperation("orders"),
|
||||
incrementalProductsOperation: (date: Date): any =>
|
||||
createOperation("products", date.toISOString()),
|
||||
incrementalCollectionsOperation: (date: Date): any =>
|
||||
createOperation("collections", date.toISOString()),
|
||||
incrementalRegionsOperation: (date: Date): any =>
|
||||
createOperation("regions", date.toISOString()),
|
||||
incrementalOrdersOperation: (date: Date): any =>
|
||||
createOperation("orders", date.toISOString()),
|
||||
}
|
||||
}
|
||||
49
packages/gatsby-source-medusa/src/process-node.ts
Normal file
49
packages/gatsby-source-medusa/src/process-node.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { capitalize } from "./utils/capitalize"
|
||||
|
||||
export const processNode = (
|
||||
node: any,
|
||||
fieldName: string,
|
||||
createContentDigest: (this: void, input: string | object) => string
|
||||
): any[] => {
|
||||
const nodeId: string = node.id
|
||||
const nodeContent = JSON.stringify(node)
|
||||
const nodeContentDigest = createContentDigest(nodeContent)
|
||||
|
||||
let images = []
|
||||
|
||||
if (fieldName === "products") {
|
||||
if (node.images?.length) {
|
||||
images = node.images.map((image: any) => {
|
||||
const nodeImageContentDigest = createContentDigest(image.id)
|
||||
const nodeImageContent = JSON.stringify(image)
|
||||
|
||||
const imageData = Object.assign({}, image, {
|
||||
id: image.id,
|
||||
parent: nodeId,
|
||||
children: [],
|
||||
internal: {
|
||||
type: "MedusaImages",
|
||||
content: nodeImageContent,
|
||||
contentDigest: nodeImageContentDigest,
|
||||
},
|
||||
})
|
||||
|
||||
return imageData
|
||||
})
|
||||
}
|
||||
delete node.images
|
||||
}
|
||||
|
||||
const nodeData = Object.assign({}, node, {
|
||||
id: nodeId,
|
||||
parent: null,
|
||||
children: [],
|
||||
internal: {
|
||||
type: `Medusa${capitalize(fieldName)}`,
|
||||
content: nodeContent,
|
||||
contentDigest: nodeContentDigest,
|
||||
},
|
||||
})
|
||||
|
||||
return [nodeData, ...images]
|
||||
}
|
||||
3
packages/gatsby-source-medusa/src/utils/capitalize.ts
Normal file
3
packages/gatsby-source-medusa/src/utils/capitalize.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function capitalize(s: string): string {
|
||||
return s[0].toUpperCase() + s.slice(1)
|
||||
}
|
||||
12
packages/gatsby-source-medusa/src/utils/format-uri.ts
Normal file
12
packages/gatsby-source-medusa/src/utils/format-uri.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const formatUri = (uri: string): string => {
|
||||
let url
|
||||
|
||||
try {
|
||||
url = new URL(uri)
|
||||
} catch (_) {
|
||||
const formatted = /[\w||\d].*/.exec(uri)?.[0]
|
||||
return `https://${formatted}`
|
||||
}
|
||||
|
||||
return url.href
|
||||
}
|
||||
19
packages/gatsby-source-medusa/tsconfig.json
Normal file
19
packages/gatsby-source-medusa/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"include": ["src/**/*.ts", "types"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"module": "commonjs",
|
||||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"target": "es2017",
|
||||
"declaration": true,
|
||||
"lib": ["es2017", "dom", "esnext.asynciterable"]
|
||||
}
|
||||
}
|
||||
29
packages/gatsby-source-medusa/types/interface.d.ts
vendored
Normal file
29
packages/gatsby-source-medusa/types/interface.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
interface MedusaPluginOptions {
|
||||
storeUrl: string
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
interface MedusaProductImage {
|
||||
url: string
|
||||
metadata: Record<string, unknown> | null
|
||||
id: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
deleted_at: string | null
|
||||
}
|
||||
|
||||
interface IMedusaOperation {
|
||||
execute: () => Promise<any[]>
|
||||
name: string
|
||||
}
|
||||
|
||||
interface IOperations {
|
||||
createProductsOperation: IMedusaOperation
|
||||
createCollectionsOperation: IMedusaOperation
|
||||
createRegionsOperation: IMedusaOperation
|
||||
createOrdersOperation: IMedusaOperation
|
||||
incrementalProductsOperation: (date: Date) => IMedusaOperation
|
||||
incrementalCollectionsOperation: (date: Date) => IMedusaOperation
|
||||
incrementalRegionsOperation: (date: Date) => IMedusaOperation
|
||||
incrementalOrdersOperation: (date: Date) => IMedusaOperation
|
||||
}
|
||||
11282
packages/gatsby-source-medusa/yarn.lock
Normal file
11282
packages/gatsby-source-medusa/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user