From 2b2e31d5e44847e0f1e811b173acd9ef39a33f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antony=20Dur=C3=A1n?= Date: Mon, 31 Mar 2025 17:17:57 -0600 Subject: [PATCH 01/15] feat: initial Page Builder plugin implementation - Introduced a new Page Builder module with models for posts, authors, tags, and templates. - Added CRUD workflows for creating, updating, deleting, and duplicating posts. - Integrated the module with the Medusa SDK for seamless API interactions. - Created a custom SDK for the Page Builder, enhancing admin and storefront functionalities. - Updated dependencies and added TypeScript definitions for improved type safety. These changes provide a robust foundation for managing content within the Medusa framework, enabling users to create and manage posts effectively. --- apps/medusa/package.json | 14 +- .../src/admin/components/action-menu.tsx | 100 ++ apps/medusa/src/admin/components/header.tsx | 66 + .../medusa/src/admin/hooks/posts-mutations.ts | 65 + apps/medusa/src/admin/hooks/posts-queries.ts | 32 + .../src/admin/hooks/use-query-params.tsx | 50 + .../src/admin/layouts/single-column.tsx | 16 + .../components/posts-data-table/index.tsx | 145 ++ .../use-post-data-table-columns.tsx | 115 ++ .../posts-data-table/use-post-table-query.tsx | 217 +++ .../content/editor/components/breadcrumbs.tsx | 81 + .../editor/components/editor-modal.tsx | 206 +++ .../editor/components/editor-sidebar.tsx | 61 + .../editor/components/editor-top-bar.tsx | 18 + .../editor/components/main-content.tsx | 23 + .../content/editor/components/nav-item.tsx | 37 + .../editor/components/post-editor-layout.tsx | 20 + .../components/post-settings-sidebar.tsx | 30 + .../editor/components/sidebar-container.tsx | 68 + .../editor/components/sidebar-toggle.tsx | 34 + .../editor/hooks/use-editor-sidebar.tsx | 12 + .../content/editor/hooks/use-loading-state.ts | 14 + .../providers/editor-sidebar-context.tsx | 28 + .../providers/editor-sidebar-provider.tsx | 46 + .../admin/routes/content/editor/test/page.tsx | 54 + apps/medusa/src/admin/routes/content/page.tsx | 49 + apps/medusa/src/admin/sdk.ts | 12 + apps/medusa/src/admin/tsconfig.json | 26 +- apps/medusa/src/admin/vite-env.d.ts | 1 + .../content/posts/[id]/duplicate/route.ts | 20 + .../admin/content/posts/[id]/middlewares.ts | 18 + .../api/admin/content/posts/[id]/route.tsx | 29 + .../api/admin/content/posts/middlewares.ts | 52 + .../src/api/admin/content/posts/route.ts | 31 + .../src/api/admin/content/validations.ts | 71 + apps/medusa/src/api/middlewares.ts | 8 + apps/medusa/src/links/post-author-user.ts | 14 + apps/medusa/src/links/post-tag-user.ts | 14 + .../src/modules/page-builder/enum-values.ts | 3 + apps/medusa/src/modules/page-builder/index.ts | 15 + .../.snapshot-medusa-page-builder.json | 1489 +++++++++++++++++ .../migrations/Migration20250305164601.ts | 103 ++ .../migrations/Migration20250313155933.ts | 15 + .../src/modules/page-builder/models/image.ts | 30 + .../src/modules/page-builder/models/index.ts | 8 + .../page-builder/models/navigation-item.ts | 10 + .../page-builder/models/post-author.ts | 13 + .../page-builder/models/post-section.ts | 39 + .../modules/page-builder/models/post-tag.ts | 15 + .../page-builder/models/post-template.ts | 14 + .../src/modules/page-builder/models/post.ts | 41 + .../page-builder/models/site-settings.ts | 32 + .../src/modules/page-builder/service.ts | 24 + apps/medusa/src/subscribers/README.md | 6 +- apps/medusa/src/workflows/create-post.ts | 25 + apps/medusa/src/workflows/delete-post.ts | 26 + apps/medusa/src/workflows/duplicate-post.ts | 32 + .../medusa/src/workflows/steps/create-post.ts | 37 + .../medusa/src/workflows/steps/delete-post.ts | 49 + .../steps/duplicate-post-relations.ts | 82 + .../src/workflows/steps/duplicate-post.ts | 51 + .../medusa/src/workflows/steps/update-post.ts | 42 + apps/medusa/src/workflows/types/index.ts | 42 + apps/medusa/src/workflows/update-post.ts | 25 + apps/storefront/package.json | 5 +- package.json | 4 +- packages/page-builder-sdk/.gitignore | 12 + packages/page-builder-sdk/README.md | 182 ++ packages/page-builder-sdk/package.json | 58 + packages/page-builder-sdk/src/index.ts | 2 + .../src/sdk/admin/admin-page-builder.ts | 48 + .../page-builder-sdk/src/sdk/admin/index.ts | 12 + packages/page-builder-sdk/src/sdk/index.ts | 15 + .../page-builder-sdk/src/sdk/store/index.ts | 13 + .../src/sdk/store/store-page-builder.ts | 12 + packages/page-builder-sdk/src/types/index.ts | 2 + .../src/types/product-review-stats.ts | 34 + .../src/types/product-reviews.ts | 136 ++ packages/page-builder-sdk/tsconfig.esm.json | 24 + packages/page-builder-sdk/tsconfig.json | 26 + packages/page-builder-sdk/tsup.config.ts | 12 + packages/page-builder-types/.gitignore | 1 + packages/page-builder-types/package.json | 18 + packages/page-builder-types/src/admins.d.ts | 79 + packages/page-builder-types/src/common.d.ts | 39 + packages/page-builder-types/src/index.d.ts | 4 + packages/page-builder-types/src/models.d.ts | 92 + .../page-builder-types/src/storefronts.d.ts | 49 + yarn.lock | 1388 +++++++++++---- 89 files changed, 6042 insertions(+), 390 deletions(-) create mode 100644 apps/medusa/src/admin/components/action-menu.tsx create mode 100644 apps/medusa/src/admin/components/header.tsx create mode 100644 apps/medusa/src/admin/hooks/posts-mutations.ts create mode 100644 apps/medusa/src/admin/hooks/posts-queries.ts create mode 100644 apps/medusa/src/admin/hooks/use-query-params.tsx create mode 100644 apps/medusa/src/admin/layouts/single-column.tsx create mode 100644 apps/medusa/src/admin/routes/content/components/posts-data-table/index.tsx create mode 100644 apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-data-table-columns.tsx create mode 100644 apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-table-query.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/breadcrumbs.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/editor-modal.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/editor-sidebar.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/editor-top-bar.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/main-content.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/nav-item.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/post-editor-layout.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/post-settings-sidebar.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/sidebar-container.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/components/sidebar-toggle.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/hooks/use-editor-sidebar.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/hooks/use-loading-state.ts create mode 100644 apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-context.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-provider.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/test/page.tsx create mode 100644 apps/medusa/src/admin/routes/content/page.tsx create mode 100644 apps/medusa/src/admin/sdk.ts create mode 100644 apps/medusa/src/admin/vite-env.d.ts create mode 100644 apps/medusa/src/api/admin/content/posts/[id]/duplicate/route.ts create mode 100644 apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts create mode 100644 apps/medusa/src/api/admin/content/posts/[id]/route.tsx create mode 100644 apps/medusa/src/api/admin/content/posts/middlewares.ts create mode 100644 apps/medusa/src/api/admin/content/posts/route.ts create mode 100644 apps/medusa/src/api/admin/content/validations.ts create mode 100644 apps/medusa/src/api/middlewares.ts create mode 100644 apps/medusa/src/links/post-author-user.ts create mode 100644 apps/medusa/src/links/post-tag-user.ts create mode 100644 apps/medusa/src/modules/page-builder/enum-values.ts create mode 100644 apps/medusa/src/modules/page-builder/index.ts create mode 100644 apps/medusa/src/modules/page-builder/migrations/.snapshot-medusa-page-builder.json create mode 100644 apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts create mode 100644 apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts create mode 100644 apps/medusa/src/modules/page-builder/models/image.ts create mode 100644 apps/medusa/src/modules/page-builder/models/index.ts create mode 100644 apps/medusa/src/modules/page-builder/models/navigation-item.ts create mode 100644 apps/medusa/src/modules/page-builder/models/post-author.ts create mode 100644 apps/medusa/src/modules/page-builder/models/post-section.ts create mode 100644 apps/medusa/src/modules/page-builder/models/post-tag.ts create mode 100644 apps/medusa/src/modules/page-builder/models/post-template.ts create mode 100644 apps/medusa/src/modules/page-builder/models/post.ts create mode 100644 apps/medusa/src/modules/page-builder/models/site-settings.ts create mode 100644 apps/medusa/src/modules/page-builder/service.ts create mode 100644 apps/medusa/src/workflows/create-post.ts create mode 100644 apps/medusa/src/workflows/delete-post.ts create mode 100644 apps/medusa/src/workflows/duplicate-post.ts create mode 100644 apps/medusa/src/workflows/steps/create-post.ts create mode 100644 apps/medusa/src/workflows/steps/delete-post.ts create mode 100644 apps/medusa/src/workflows/steps/duplicate-post-relations.ts create mode 100644 apps/medusa/src/workflows/steps/duplicate-post.ts create mode 100644 apps/medusa/src/workflows/steps/update-post.ts create mode 100644 apps/medusa/src/workflows/types/index.ts create mode 100644 apps/medusa/src/workflows/update-post.ts create mode 100644 packages/page-builder-sdk/.gitignore create mode 100644 packages/page-builder-sdk/README.md create mode 100644 packages/page-builder-sdk/package.json create mode 100644 packages/page-builder-sdk/src/index.ts create mode 100644 packages/page-builder-sdk/src/sdk/admin/admin-page-builder.ts create mode 100644 packages/page-builder-sdk/src/sdk/admin/index.ts create mode 100644 packages/page-builder-sdk/src/sdk/index.ts create mode 100644 packages/page-builder-sdk/src/sdk/store/index.ts create mode 100644 packages/page-builder-sdk/src/sdk/store/store-page-builder.ts create mode 100644 packages/page-builder-sdk/src/types/index.ts create mode 100644 packages/page-builder-sdk/src/types/product-review-stats.ts create mode 100644 packages/page-builder-sdk/src/types/product-reviews.ts create mode 100644 packages/page-builder-sdk/tsconfig.esm.json create mode 100644 packages/page-builder-sdk/tsconfig.json create mode 100644 packages/page-builder-sdk/tsup.config.ts create mode 100644 packages/page-builder-types/.gitignore create mode 100644 packages/page-builder-types/package.json create mode 100644 packages/page-builder-types/src/admins.d.ts create mode 100644 packages/page-builder-types/src/common.d.ts create mode 100644 packages/page-builder-types/src/index.d.ts create mode 100644 packages/page-builder-types/src/models.d.ts create mode 100644 packages/page-builder-types/src/storefronts.d.ts diff --git a/apps/medusa/package.json b/apps/medusa/package.json index 457575b47..9c1a4c2b3 100644 --- a/apps/medusa/package.json +++ b/apps/medusa/package.json @@ -33,12 +33,12 @@ }, "dependencies": { "@lambdacurry/medusa-product-reviews": "1.2.0", - "@medusajs/admin-sdk": "2.7.0", - "@medusajs/cli": "2.7.0", - "@medusajs/framework": "2.7.0", - "@medusajs/js-sdk": "2.7.0", - "@medusajs/medusa": "2.7.0", - "@medusajs/types": "2.7.0", + "@medusajs/admin-sdk": "2.8.2", + "@medusajs/cli": "2.8.2", + "@medusajs/framework": "2.8.2", + "@medusajs/js-sdk": "2.8.2", + "@medusajs/medusa": "2.8.2", + "@medusajs/types": "2.8.2", "@mikro-orm/core": "6.4.3", "@mikro-orm/knex": "6.4.3", "@mikro-orm/migrations": "6.4.3", @@ -47,7 +47,7 @@ "pg": "^8.13.0" }, "devDependencies": { - "@medusajs/test-utils": "2.7.0", + "@medusajs/test-utils": "2.8.2", "@mikro-orm/cli": "6.4.3", "@mikro-orm/core": "6.4.3", "@mikro-orm/migrations": "6.4.3", diff --git a/apps/medusa/src/admin/components/action-menu.tsx b/apps/medusa/src/admin/components/action-menu.tsx new file mode 100644 index 000000000..3444f24b8 --- /dev/null +++ b/apps/medusa/src/admin/components/action-menu.tsx @@ -0,0 +1,100 @@ +import { + DropdownMenu, + IconButton, + clx, +} from "@medusajs/ui" +import { EllipsisHorizontal } from "@medusajs/icons" +import { Link } from "react-router-dom" + +export type Action = { + icon: React.ReactNode + label: string + disabled?: boolean +} & ( + | { + to: string + onClick?: never + } + | { + onClick: () => void + to?: never + } +) + +export type ActionGroup = { + actions: Action[] +} + +export type ActionMenuProps = { + groups: ActionGroup[] +} + +export const ActionMenu = ({ groups }: ActionMenuProps) => { + return ( + + + + + + + + {groups.map((group, index) => { + if (!group.actions.length) { + return null + } + + const isLast = index === groups.length - 1 + + return ( + + {group.actions.map((action, index) => { + if (action.onClick) { + return ( + { + e.stopPropagation() + action.onClick() + }} + className={clx( + "[&_svg]:text-ui-fg-subtle flex items-center gap-x-2", + { + "[&_svg]:text-ui-fg-disabled": action.disabled, + } + )} + > + {action.icon} + {action.label} + + ) + } + + return ( +
+ + e.stopPropagation()}> + {action.icon} + {action.label} + + +
+ ) + })} + {!isLast && } +
+ ) + })} +
+
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/components/header.tsx b/apps/medusa/src/admin/components/header.tsx new file mode 100644 index 000000000..253b44bc5 --- /dev/null +++ b/apps/medusa/src/admin/components/header.tsx @@ -0,0 +1,66 @@ +import { Heading, Button, Text } from "@medusajs/ui" +import React, { Fragment } from "react" +import { Link, LinkProps } from "react-router-dom" +import { ActionMenu, ActionMenuProps } from "./action-menu" + +export type HeadingProps = { + title: string + subtitle?: string + actions?: ( + { + type: "button", + props: React.ComponentProps + link?: LinkProps + } | + { + type: "action-menu" + props: ActionMenuProps + } | + { + type: "custom" + children: React.ReactNode + } + )[] +} + +export const Header = ({ + title, + subtitle, + actions = [], +}: HeadingProps) => { + return ( +
+
+ {title} + {subtitle && ( + + {subtitle} + + )} +
+ {actions.length > 0 && ( +
+ {actions.map((action, index) => ( + + {action.type === "button" && ( + + )} + {action.type === "action-menu" && ( + + )} + {action.type === "custom" && action.children} + + ))} +
+ )} +
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/hooks/posts-mutations.ts b/apps/medusa/src/admin/hooks/posts-mutations.ts new file mode 100644 index 000000000..5692c37b1 --- /dev/null +++ b/apps/medusa/src/admin/hooks/posts-mutations.ts @@ -0,0 +1,65 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import type { + AdminPageBuilderCreatePostBody, + AdminPageBuilderCreatePostResponse, + AdminPageBuilderDeletePostResponse, + AdminPageBuilderDuplicatePostResponse, + AdminPageBuilderUpdatePostBody, + AdminPageBuilderUpdatePostResponse, +} from '@lambdacurry/page-builder-types'; + +import { sdk } from '../sdk'; + +const QUERY_KEY = ['posts']; + +export const useAdminCreatePost = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async (data) => { + return sdk.admin.pageBuilder.createPost(data); + }, + mutationKey: QUERY_KEY, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: QUERY_KEY }); + }, + }); +}; + +export const useAdminUpdatePost = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async (data) => { + return sdk.admin.pageBuilder.updatePost(data.id, data); + }, + mutationKey: QUERY_KEY, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: QUERY_KEY }); + }, + }); +}; + +export const useAdminDeletePost = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async (id: string) => { + return sdk.admin.pageBuilder.deletePost(id); + }, + mutationKey: QUERY_KEY, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: QUERY_KEY }); + }, + }); +}; + +export const useAdminDuplicatePost = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async (id: string) => { + return sdk.admin.pageBuilder.duplicatePost(id); + }, + mutationKey: QUERY_KEY, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: QUERY_KEY }); + }, + }); +}; diff --git a/apps/medusa/src/admin/hooks/posts-queries.ts b/apps/medusa/src/admin/hooks/posts-queries.ts new file mode 100644 index 000000000..3df41756e --- /dev/null +++ b/apps/medusa/src/admin/hooks/posts-queries.ts @@ -0,0 +1,32 @@ +import { useQuery } from '@tanstack/react-query'; +import type { + AdminPageBuilderListPostsQuery, + AdminPageBuilderListPostsResponse, + Post, +} from '@lambdacurry/page-builder-types'; + +import { sdk } from '../sdk'; + +const QUERY_KEY = ['posts']; + +export const useAdminListPosts = (query: AdminPageBuilderListPostsQuery) => { + return useQuery({ + queryKey: [...QUERY_KEY, query], + queryFn: async () => { + return sdk.admin.pageBuilder.listPosts(query); + }, + }); +}; + +export const useAdminFetchPost = (id: string) => { + return useQuery({ + queryKey: [...QUERY_KEY, id], + queryFn: async () => { + const post = await sdk.admin.pageBuilder.listPosts({ + id, + } as AdminPageBuilderListPostsQuery); + + return post?.posts?.[0]; + }, + }); +}; diff --git a/apps/medusa/src/admin/hooks/use-query-params.tsx b/apps/medusa/src/admin/hooks/use-query-params.tsx new file mode 100644 index 000000000..39ba4652c --- /dev/null +++ b/apps/medusa/src/admin/hooks/use-query-params.tsx @@ -0,0 +1,50 @@ +import { useSearchParams } from "react-router-dom"; +import { useMemo } from "react"; + +type QueryParams = { + [key in T]: string | undefined; +}; + +type SetQueryParams = ( + params: Partial>, +) => void; + +export function useQueryParams( + keys: T[], + prefix?: string, +): { queryObject: QueryParams; setQueryObject: SetQueryParams } { + const [params, setParams] = useSearchParams(); + + // Use useMemo to create the query object from URL params + const queryObject = useMemo(() => { + const result = {} as QueryParams; + + for (const key of keys) { + const prefixedKey = prefix ? `${prefix}_${key}` : key; + const value = params.get(prefixedKey) || undefined; + result[key] = value; + } + + return result; + }, [keys, params, prefix]); + + const setQueryObject = (newParams: Partial>) => { + const newSearchParams = new URLSearchParams(params); + + for (const [key, value] of Object.entries(newParams)) { + const prefixedKey = prefix ? `${prefix}_${key}` : key; + if (value === undefined || value === null) { + newSearchParams.delete(prefixedKey); + } else { + newSearchParams.set(prefixedKey, String(value)); + } + } + + setParams(newSearchParams); + }; + + return { + queryObject, + setQueryObject, + }; +} diff --git a/apps/medusa/src/admin/layouts/single-column.tsx b/apps/medusa/src/admin/layouts/single-column.tsx new file mode 100644 index 000000000..539ac1467 --- /dev/null +++ b/apps/medusa/src/admin/layouts/single-column.tsx @@ -0,0 +1,16 @@ +import { Toaster } from "@medusajs/ui" + +export type SingleColumnLayoutProps = { + children: React.ReactNode +} + +export const SingleColumnLayout = ({ children }: SingleColumnLayoutProps) => { + return ( + <> + +
+ {children} +
+ + ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/components/posts-data-table/index.tsx b/apps/medusa/src/admin/routes/content/components/posts-data-table/index.tsx new file mode 100644 index 000000000..53a021a0c --- /dev/null +++ b/apps/medusa/src/admin/routes/content/components/posts-data-table/index.tsx @@ -0,0 +1,145 @@ +import { createDataTableFilterHelper, DataTable, toast, useDataTable, TooltipProvider } from '@medusajs/ui'; +import { useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { usePostsDataTableColumns } from './use-post-data-table-columns'; +import { useAdminListPosts } from '../../../../hooks/posts-queries'; +import type { Post, PostStatus, PostType } from '@lambdacurry/page-builder-types'; +import { useAdminDeletePost, useAdminDuplicatePost } from '../../../../hooks/posts-mutations'; +import { usePostTableQuery } from './use-post-table-query'; + +// Create filter helper +const filterHelper = createDataTableFilterHelper(); + +// Define filters +const filters = [ + filterHelper.accessor('status', { + type: 'select', + label: 'Status', + options: [ + { + label: 'Published', + value: 'published', + }, + { + label: 'Draft', + value: 'draft', + }, + ], + }), + filterHelper.accessor('type', { + type: 'select', + label: 'Type', + options: [ + { + label: 'Page', + value: 'page', + }, + { + label: 'Post', + value: 'post', + }, + ], + }), +]; + +export const PostsDataTable = () => { + const navigate = useNavigate(); + const { mutateAsync: deletePost } = useAdminDeletePost(); + const { mutateAsync: duplicatePost } = useAdminDuplicatePost(); + const limit = 10; + + // Get all query state from the hook + const { + searchParams, + pagination, + filtering, + sorting, + search, + setPaginationState, + setFilteringState, + setSortingState, + setSearchState, + } = usePostTableQuery({ + pageSize: limit, + }); + + const statusFilters = useMemo(() => { + return (filtering.status || []) as PostStatus[]; + }, [filtering]); + + const typeFilters = useMemo(() => { + return (filtering.type || []) as PostType[]; + }, [filtering]); + + const handleEdit = (id: string) => { + navigate('editor/test'); // TODO: change to the actual content detail page + }; + + const handleDuplicate = async (id: string) => { + await duplicatePost(id); + toast.success('Page duplicated'); + }; + + const handleDelete = async (id: string) => { + await deletePost(id); + toast.success('Page deleted'); + }; + + const columns = usePostsDataTableColumns({ + onEdit: handleEdit, + onDuplicate: handleDuplicate, + onDelete: handleDelete, + }); + + const { data, isLoading } = useAdminListPosts({ + ...searchParams, + status: statusFilters.length > 0 ? statusFilters : undefined, + type: typeFilters.length > 0 ? typeFilters : undefined, + order: sorting ? `${sorting.desc ? '-' : ''}${sorting.id}` : undefined, + }); + + const table = useDataTable({ + onRowClick: (_, row) => handleEdit(row.id), + columns, + data: data?.posts || [], + getRowId: (row) => row.id, + rowCount: data?.count || 0, + isLoading, + pagination: { + state: pagination, + onPaginationChange: setPaginationState, + }, + search: { + state: search, + onSearchChange: setSearchState, + }, + filtering: { + state: filtering, + onFilteringChange: setFilteringState, + }, + filters, + sorting: { + state: sorting, + onSortingChange: setSortingState, + }, + }); + console.log('🚀 ~ PostsDataTable ~ filters:', filters); + console.log('🚀 ~ PostsDataTable ~ filtering:', filtering); + + return ( + + +
+ {/* Do not remove this tooltip */} + +
+ + +
+
+
+ + +
+ ); +}; diff --git a/apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-data-table-columns.tsx b/apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-data-table-columns.tsx new file mode 100644 index 000000000..1e32fbf26 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-data-table-columns.tsx @@ -0,0 +1,115 @@ +import React from 'react'; +import { createDataTableColumnHelper, Text, StatusBadge, usePrompt } from '@medusajs/ui'; +import { PencilSquare, SquareTwoStackMini, Trash } from '@medusajs/icons'; +import type { Post } from '@lambdacurry/page-builder-types'; + +export type ColumnActions = { + onEdit?: (id: string) => void; + onDuplicate?: (id: string) => void; + onDelete?: (id: string) => void; +}; + +const columnHelper = createDataTableColumnHelper(); + +/** + * Hook that returns column definitions for the PostsDataTable + */ +export const usePostsDataTableColumns = (actions: ColumnActions = {}) => { + const { onEdit, onDuplicate, onDelete } = actions; + const prompt = usePrompt(); + + return React.useMemo( + () => [ + columnHelper.accessor('title', { + header: 'Title', + enableSorting: true, + sortLabel: 'Title', + }), + columnHelper.accessor('handle', { + header: 'Handle', + enableSorting: true, + }), + columnHelper.accessor('status', { + header: 'Status', + cell: ({ getValue }) => { + const status = getValue(); + return ( + + {status === 'published' ? 'Published' : 'Draft'} + + ); + }, + enableSorting: true, + }), + columnHelper.accessor('type', { + header: 'Type', + enableSorting: true, + }), + columnHelper.accessor('created_at', { + header: 'Date Created', + cell: ({ getValue }) => { + const date = new Date(getValue()); + return {date.toLocaleDateString()}; + }, + enableSorting: true, + }), + columnHelper.accessor('updated_at', { + header: 'Last Updated', + cell: ({ getValue }) => { + const dateValue = getValue(); + if (!dateValue) return ; + + const date = new Date(dateValue); + return {date.toLocaleDateString()}; + }, + enableSorting: true, + }), + columnHelper.action({ + // @ts-ignore + actions: ({ row }) => [ + [ + { + icon: , + label: 'Edit', + onClick: () => { + if (onEdit) { + onEdit(row.original.id); + } else { + console.log('edit', row.original.id); + } + }, + }, + ], + [ + { + icon: , + label: 'Duplicate', + onClick: () => { + onDuplicate?.(row.original.id); + }, + }, + ], + [ + { + icon: , + label: 'Delete', + onClick: async () => { + const res = await prompt({ + title: 'Are you sure?', + description: `You are about to delete the page "${row.original.title}". This action cannot be undone.`, + confirmText: 'Delete', + cancelText: 'Cancel', + }); + + if (!res) return; + + onDelete?.(row.original.id); + }, + }, + ], + ], + }), + ], + [onEdit, onDuplicate, onDelete, prompt], + ); +}; diff --git a/apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-table-query.tsx b/apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-table-query.tsx new file mode 100644 index 000000000..70d7d9c0a --- /dev/null +++ b/apps/medusa/src/admin/routes/content/components/posts-data-table/use-post-table-query.tsx @@ -0,0 +1,217 @@ +import { useMemo } from 'react'; +import type { DataTableFilteringState, DataTablePaginationState, DataTableSortingState } from '@medusajs/ui'; +import type { + PostContentMode, + PostType, + PostStatus, + AdminPageBuilderListPostsQuery, +} from '@lambdacurry/page-builder-types'; + +import { useQueryParams } from '../../../../hooks/use-query-params'; + +type UsePostTableQueryProps = { + prefix?: string; + pageSize?: number; +}; + +const DEFAULT_FIELDS = [ + 'id', + 'type', + 'title', + 'handle', + 'excerpt', + 'status', + 'published_at', + 'archived_at', + 'is_home_page', + 'created_at', + 'updated_at', + 'featured_image.*', +].join(','); + +export const usePostTableQuery = ({ prefix, pageSize = 10 }: UsePostTableQueryProps) => { + const { queryObject, setQueryObject } = useQueryParams( + [ + 'offset', + 'order', + 'q', + 'title', + 'handle', + 'status', + 'type', + 'content_mode', + 'is_home_page', + 'published_at', + 'archived_at', + 'created_at', + 'updated_at', + 'id', + ], + prefix, + ); + + const { + offset, + title, + handle, + status, + type, + content_mode, + is_home_page, + published_at, + archived_at, + created_at, + updated_at, + order, + q, + } = queryObject; + + // Derived state for data table + const pagination = useMemo( + () => ({ + pageSize, + pageIndex: offset ? Math.floor(Number(offset) / pageSize) : 0, + }), + [offset, pageSize], + ); + + const filtering = useMemo(() => { + const filterState: DataTableFilteringState = {}; + + if (status) { + filterState.status = Array.isArray(status) ? status : status.split(','); + } + + if (type) { + filterState.type = Array.isArray(type) ? type : type.split(','); + } + + return filterState; + }, [status, type]); + + const sorting = useMemo(() => { + if (order) { + const isDesc = order.startsWith('-'); + const field = isDesc ? order.substring(1) : order; + return { + id: field, + desc: isDesc, + }; + } + return null; + }, [order]); + + const searchParams: AdminPageBuilderListPostsQuery = { + limit: pageSize, + offset: offset ? Number(offset) : 0, + title: title, + handle: handle, + status: status?.split(',') as PostStatus[], + type: type?.split(',') as PostType[], + content_mode: content_mode?.split(',') as PostContentMode[], + is_home_page: is_home_page ? is_home_page === 'true' : undefined, + published_at: published_at ? JSON.parse(published_at) : undefined, + archived_at: archived_at ? JSON.parse(archived_at) : undefined, + created_at: created_at ? JSON.parse(created_at) : undefined, + updated_at: updated_at ? JSON.parse(updated_at) : undefined, + order: order, + q, + fields: DEFAULT_FIELDS, + }; + + // State updaters + const setSearchParams = (params: Partial) => { + const newQueryObject: Record = {}; + + if ('q' in params) { + newQueryObject.q = params.q || undefined; + } + + if ('status' in params) { + if (params.status && Array.isArray(params.status) && params.status.length > 0) { + newQueryObject.status = params.status.join(','); + } else if (typeof params.status === 'string') { + newQueryObject.status = params.status; + } else { + newQueryObject.status = undefined; + } + } + + if ('type' in params) { + if (params.type && Array.isArray(params.type) && params.type.length > 0) { + newQueryObject.type = params.type.join(','); + } else if (typeof params.type === 'string') { + newQueryObject.type = params.type; + } else { + newQueryObject.type = undefined; + } + } + + if ('content_mode' in params) { + if (params.content_mode && Array.isArray(params.content_mode) && params.content_mode.length > 0) { + newQueryObject.content_mode = params.content_mode.join(','); + } else if (typeof params.content_mode === 'string') { + newQueryObject.content_mode = params.content_mode; + } else { + newQueryObject.content_mode = undefined; + } + } + + if (params.is_home_page !== undefined) { + newQueryObject.is_home_page = params.is_home_page?.toString(); + } + + if (params.order !== undefined) { + newQueryObject.order = params.order || undefined; + } + + if (params.offset !== undefined) { + newQueryObject.offset = params.offset?.toString(); + } + + setQueryObject(newQueryObject); + }; + + // Simplified handlers for common operations + const setPaginationState = (newPagination: DataTablePaginationState) => { + setSearchParams({ offset: newPagination.pageIndex * pageSize }); + }; + + const setFilteringState = (newFiltering: DataTableFilteringState) => { + console.log('🚀 ~ setFilteringState ~ newFiltering:', newFiltering); + setSearchParams({ + status: (newFiltering.status || []) as PostStatus[], + type: (newFiltering.type || []) as PostType[], + }); + }; + + const setSortingState = (newSorting: DataTableSortingState | null) => { + if (newSorting) { + setSearchParams({ + order: `${newSorting.desc ? '-' : ''}${newSorting.id}`, + }); + } else { + setSearchParams({ order: undefined }); + } + }; + + const setSearchState = (search: string) => { + setSearchParams({ q: search || undefined }); + }; + + return { + searchParams, + raw: queryObject, + setSearchParams, + // Derived state + pagination, + filtering, + sorting, + search: q || '', + // State updaters + setPaginationState, + setFilteringState, + setSortingState, + setSearchState, + }; +}; diff --git a/apps/medusa/src/admin/routes/content/editor/components/breadcrumbs.tsx b/apps/medusa/src/admin/routes/content/editor/components/breadcrumbs.tsx new file mode 100644 index 000000000..8cfd0b126 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/breadcrumbs.tsx @@ -0,0 +1,81 @@ +import { clx } from "@medusajs/ui" +import { TriangleRightMini } from "@medusajs/icons" +import { Link, useLoaderData } from "react-router-dom" + +type Crumb = { + label: string + path?: string +} + +export const Breadcrumbs = () => { + const data = useLoaderData() as any + + const crumbs: Crumb[] = [ + { + label: "Home", + path: "/", + }, + { + label: "Content", + path: "/content", + }, + ] + + if (data?.post) { + const post = data.post + const type = post.type?.charAt(0).toUpperCase() + post.type?.slice(1) as string + + crumbs.push(...[ + { + label: type, + }, + { + label: post.title as string, + path: post.id as string, + }, + ]) + } + + return ( +
    + {crumbs.map((crumb, index) => { + const isLast = index === crumbs.length - 1 + const isSingle = crumbs.length === 1 + + return ( +
  1. + {!isLast && crumb.path ? ( + + {crumb.label} + + ) : ( +
    + {!isSingle && isLast && ...} + + {crumb.label} + +
    + )} + {!isLast && ( + + + + )} +
  2. + ) + })} +
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/editor-modal.tsx b/apps/medusa/src/admin/routes/content/editor/components/editor-modal.tsx new file mode 100644 index 000000000..d24b3d4a8 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/editor-modal.tsx @@ -0,0 +1,206 @@ +"use client" + +import { clx } from "@medusajs/ui" +import { Dialog as RadixDialog } from "radix-ui" +import * as React from "react" + +/** + * @prop defaultOpen - Whether the modal is opened by default. + * @prop open - Whether the modal is opened. + * @prop onOpenChange - A function to handle when the modal is opened or closed. + */ +interface EditorModalRootProps + extends React.ComponentPropsWithoutRef {} + +/** + * This component is based on the [Radix UI Dialog](https://www.radix-ui.com/primitives/docs/components/dialog) primitives. + */ +const EditorModalRoot = (props: EditorModalRootProps) => { + return +} +EditorModalRoot.displayName = "EditorModal" + +interface EditorModalTriggerProps extends React.ComponentPropsWithoutRef {} + +/** + * This component is used to create the trigger button that opens the modal. + * It accepts props from the [Radix UI Dialog Trigger](https://www.radix-ui.com/primitives/docs/components/dialog#trigger) component. + */ +const EditorModalTrigger = React.forwardRef< + React.ElementRef, + EditorModalTriggerProps +>((props: EditorModalTriggerProps, ref) => { + return +}) +EditorModalTrigger.displayName = "EditorModal.Trigger" + +// /** +// * This component is used to create the close button for the modal. +// * It accepts props from the [Radix UI Dialog Close](https://www.radix-ui.com/primitives/docs/components/dialog#close) component. +// */ +// const EditorModalClose = RadixDialog.Close +// EditorModalClose.displayName = "EditorModal.Close" + +interface EditorModalPortalProps extends RadixDialog.DialogPortalProps {} + +/** + * The `EditorModal.Content` component uses this component to wrap the modal content. + * It accepts props from the [Radix UI Dialog Portal](https://www.radix-ui.com/primitives/docs/components/dialog#portal) component. + */ +const EditorModalPortal = (props: EditorModalPortalProps) => { + return ( + + ) +} +EditorModalPortal.displayName = "EditorModal.Portal" + +/** + * This component is used to create the overlay for the modal. + * It accepts props from the [Radix UI Dialog Overlay](https://www.radix-ui.com/primitives/docs/components/dialog#overlay) component. + */ +const EditorModalOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + return ( + + ) +}) +EditorModalOverlay.displayName = "EditorModal.Overlay" + +/** + * This component wraps the content of the modal. + * It accepts props from the [Radix UI Dialog Content](https://www.radix-ui.com/primitives/docs/components/dialog#content) component. + */ +const EditorModalContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + overlayProps?: React.ComponentPropsWithoutRef + portalProps?: React.ComponentPropsWithoutRef + } +>(({ className, overlayProps, portalProps, ...props }, ref) => { + return ( + + + + + ) +}) +EditorModalContent.displayName = "EditorModal.Content" + +/** + * This component is used to wrap the header content of the modal. + * This component is based on the `div` element and supports all of its props + */ +const EditorModalHeader = React.forwardRef< + HTMLDivElement, + React.ComponentPropsWithoutRef<"div"> +>(({ children, className, ...props }, ref) => { + return ( +
+ {/*
+ + + + + +
*/} + {children} +
+ ) +}) +EditorModalHeader.displayName = "EditorModal.Header" + +/** + * This component is used to wrap the footer content of the modal. + * This component is based on the `div` element and supports all of its props + */ +const EditorModalFooter = React.forwardRef< + HTMLDivElement, + React.ComponentPropsWithoutRef<"div"> +>(({ children, className, ...props }, ref) => { + return ( +
+ {children} +
+ ) +}) +EditorModalFooter.displayName = "EditorModal.Footer" + +interface EditorModalTitleProps extends React.ComponentPropsWithoutRef {} + +/** + * This component adds an accessible title to the modal. + * It accepts props from the [Radix UI Dialog Title](https://www.radix-ui.com/primitives/docs/components/dialog#title) component. + */ +const EditorModalTitle = React.forwardRef< + HTMLHeadingElement, + EditorModalTitleProps +>(({ className, ...props }: EditorModalTitleProps, ref) => { + return ( + + ) +}) +EditorModalTitle.displayName = "EditorModal.Title" + +/** + * This component adds accessible description to the modal. + * It accepts props from the [Radix UI Dialog Description](https://www.radix-ui.com/primitives/docs/components/dialog#description) component. + */ +const EditorModalDescription = RadixDialog.Description +EditorModalDescription.displayName = "EditorModal.Description" + +/** + * This component is used to wrap the body content of the modal. + * This component is based on the `div` element and supports all of its props + */ +const EditorModalBody = React.forwardRef< + HTMLDivElement, + React.ComponentPropsWithoutRef<"div"> +>(({ className, ...props }, ref) => { + return
+}) +EditorModalBody.displayName = "EditorModal.Body" + +const EditorModal = Object.assign(EditorModalRoot, { + Trigger: EditorModalTrigger, + Title: EditorModalTitle, + Description: EditorModalDescription, + Content: EditorModalContent, + Header: EditorModalHeader, + Body: EditorModalBody, + // Close: EditorModalClose, + Footer: EditorModalFooter, +}) + +export { EditorModal } \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/editor-sidebar.tsx b/apps/medusa/src/admin/routes/content/editor/components/editor-sidebar.tsx new file mode 100644 index 000000000..1ad9e60ee --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/editor-sidebar.tsx @@ -0,0 +1,61 @@ +import { SquareTwoStackSolid } from "@medusajs/icons" + +import { SidebarContainer } from "./sidebar-container" +import { INavItem, NavItem } from "./nav-item" + +export const EditorSidebar = () => { + const sidebarContent = ( + + ) + + return ( + <> + + {sidebarContent} + + + {sidebarContent} + + + ) +} + +const sections: INavItem[] = [ + { + icon: , + label: 'Section 1', + to: "sections/section_id_1", + }, + { + icon: , + label: 'Section 2', + to: "sections/section_id_2", + }, + { + icon: , + label: 'Section 3', + to: "sections/section_id_3", + }, + { + icon: , + label: 'Section 4', + to: "sections/section_id_4", + }, + { + icon: , + label: 'Section 5', + to: "sections/section_id_5", + }, +] + +const SectionsMenu = () => { + return ( + + ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/editor-top-bar.tsx b/apps/medusa/src/admin/routes/content/editor/components/editor-top-bar.tsx new file mode 100644 index 000000000..4b59d7fbc --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/editor-top-bar.tsx @@ -0,0 +1,18 @@ +import { Button } from "@medusajs/ui" +import { Breadcrumbs } from "./breadcrumbs" +import { SidebarToggle } from "./sidebar-toggle" + +export const EditorTopbar = () => { + return ( +
+
+ + +
+
+ + +
+
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/main-content.tsx b/apps/medusa/src/admin/routes/content/editor/components/main-content.tsx new file mode 100644 index 000000000..50e802e00 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/main-content.tsx @@ -0,0 +1,23 @@ +import { clx } from "@medusajs/ui" +import { PropsWithChildren } from "react" + +import { useLoadingState } from "../hooks/use-loading-state" + +export const MainContent = ({ children }: PropsWithChildren) => { + const { isLoading } = useLoadingState() + + return ( +
+
+ {children} +
+
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/nav-item.tsx b/apps/medusa/src/admin/routes/content/editor/components/nav-item.tsx new file mode 100644 index 000000000..9d4a61ee1 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/nav-item.tsx @@ -0,0 +1,37 @@ +import { Text } from '@medusajs/ui' +import { ReactNode } from 'react' +import { NavLink } from 'react-router-dom' + +export type INavItem = { + icon?: ReactNode + label: string + to: string + from?: string +} + +const BASE_NAV_LINK_CLASSES = + 'text-ui-fg-subtle transition-fg hover:bg-ui-bg-subtle-hover flex items-center gap-x-2 rounded-md py-0.5 pl-0.5 pr-2 outline-none [&>svg]:text-ui-fg-subtle focus-visible:shadow-borders-focus' + +export const NavItem = ({ icon, label, to, from }: INavItem) => { + return ( +
+ +
{icon}
+ + {label} + +
+
+ ) +} diff --git a/apps/medusa/src/admin/routes/content/editor/components/post-editor-layout.tsx b/apps/medusa/src/admin/routes/content/editor/components/post-editor-layout.tsx new file mode 100644 index 000000000..0941d5e3f --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/post-editor-layout.tsx @@ -0,0 +1,20 @@ +import { PropsWithChildren } from "react" +import { TooltipProvider } from "@medusajs/ui" + +import { MainContent } from "./main-content" +import { EditorSidebar } from "./editor-sidebar" +import { PostSettingsSidebar } from "./post-settings-sidebar" + +type PostEditorLayoutProps = PropsWithChildren + +export const PostEditorLayout = ({ children }: PostEditorLayoutProps) => { + return ( + +
+ + {children} + +
+
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/post-settings-sidebar.tsx b/apps/medusa/src/admin/routes/content/editor/components/post-settings-sidebar.tsx new file mode 100644 index 000000000..8e2dbb912 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/post-settings-sidebar.tsx @@ -0,0 +1,30 @@ +import { useLoaderData } from "react-router-dom" +import { SidebarContainer } from "./sidebar-container" + +export const PostSettingsSidebar = () => { + const data = useLoaderData() as any + const post = data?.post + const type = post?.type ? post.type?.charAt(0).toUpperCase() + post.type?.slice(1) as string : "Post" + + return ( + + + + ) +} + +type PostSettingsMenuProps = { + post: Record +} + +const PostSettingsMenu = ({ post }: PostSettingsMenuProps) => { + return ( +
+

+ Settings +

+
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/sidebar-container.tsx b/apps/medusa/src/admin/routes/content/editor/components/sidebar-container.tsx new file mode 100644 index 000000000..10f4bbc2b --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/sidebar-container.tsx @@ -0,0 +1,68 @@ +import { XMark } from "@medusajs/icons" +import { Drawer, IconButton, clx } from "@medusajs/ui" +import { PropsWithChildren } from "react" +import { useEditorSidebar } from "../hooks/use-editor-sidebar" + +type DrawerSidebarContainerProps = PropsWithChildren & { + title?: string + side?: "left" | "right" +} + +const DrawerSidebarContainer = ({ title, children, side = "left" }: DrawerSidebarContainerProps) => { + const { left, right, toggleLeft, toggleRight } = useEditorSidebar() + + const isOpen = side === "left" ? left.drawer : right.drawer + const toggle = side === "left" + ? () => toggleLeft("drawer") + : () => toggleRight("drawer") + + return ( + + +
+ {title} + + + +
+
+ {children} +
+
+
+ ) +} + +const StaticSidebarContainer = ({ children, side = "left" }: PropsWithChildren & { side?: "left" | "right" }) => { + const { left, right } = useEditorSidebar() + const isOpen = side === "left" ? left.static : right.static + + return ( +
+ {children} +
+ ) +} + +export const SidebarContainer = { + Drawer: DrawerSidebarContainer, + Static: StaticSidebarContainer +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/components/sidebar-toggle.tsx b/apps/medusa/src/admin/routes/content/editor/components/sidebar-toggle.tsx new file mode 100644 index 000000000..179a82081 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/components/sidebar-toggle.tsx @@ -0,0 +1,34 @@ +import { SidebarLeft, SidebarRight } from "@medusajs/icons" +import { IconButton, Tooltip, TooltipProvider } from "@medusajs/ui" +import { useEditorSidebar } from "../hooks/use-editor-sidebar" + +export const SidebarToggle = ({ side, drawerOnly = false }: { side: "left" | "right", drawerOnly?: boolean }) => { + const { toggleLeft, toggleRight } = useEditorSidebar() + const toggle = side === "left" ? toggleLeft : toggleRight + const Icon = side === "left" ? SidebarLeft : SidebarRight + + return ( + + +
+ toggle(drawerOnly ? "drawer" : "static")} + size="small" + > + + + toggle("drawer")} + size="small" + > + + +
+
+
+ ) +} \ No newline at end of file diff --git a/apps/medusa/src/admin/routes/content/editor/hooks/use-editor-sidebar.tsx b/apps/medusa/src/admin/routes/content/editor/hooks/use-editor-sidebar.tsx new file mode 100644 index 000000000..321ef7bd4 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/hooks/use-editor-sidebar.tsx @@ -0,0 +1,12 @@ +import { useContext } from "react" +import { EditorSidebarContext, EditorSidebarContextType } from "../providers/editor-sidebar-context" + +export const useEditorSidebar = (): EditorSidebarContextType => { + const context = useContext(EditorSidebarContext) + + if (!context) { + throw new Error("useEditorSidebar must be used within a EditorSidebarProvider") + } + + return context +} diff --git a/apps/medusa/src/admin/routes/content/editor/hooks/use-loading-state.ts b/apps/medusa/src/admin/routes/content/editor/hooks/use-loading-state.ts new file mode 100644 index 000000000..9b4770f0d --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/hooks/use-loading-state.ts @@ -0,0 +1,14 @@ +import { useNavigation } from 'react-router-dom' + +/** + * Hook to track the loading state of the application + * @returns Object containing the loading state + */ +export const useLoadingState = () => { + const navigation = useNavigation() + const isLoading = navigation.state === 'loading' + + return { + isLoading, + } +} diff --git a/apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-context.tsx b/apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-context.tsx new file mode 100644 index 000000000..3c2c06c63 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-context.tsx @@ -0,0 +1,28 @@ +import { createContext } from "react" + +export type SidebarViewType = "drawer" | "static" + +export interface SidebarState { + drawer: boolean + static: boolean +} + +export interface EditorSidebarContextType { + left: SidebarState + right: SidebarState + toggleLeft: (viewType: SidebarViewType) => void + toggleRight: (viewType: SidebarViewType) => void +} + +export const EditorSidebarContext = createContext({ + left: { + drawer: false, + static: true + }, + right: { + drawer: false, + static: false + }, + toggleLeft: () => {}, + toggleRight: () => {}, +}) diff --git a/apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-provider.tsx b/apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-provider.tsx new file mode 100644 index 000000000..fbca84f21 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/providers/editor-sidebar-provider.tsx @@ -0,0 +1,46 @@ +import { PropsWithChildren, useState } from "react" +import { EditorSidebarContext, SidebarState, SidebarViewType } from "./editor-sidebar-context" + +/** + * Provider for the editor sidebar state + * Manages the visibility state of left and right sidebars + * with separate states for drawer and static views + */ +export const EditorSidebarProvider = ({ children }: PropsWithChildren) => { + const [leftSidebar, setLeftSidebar] = useState({ + drawer: false, + static: true + }) + + const [rightSidebar, setRightSidebar] = useState({ + drawer: false, + static: false + }) + + const toggleLeft = (viewType: SidebarViewType) => { + setLeftSidebar((prev) => ({ + ...prev, + [viewType]: !prev[viewType], + })) + } + + const toggleRight = (viewType: SidebarViewType) => { + setRightSidebar((prev) => ({ + ...prev, + [viewType]: !prev[viewType], + })) + } + + return ( + + {children} + + ) +} diff --git a/apps/medusa/src/admin/routes/content/editor/test/page.tsx b/apps/medusa/src/admin/routes/content/editor/test/page.tsx new file mode 100644 index 000000000..dcaced1b4 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/editor/test/page.tsx @@ -0,0 +1,54 @@ +import { LoaderFunctionArgs, useLoaderData, useParams } from "react-router-dom" +import { EditorTopbar } from "../components/editor-top-bar" +import { EditorModal } from "../components/editor-modal" +import { EditorSidebarProvider } from "../providers/editor-sidebar-provider" +import { PostEditorLayout } from "../components/post-editor-layout" +import { TooltipProvider } from "@medusajs/ui" + + +export async function loader({ params }: LoaderFunctionArgs) { + console.log("🚀 ~ loader ~ content/editor/:id ~ params:", params) + + return { + post: { + id: params.id, + title: "Test Page", + description: "Test Page Description", + content: "Test Page Content", + type: "page", + }, + } +} + +const PostDetailsPage = () => { + const { id } = useParams() + console.log("🚀 ~ PostDetailsPage ~ id:", id) + // const postData = useLoaderData() as Awaited> + // console.log("🚀 ~ PostDetailsPage ~ post:", postData) + const pageName = "Test Page" + + return ( + + + + + + {/* EditorModal.Title is required by EditorModal.Content */} + + + + + + {/*

{postData.post?.title}

+

{postData.post?.description}

*/} +

{pageName}

+
+
+
+
+
+
+ ) +} + +export default PostDetailsPage diff --git a/apps/medusa/src/admin/routes/content/page.tsx b/apps/medusa/src/admin/routes/content/page.tsx new file mode 100644 index 000000000..fb545dd28 --- /dev/null +++ b/apps/medusa/src/admin/routes/content/page.tsx @@ -0,0 +1,49 @@ +import { Button, Container, TooltipProvider } from "@medusajs/ui" +import { defineRouteConfig } from "@medusajs/admin-sdk" +import { DocumentText } from "@medusajs/icons" +import { useNavigate } from "react-router-dom" +import { SingleColumnLayout } from "../../layouts/single-column" +import { Header } from "../../components/header" +import { PostsDataTable } from "./components/posts-data-table" +import { useAdminCreatePost } from "../../hooks/posts-mutations" + +const ContentPage = () => { + const navigate = useNavigate() + + const { mutateAsync: createPost, isPending } = useAdminCreatePost() + + const handleCreatePost = async () => { + await createPost({ + title: 'New Page', + content: {}, + type: 'page' + }) + + navigate(`editor/test`) // TODO: change to the correct path + // navigate(`/editor/${type}/new`) + } + + return ( + + +
Create + } + ]} + /> + + + + ) +} + +export const config = defineRouteConfig({ + label: "Content", + icon: DocumentText, +}) + +export default ContentPage \ No newline at end of file diff --git a/apps/medusa/src/admin/sdk.ts b/apps/medusa/src/admin/sdk.ts new file mode 100644 index 000000000..78a22804d --- /dev/null +++ b/apps/medusa/src/admin/sdk.ts @@ -0,0 +1,12 @@ +import { PageBuilderSDK } from '@lambdacurry/page-builder-sdk'; + +declare const __BACKEND_URL__: string | undefined; + +export const backendUrl = __BACKEND_URL__ ?? 'http://localhost:9000'; + +export const sdk = new PageBuilderSDK({ + baseUrl: backendUrl, + auth: { + type: 'session', + }, +}); diff --git a/apps/medusa/src/admin/tsconfig.json b/apps/medusa/src/admin/tsconfig.json index 76cc58ae3..ea4bf122b 100644 --- a/apps/medusa/src/admin/tsconfig.json +++ b/apps/medusa/src/admin/tsconfig.json @@ -1,8 +1,24 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { - "module": "esnext" + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true }, - "include": ["."], - "exclude": ["**/*.spec.js"] -} + "include": ["."] +} \ No newline at end of file diff --git a/apps/medusa/src/admin/vite-env.d.ts b/apps/medusa/src/admin/vite-env.d.ts new file mode 100644 index 000000000..151aa6856 --- /dev/null +++ b/apps/medusa/src/admin/vite-env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/apps/medusa/src/api/admin/content/posts/[id]/duplicate/route.ts b/apps/medusa/src/api/admin/content/posts/[id]/duplicate/route.ts new file mode 100644 index 000000000..bac143df1 --- /dev/null +++ b/apps/medusa/src/api/admin/content/posts/[id]/duplicate/route.ts @@ -0,0 +1,20 @@ +import type { + AuthenticatedMedusaRequest, + MedusaResponse, +} from '@medusajs/framework/http' +import { duplicatePostWorkflow } from '../../../../../../workflows/duplicate-post' + +export const POST = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse, +) => { + const id = req.params.id + + const { result } = await duplicatePostWorkflow(req.scope).run({ + input: { + id, + }, + }) + + res.status(200).json({ post: result }) +} diff --git a/apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts b/apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts new file mode 100644 index 000000000..0a1b7355b --- /dev/null +++ b/apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts @@ -0,0 +1,18 @@ +import { + type MiddlewareRoute, + validateAndTransformBody, +} from '@medusajs/framework' +import { updatePostSchema } from '../../validations' + +export const adminPostItemRoutesMiddlewares: MiddlewareRoute[] = [ + { + matcher: '/admin/content/posts/:id', + method: 'PUT', + middlewares: [validateAndTransformBody(updatePostSchema)], + }, + { + matcher: '/admin/content/posts/:id', + method: 'DELETE', + middlewares: [], + }, +] diff --git a/apps/medusa/src/api/admin/content/posts/[id]/route.tsx b/apps/medusa/src/api/admin/content/posts/[id]/route.tsx new file mode 100644 index 000000000..1cfee6c4a --- /dev/null +++ b/apps/medusa/src/api/admin/content/posts/[id]/route.tsx @@ -0,0 +1,29 @@ +import type { AuthenticatedMedusaRequest, MedusaResponse } from '@medusajs/framework/http'; +import { updatePostWorkflow } from '../../../../../workflows/update-post'; +import { deletePostWorkflow } from '../../../../../workflows/delete-post'; +import type { AdminPageBuilderUpdatePostBody } from '@lambdacurry/page-builder-types'; + +export const PUT = async (req: AuthenticatedMedusaRequest, res: MedusaResponse) => { + const id = req.params.id; + const data = { ...req.validatedBody, id }; + + const { result } = await updatePostWorkflow(req.scope).run({ + input: { + post: data, + }, + }); + + res.status(200).json({ post: result }); +}; + +export const DELETE = async (req: AuthenticatedMedusaRequest, res: MedusaResponse) => { + const id = req.params.id; + + const { result } = await deletePostWorkflow(req.scope).run({ + input: { + id, + }, + }); + + res.status(200).json({ id: result.id, object: 'post', deleted: true }); +}; diff --git a/apps/medusa/src/api/admin/content/posts/middlewares.ts b/apps/medusa/src/api/admin/content/posts/middlewares.ts new file mode 100644 index 000000000..1671360d0 --- /dev/null +++ b/apps/medusa/src/api/admin/content/posts/middlewares.ts @@ -0,0 +1,52 @@ +import { + type MiddlewareRoute, + validateAndTransformQuery, + validateAndTransformBody, +} from '@medusajs/framework' +import { createPostSchema, listAdminPostsQuerySchema } from '../validations' + +export const defaultAdminPostFields = [ + 'id', + 'type', + 'title', + 'handle', + 'excerpt', + 'content', + 'status', + 'content_mode', + 'seo', + 'published_at', + 'archived_at', + 'is_home_page', + 'created_at', + 'updated_at', + 'featured_image.*', + 'authors.*', + 'root.*', + 'sections.*', + 'tags.*', +] + +export const defaultPostsQueryConfig = { + defaults: [...defaultAdminPostFields], + defaultLimit: 50, + isList: true, +} + +export const adminPostRoutesMiddlewares: MiddlewareRoute[] = [ + { + matcher: '/admin/content/posts', + method: 'GET', + middlewares: [ + validateAndTransformQuery( + listAdminPostsQuerySchema, + defaultPostsQueryConfig, + ), + ], + }, + { + matcher: '/admin/content/posts', + method: 'POST', + middlewares: [validateAndTransformBody(createPostSchema)], + }, +] diff --git a/apps/medusa/src/api/admin/content/posts/route.ts b/apps/medusa/src/api/admin/content/posts/route.ts new file mode 100644 index 000000000..e0db28b2a --- /dev/null +++ b/apps/medusa/src/api/admin/content/posts/route.ts @@ -0,0 +1,31 @@ +import type { AuthenticatedMedusaRequest, MedusaResponse } from '@medusajs/framework/http'; +import { createPostWorkflow } from '../../../../workflows/create-post'; +import type { AdminPageBuilderCreatePostBody } from '@lambdacurry/page-builder-types'; + +export const GET = async (req: AuthenticatedMedusaRequest, res: MedusaResponse) => { + const query = req.scope.resolve('query'); + + const { data: posts, metadata = { count: 0, skip: 0, take: 0 } } = await query.graph({ + entity: 'post', + fields: req.queryConfig?.fields || ['*'], + filters: req.filterableFields || {}, + pagination: req.queryConfig?.pagination || { skip: 0, take: 10 }, + }); + + res.status(200).json({ + posts: posts, + count: metadata.count, + offset: metadata.skip, + limit: metadata.take, + }); +}; + +export const POST = async (req: AuthenticatedMedusaRequest, res: MedusaResponse) => { + const { result } = await createPostWorkflow(req.scope).run({ + input: { + post: req.validatedBody, + }, + }); + + res.status(200).json({ post: result }); +}; diff --git a/apps/medusa/src/api/admin/content/validations.ts b/apps/medusa/src/api/admin/content/validations.ts new file mode 100644 index 000000000..73686f2a6 --- /dev/null +++ b/apps/medusa/src/api/admin/content/validations.ts @@ -0,0 +1,71 @@ +import { z } from 'zod' +import { + createFindParams, + createOperatorMap, +} from '@medusajs/medusa/api/utils/validators' + +import { + postStatusValues, + postTypeValues, + postContentModeValues, +} from '../../../modules/page-builder/enum-values' + +export const postStatusesEnum = z.enum([...postStatusValues]) +export const postTypesEnum = z.enum([...postTypeValues]) +export const postContentModesEnum = z.enum([...postContentModeValues]) + +export const createPostSchema = z.object({ + title: z.string(), + handle: z.string().optional(), + excerpt: z.string().optional(), + content: z.record(z.string(), z.any()).optional(), + status: postStatusesEnum.optional(), + type: postTypesEnum.optional(), + content_mode: postContentModesEnum.optional(), + seo: z.record(z.string(), z.any()).optional(), + is_home_page: z.boolean().optional(), +}) as any + +export const updatePostSchema = z.object({ + id: z.string(), + title: z.string().optional(), + handle: z.string().optional(), + excerpt: z.string().optional(), + content: z.record(z.string(), z.any()).optional(), + status: postStatusesEnum.optional(), + type: postTypesEnum.optional(), + content_mode: postContentModesEnum.optional(), + seo: z.record(z.string(), z.any()).optional(), + is_home_page: z.boolean().optional(), +}) as any + +export const deletePostSchema = z.object({ + id: z.string(), +}) + +export const listAdminPostsQuerySchema = createFindParams({ + offset: 0, + limit: 50, +}).merge( + // @ts-ignore + z.object({ + q: z.string().optional(), + id: z.union([z.string(), z.array(z.string())]).optional(), + title: z.string().optional(), + handle: z.string().optional(), + status: z.union([postStatusesEnum, z.array(postStatusesEnum)]).optional(), + type: z.union([postTypesEnum, z.array(postTypesEnum)]).optional(), + content_mode: z + .union([postContentModesEnum, z.array(postContentModesEnum)]) + .optional(), + is_home_page: z.boolean().optional(), + // @ts-ignore + published_at: createOperatorMap().optional(), + // @ts-ignore + archived_at: createOperatorMap().optional(), + // @ts-ignore + created_at: createOperatorMap().optional(), + // @ts-ignore + updated_at: createOperatorMap().optional(), + }), +) diff --git a/apps/medusa/src/api/middlewares.ts b/apps/medusa/src/api/middlewares.ts new file mode 100644 index 000000000..8d7f46b15 --- /dev/null +++ b/apps/medusa/src/api/middlewares.ts @@ -0,0 +1,8 @@ +import { defineMiddlewares } from '@medusajs/framework' +import { adminPostRoutesMiddlewares } from './admin/content/posts/middlewares' +import { adminPostItemRoutesMiddlewares } from './admin/content/posts/[id]/middlewares' + +export default defineMiddlewares([ + ...adminPostRoutesMiddlewares, + ...adminPostItemRoutesMiddlewares, +]) diff --git a/apps/medusa/src/links/post-author-user.ts b/apps/medusa/src/links/post-author-user.ts new file mode 100644 index 000000000..87cbaf279 --- /dev/null +++ b/apps/medusa/src/links/post-author-user.ts @@ -0,0 +1,14 @@ +import { defineLink } from '@medusajs/framework/utils' +import UserModule from '@medusajs/medusa/user' +import PageBuilderModule from '../modules/page-builder' + +export default defineLink( + { + ...PageBuilderModule.linkable.postAuthor.id, + field: 'medusa_user_id', + }, + UserModule.linkable.user, + { + readOnly: true, + }, +) diff --git a/apps/medusa/src/links/post-tag-user.ts b/apps/medusa/src/links/post-tag-user.ts new file mode 100644 index 000000000..86a515b33 --- /dev/null +++ b/apps/medusa/src/links/post-tag-user.ts @@ -0,0 +1,14 @@ +import { defineLink } from '@medusajs/framework/utils' +import UserModule from '@medusajs/medusa/user' +import PageBuilderModule from '../modules/page-builder' + +export default defineLink( + { + ...PageBuilderModule.linkable.postTag.id, + field: 'created_by_id', + }, + UserModule.linkable.user, + { + readOnly: true, + }, +) diff --git a/apps/medusa/src/modules/page-builder/enum-values.ts b/apps/medusa/src/modules/page-builder/enum-values.ts new file mode 100644 index 000000000..23e58f55e --- /dev/null +++ b/apps/medusa/src/modules/page-builder/enum-values.ts @@ -0,0 +1,3 @@ +export const postTypeValues = ['page', 'post'] as const +export const postStatusValues = ['draft', 'published', 'archived'] as const +export const postContentModeValues = ['basic', 'advanced'] as const diff --git a/apps/medusa/src/modules/page-builder/index.ts b/apps/medusa/src/modules/page-builder/index.ts new file mode 100644 index 000000000..42f96ad0f --- /dev/null +++ b/apps/medusa/src/modules/page-builder/index.ts @@ -0,0 +1,15 @@ +import { Module } from '@medusajs/framework/utils' + +import PageBuilderService from './service' + +export const PAGE_BUILDER_MODULE = 'page-builder' + +export const pageBuilderModuleEvents = Object.freeze({ + POST_CREATED: 'post.created', + POST_UPDATED: 'post.updated', + POST_DELETED: 'post.deleted', +}) + +export default Module(PAGE_BUILDER_MODULE, { + service: PageBuilderService, +}) diff --git a/apps/medusa/src/modules/page-builder/migrations/.snapshot-medusa-page-builder.json b/apps/medusa/src/modules/page-builder/migrations/.snapshot-medusa-page-builder.json new file mode 100644 index 000000000..66eeab377 --- /dev/null +++ b/apps/medusa/src/modules/page-builder/migrations/.snapshot-medusa-page-builder.json @@ -0,0 +1,1489 @@ +{ + "namespaces": [ + "public" + ], + "name": "public", + "tables": [ + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "label": { + "name": "label", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "location": { + "name": "location", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "enumItems": [ + "header", + "footer" + ], + "mappedType": "enum" + }, + "url": { + "name": "url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "new_tab": { + "name": "new_tab", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "false", + "mappedType": "boolean" + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "0", + "mappedType": "integer" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "navigation_item", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_navigation_item_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_navigation_item_deleted_at\" ON \"navigation_item\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "navigation_item_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": {}, + "nativeEnums": {} + }, + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "type": { + "name": "type", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "enumItems": [ + "page", + "post" + ], + "mappedType": "enum" + }, + "title": { + "name": "title", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "handle": { + "name": "handle", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "excerpt": { + "name": "excerpt", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "content": { + "name": "content", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "'draft'", + "enumItems": [ + "draft", + "published", + "archived" + ], + "mappedType": "enum" + }, + "content_mode": { + "name": "content_mode", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "'advanced'", + "enumItems": [ + "basic", + "advanced" + ], + "mappedType": "enum" + }, + "seo": { + "name": "seo", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "published_at": { + "name": "published_at", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "archived_at": { + "name": "archived_at", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "is_home_page": { + "name": "is_home_page", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "false", + "mappedType": "boolean" + }, + "root_id": { + "name": "root_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "post", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_post_handle_unique", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_post_handle_unique\" ON \"post\" (handle) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_post_root_id", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_root_id\" ON \"post\" (root_id) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_post_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_deleted_at\" ON \"post\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "post_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": { + "post_root_id_foreign": { + "constraintName": "post_root_id_foreign", + "columnNames": [ + "root_id" + ], + "localTableName": "public.post", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post", + "deleteRule": "set null", + "updateRule": "cascade" + } + }, + "nativeEnums": {} + }, + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "medusa_user_id": { + "name": "medusa_user_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "post_author", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_post_author_medusa_user_id_unique", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_post_author_medusa_user_id_unique\" ON \"post_author\" (medusa_user_id) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_post_author_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_author_deleted_at\" ON \"post_author\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "post_author_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": {}, + "nativeEnums": {} + }, + { + "columns": { + "post_id": { + "name": "post_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "post_author_id": { + "name": "post_author_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + } + }, + "name": "post_post_authors", + "schema": "public", + "indexes": [ + { + "keyName": "post_post_authors_pkey", + "columnNames": [ + "post_id", + "post_author_id" + ], + "composite": true, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": { + "post_post_authors_post_id_foreign": { + "constraintName": "post_post_authors_post_id_foreign", + "columnNames": [ + "post_id" + ], + "localTableName": "public.post_post_authors", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post", + "deleteRule": "cascade", + "updateRule": "cascade" + }, + "post_post_authors_post_author_id_foreign": { + "constraintName": "post_post_authors_post_author_id_foreign", + "columnNames": [ + "post_author_id" + ], + "localTableName": "public.post_post_authors", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post_author", + "deleteRule": "cascade", + "updateRule": "cascade" + } + }, + "nativeEnums": {} + }, + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "label": { + "name": "label", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "handle": { + "name": "handle", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "description": { + "name": "description", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "created_by_id": { + "name": "created_by_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "post_tag", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_post_tag_handle_unique", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_post_tag_handle_unique\" ON \"post_tag\" (handle) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_post_tag_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_tag_deleted_at\" ON \"post_tag\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "post_tag_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": {}, + "nativeEnums": {} + }, + { + "columns": { + "post_id": { + "name": "post_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "post_tag_id": { + "name": "post_tag_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + } + }, + "name": "post_post_tags", + "schema": "public", + "indexes": [ + { + "keyName": "post_post_tags_pkey", + "columnNames": [ + "post_id", + "post_tag_id" + ], + "composite": true, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": { + "post_post_tags_post_id_foreign": { + "constraintName": "post_post_tags_post_id_foreign", + "columnNames": [ + "post_id" + ], + "localTableName": "public.post_post_tags", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post", + "deleteRule": "cascade", + "updateRule": "cascade" + }, + "post_post_tags_post_tag_id_foreign": { + "constraintName": "post_post_tags_post_tag_id_foreign", + "columnNames": [ + "post_tag_id" + ], + "localTableName": "public.post_post_tags", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post_tag", + "deleteRule": "cascade", + "updateRule": "cascade" + } + }, + "nativeEnums": {} + }, + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "title": { + "name": "title", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "'draft'", + "enumItems": [ + "draft", + "published", + "archived" + ], + "mappedType": "enum" + }, + "type": { + "name": "type", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "enumItems": [ + "page", + "post" + ], + "mappedType": "enum" + }, + "description": { + "name": "description", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "0", + "mappedType": "integer" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "post_template", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_post_template_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_template_deleted_at\" ON \"post_template\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "post_template_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": {}, + "nativeEnums": {} + }, + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "type": { + "name": "type", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "enumItems": [ + "button_list", + "cta", + "header", + "hero", + "product_carousel", + "product_grid", + "image_gallery", + "raw_html", + "rich_text", + "blog_list" + ], + "mappedType": "enum" + }, + "status": { + "name": "status", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "'draft'", + "enumItems": [ + "draft", + "published", + "archived" + ], + "mappedType": "enum" + }, + "name": { + "name": "name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "content": { + "name": "content", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "json" + }, + "settings": { + "name": "settings", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "json" + }, + "styles": { + "name": "styles", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "is_reusable": { + "name": "is_reusable", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "false", + "mappedType": "boolean" + }, + "usage_count": { + "name": "usage_count", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "1", + "mappedType": "integer" + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "integer" + }, + "post_id": { + "name": "post_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "post_template_id": { + "name": "post_template_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "post_section", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_post_section_post_id", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_section_post_id\" ON \"post_section\" (post_id) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_post_section_post_template_id", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_section_post_template_id\" ON \"post_section\" (post_template_id) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_post_section_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_section_deleted_at\" ON \"post_section\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "post_section_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": { + "post_section_post_id_foreign": { + "constraintName": "post_section_post_id_foreign", + "columnNames": [ + "post_id" + ], + "localTableName": "public.post_section", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post", + "deleteRule": "set null", + "updateRule": "cascade" + }, + "post_section_post_template_id_foreign": { + "constraintName": "post_section_post_template_id_foreign", + "columnNames": [ + "post_template_id" + ], + "localTableName": "public.post_section", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post_template", + "deleteRule": "set null", + "updateRule": "cascade" + } + }, + "nativeEnums": {} + }, + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "description": { + "name": "description", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "header_code": { + "name": "header_code", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "footer_code": { + "name": "footer_code", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "storefront_url": { + "name": "storefront_url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "primary_theme_colors": { + "name": "primary_theme_colors", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "accent_theme_colors": { + "name": "accent_theme_colors", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "highlight_theme_colors": { + "name": "highlight_theme_colors", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "display_font": { + "name": "display_font", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "body_font": { + "name": "body_font", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "include_site_name_beside_logo": { + "name": "include_site_name_beside_logo", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "boolean" + }, + "social_instagram": { + "name": "social_instagram", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "social_youtube": { + "name": "social_youtube", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "social_facebook": { + "name": "social_facebook", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "social_twitter": { + "name": "social_twitter", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "social_linkedin": { + "name": "social_linkedin", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "social_pinterest": { + "name": "social_pinterest", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "social_tiktok": { + "name": "social_tiktok", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "social_snapchat": { + "name": "social_snapchat", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "global_css": { + "name": "global_css", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "ga_property_id": { + "name": "ga_property_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "shipping_sort": { + "name": "shipping_sort", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "site_settings", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_site_settings_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_site_settings_deleted_at\" ON \"site_settings\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "site_settings_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": {}, + "nativeEnums": {} + }, + { + "columns": { + "id": { + "name": "id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "url": { + "name": "url", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "json" + }, + "post_id": { + "name": "post_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "site_settings_id": { + "name": "site_settings_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "created_at": { + "name": "created_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "length": 6, + "default": "now()", + "mappedType": "datetime" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamptz", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "length": 6, + "mappedType": "datetime" + } + }, + "name": "image", + "schema": "public", + "indexes": [ + { + "keyName": "IDX_image_post_id_unique", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_image_post_id_unique\" ON \"image\" (post_id) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_image_site_settings_id_unique", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_image_site_settings_id_unique\" ON \"image\" (site_settings_id) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_image_deleted_at", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_image_deleted_at\" ON \"image\" (deleted_at) WHERE deleted_at IS NULL" + }, + { + "keyName": "IDX_product_image_url", + "columnNames": [], + "composite": false, + "constraint": false, + "primary": false, + "unique": false, + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_product_image_url\" ON \"image\" (url) WHERE deleted_at IS NULL" + }, + { + "keyName": "image_pkey", + "columnNames": [ + "id" + ], + "composite": false, + "constraint": true, + "primary": true, + "unique": true + } + ], + "checks": [], + "foreignKeys": { + "image_post_id_foreign": { + "constraintName": "image_post_id_foreign", + "columnNames": [ + "post_id" + ], + "localTableName": "public.image", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.post", + "deleteRule": "set null", + "updateRule": "cascade" + }, + "image_site_settings_id_foreign": { + "constraintName": "image_site_settings_id_foreign", + "columnNames": [ + "site_settings_id" + ], + "localTableName": "public.image", + "referencedColumnNames": [ + "id" + ], + "referencedTableName": "public.site_settings", + "deleteRule": "set null", + "updateRule": "cascade" + } + }, + "nativeEnums": {} + } + ], + "nativeEnums": {} +} diff --git a/apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts b/apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts new file mode 100644 index 000000000..914a57ed3 --- /dev/null +++ b/apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts @@ -0,0 +1,103 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20250305164601 extends Migration { + + override async up(): Promise { + this.addSql(`alter table if exists "image" drop constraint if exists "image_site_settings_id_unique";`); + this.addSql(`alter table if exists "image" drop constraint if exists "image_post_id_unique";`); + this.addSql(`alter table if exists "post_tag" drop constraint if exists "post_tag_handle_unique";`); + this.addSql(`alter table if exists "post_author" drop constraint if exists "post_author_medusa_user_id_unique";`); + this.addSql(`alter table if exists "post" drop constraint if exists "post_handle_unique";`); + this.addSql(`create table if not exists "navigation_item" ("id" text not null, "label" text not null, "location" text check ("location" in ('header', 'footer')) not null, "url" text not null, "new_tab" boolean not null default false, "sort_order" integer not null default 0, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "navigation_item_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_navigation_item_deleted_at" ON "navigation_item" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "post" ("id" text not null, "type" text check ("type" in ('page', 'post')) not null, "title" text not null, "handle" text not null, "excerpt" text null, "content" jsonb null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "content_mode" text check ("content_mode" in ('basic', 'advanced')) not null, "seo" jsonb null, "published_at" text null, "archived_at" text null, "is_home_page" boolean not null default false, "root_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_post_handle_unique" ON "post" (handle) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_root_id" ON "post" (root_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_deleted_at" ON "post" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "post_author" ("id" text not null, "name" text not null, "medusa_user_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_author_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_post_author_medusa_user_id_unique" ON "post_author" (medusa_user_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_author_deleted_at" ON "post_author" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "post_post_authors" ("post_id" text not null, "post_author_id" text not null, constraint "post_post_authors_pkey" primary key ("post_id", "post_author_id"));`); + + this.addSql(`create table if not exists "post_tag" ("id" text not null, "label" text not null, "handle" text not null, "description" text not null, "created_by_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_tag_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_post_tag_handle_unique" ON "post_tag" (handle) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_tag_deleted_at" ON "post_tag" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "post_post_tags" ("post_id" text not null, "post_tag_id" text not null, constraint "post_post_tags_pkey" primary key ("post_id", "post_tag_id"));`); + + this.addSql(`create table if not exists "post_template" ("id" text not null, "title" text not null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "type" text check ("type" in ('page', 'post')) not null, "description" text null, "sort_order" integer not null default 0, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_template_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_template_deleted_at" ON "post_template" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "post_section" ("id" text not null, "type" text check ("type" in ('button_list', 'cta', 'header', 'hero', 'product_carousel', 'product_grid', 'image_gallery', 'raw_html', 'rich_text', 'blog_list')) not null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "name" text not null, "content" jsonb not null, "settings" jsonb not null, "styles" jsonb null, "is_reusable" boolean not null default false, "usage_count" integer not null default 1, "sort_order" integer not null, "post_id" text null, "post_template_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_section_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_section_post_id" ON "post_section" (post_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_section_post_template_id" ON "post_section" (post_template_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_section_deleted_at" ON "post_section" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "site_settings" ("id" text not null, "description" text null, "header_code" text null, "footer_code" text null, "storefront_url" text null, "primary_theme_colors" jsonb null, "accent_theme_colors" jsonb null, "highlight_theme_colors" jsonb null, "display_font" jsonb null, "body_font" jsonb null, "include_site_name_beside_logo" boolean not null, "social_instagram" text null, "social_youtube" text null, "social_facebook" text null, "social_twitter" text null, "social_linkedin" text null, "social_pinterest" text null, "social_tiktok" text null, "social_snapchat" text null, "global_css" text null, "ga_property_id" text null, "shipping_sort" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "site_settings_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_site_settings_deleted_at" ON "site_settings" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "image" ("id" text not null, "url" text not null, "metadata" jsonb null, "post_id" text null, "site_settings_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "image_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_image_post_id_unique" ON "image" (post_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_image_site_settings_id_unique" ON "image" (site_settings_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_image_deleted_at" ON "image" (deleted_at) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_product_image_url" ON "image" (url) WHERE deleted_at IS NULL;`); + + this.addSql(`alter table if exists "post" add constraint "post_root_id_foreign" foreign key ("root_id") references "post" ("id") on update cascade on delete set null;`); + + this.addSql(`alter table if exists "post_post_authors" add constraint "post_post_authors_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete cascade;`); + this.addSql(`alter table if exists "post_post_authors" add constraint "post_post_authors_post_author_id_foreign" foreign key ("post_author_id") references "post_author" ("id") on update cascade on delete cascade;`); + + this.addSql(`alter table if exists "post_post_tags" add constraint "post_post_tags_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete cascade;`); + this.addSql(`alter table if exists "post_post_tags" add constraint "post_post_tags_post_tag_id_foreign" foreign key ("post_tag_id") references "post_tag" ("id") on update cascade on delete cascade;`); + + this.addSql(`alter table if exists "post_section" add constraint "post_section_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete set null;`); + this.addSql(`alter table if exists "post_section" add constraint "post_section_post_template_id_foreign" foreign key ("post_template_id") references "post_template" ("id") on update cascade on delete set null;`); + + this.addSql(`alter table if exists "image" add constraint "image_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete set null;`); + this.addSql(`alter table if exists "image" add constraint "image_site_settings_id_foreign" foreign key ("site_settings_id") references "site_settings" ("id") on update cascade on delete set null;`); + } + + override async down(): Promise { + this.addSql(`alter table if exists "post" drop constraint if exists "post_root_id_foreign";`); + + this.addSql(`alter table if exists "post_post_authors" drop constraint if exists "post_post_authors_post_id_foreign";`); + + this.addSql(`alter table if exists "post_post_tags" drop constraint if exists "post_post_tags_post_id_foreign";`); + + this.addSql(`alter table if exists "post_section" drop constraint if exists "post_section_post_id_foreign";`); + + this.addSql(`alter table if exists "image" drop constraint if exists "image_post_id_foreign";`); + + this.addSql(`alter table if exists "post_post_authors" drop constraint if exists "post_post_authors_post_author_id_foreign";`); + + this.addSql(`alter table if exists "post_post_tags" drop constraint if exists "post_post_tags_post_tag_id_foreign";`); + + this.addSql(`alter table if exists "post_section" drop constraint if exists "post_section_post_template_id_foreign";`); + + this.addSql(`alter table if exists "image" drop constraint if exists "image_site_settings_id_foreign";`); + + this.addSql(`drop table if exists "navigation_item" cascade;`); + + this.addSql(`drop table if exists "post" cascade;`); + + this.addSql(`drop table if exists "post_author" cascade;`); + + this.addSql(`drop table if exists "post_post_authors" cascade;`); + + this.addSql(`drop table if exists "post_tag" cascade;`); + + this.addSql(`drop table if exists "post_post_tags" cascade;`); + + this.addSql(`drop table if exists "post_template" cascade;`); + + this.addSql(`drop table if exists "post_section" cascade;`); + + this.addSql(`drop table if exists "site_settings" cascade;`); + + this.addSql(`drop table if exists "image" cascade;`); + } + +} diff --git a/apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts b/apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts new file mode 100644 index 000000000..4016e27fb --- /dev/null +++ b/apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts @@ -0,0 +1,15 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20250313155933 extends Migration { + + override async up(): Promise { + this.addSql(`alter table if exists "post" alter column "handle" type text using ("handle"::text);`); + this.addSql(`alter table if exists "post" alter column "handle" drop not null;`); + } + + override async down(): Promise { + this.addSql(`alter table if exists "post" alter column "handle" type text using ("handle"::text);`); + this.addSql(`alter table if exists "post" alter column "handle" set not null;`); + } + +} diff --git a/apps/medusa/src/modules/page-builder/models/image.ts b/apps/medusa/src/modules/page-builder/models/image.ts new file mode 100644 index 000000000..ab58e80a6 --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/image.ts @@ -0,0 +1,30 @@ +import { model } from '@medusajs/framework/utils' +import { PostModel } from './post' +import { SiteSettingsModel } from './site-settings' + +export const ImageModel = model + .define('image', { + id: model.id({ prefix: 'img' }).primaryKey(), + url: model.text(), + metadata: model.json().nullable(), + + // relations fields + post: model + .belongsTo(() => PostModel, { + mappedBy: 'featured_image', + }) + .nullable(), + site_settings: model + .belongsTo(() => SiteSettingsModel, { + mappedBy: 'favicon', + }) + .nullable(), + }) + .indexes([ + { + name: 'IDX_product_image_url', + on: ['url'], + unique: false, + where: 'deleted_at IS NULL', + }, + ]) diff --git a/apps/medusa/src/modules/page-builder/models/index.ts b/apps/medusa/src/modules/page-builder/models/index.ts new file mode 100644 index 000000000..e70097799 --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/index.ts @@ -0,0 +1,8 @@ +export * from './post-author' +export * from './post' +export * from './post-section' +export * from './post-tag' +export * from './post-template' +export * from './image' +export * from './site-settings' +export * from './navigation-item' diff --git a/apps/medusa/src/modules/page-builder/models/navigation-item.ts b/apps/medusa/src/modules/page-builder/models/navigation-item.ts new file mode 100644 index 000000000..db55b3ab9 --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/navigation-item.ts @@ -0,0 +1,10 @@ +import { model } from '@medusajs/framework/utils' + +export const NavigationItemModel = model.define('navigation_item', { + id: model.id({ prefix: 'nav_item' }).primaryKey(), + label: model.text(), + location: model.enum(['header', 'footer']), + url: model.text(), + new_tab: model.boolean().default(false), + sort_order: model.number().default(0), +}) diff --git a/apps/medusa/src/modules/page-builder/models/post-author.ts b/apps/medusa/src/modules/page-builder/models/post-author.ts new file mode 100644 index 000000000..f9897b73b --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/post-author.ts @@ -0,0 +1,13 @@ +import { model } from '@medusajs/framework/utils' +import { PostModel } from './post' + +export const PostAuthorModel = model.define('post_author', { + id: model.id({ prefix: 'post_author' }).primaryKey(), + name: model.text(), + + // relations fields + medusa_user_id: model.text().unique(), + posts: model.manyToMany(() => PostModel, { + mappedBy: 'authors', + }), +}) diff --git a/apps/medusa/src/modules/page-builder/models/post-section.ts b/apps/medusa/src/modules/page-builder/models/post-section.ts new file mode 100644 index 000000000..1a9823f3b --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/post-section.ts @@ -0,0 +1,39 @@ +import { model } from '@medusajs/framework/utils' +import { PostModel } from './post' +import { PostTemplateModel } from './post-template' + +export const PostSectionModel = model.define('post_section', { + id: model.id({ prefix: 'postsec' }).primaryKey(), + type: model.enum([ + 'button_list', + 'cta', + 'header', + 'hero', + 'product_carousel', + 'product_grid', + 'image_gallery', + 'raw_html', + 'rich_text', + 'blog_list', + ]), + status: model.enum(['draft', 'published', 'archived']).default('draft'), + name: model.text(), + content: model.json(), + settings: model.json(), + styles: model.json().nullable(), + is_reusable: model.boolean().default(false), + usage_count: model.number().default(1), + sort_order: model.number(), + + // relations fields + post: model + .belongsTo(() => PostModel, { + mappedBy: 'sections', + }) + .nullable(), + post_template: model + .belongsTo(() => PostTemplateModel, { + mappedBy: 'sections', + }) + .nullable(), +}) diff --git a/apps/medusa/src/modules/page-builder/models/post-tag.ts b/apps/medusa/src/modules/page-builder/models/post-tag.ts new file mode 100644 index 000000000..17e5e6c3a --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/post-tag.ts @@ -0,0 +1,15 @@ +import { model } from '@medusajs/framework/utils' +import { PostModel } from './post' + +export const PostTagModel = model.define('post_tag', { + id: model.id({ prefix: 'post_tag' }).primaryKey(), + label: model.text(), + handle: model.text().unique(), + description: model.text(), + + // relations fields + created_by_id: model.text(), + posts: model.manyToMany(() => PostModel, { + mappedBy: 'tags', + }), +}) diff --git a/apps/medusa/src/modules/page-builder/models/post-template.ts b/apps/medusa/src/modules/page-builder/models/post-template.ts new file mode 100644 index 000000000..bc312b53f --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/post-template.ts @@ -0,0 +1,14 @@ +import { model } from '@medusajs/framework/utils' +import { PostSectionModel } from './post-section' + +export const PostTemplateModel = model.define('post_template', { + id: model.id({ prefix: 'post_temp' }).primaryKey(), + title: model.text(), + status: model.enum(['draft', 'published', 'archived']).default('draft'), + type: model.enum(['page', 'post']), + description: model.text().nullable(), + sort_order: model.number().default(0), + + // relations fields + sections: model.hasMany(() => PostSectionModel), +}) diff --git a/apps/medusa/src/modules/page-builder/models/post.ts b/apps/medusa/src/modules/page-builder/models/post.ts new file mode 100644 index 000000000..d16f51690 --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/post.ts @@ -0,0 +1,41 @@ +import { model } from '@medusajs/framework/utils' +import { PostSectionModel } from './post-section' +import { PostTagModel } from './post-tag' +import { PostAuthorModel } from './post-author' +import { ImageModel } from './image' +import { + postContentModeValues, + postStatusValues, + postTypeValues, +} from '../enum-values' + +export const PostModel = model.define('post', { + id: model.id({ prefix: 'post' }).primaryKey(), + type: model.enum([...postTypeValues]), + title: model.text().searchable(), + handle: model.text().unique().searchable().nullable(), + excerpt: model.text().searchable().nullable(), + content: model.json().nullable(), + status: model.enum([...postStatusValues]).default('draft'), + content_mode: model.enum([...postContentModeValues]).default('advanced'), + seo: model.json().nullable(), + published_at: model.text().nullable(), + archived_at: model.text().nullable(), + is_home_page: model.boolean().default(false), + + // relations fields + featured_image: model.hasOne(() => ImageModel, { + mappedBy: 'post', + }), + authors: model.manyToMany(() => PostAuthorModel, { + mappedBy: 'posts', + }), + + root: model.belongsTo(() => PostModel).nullable(), + + sections: model.hasMany(() => PostSectionModel), + + tags: model.manyToMany(() => PostTagModel, { + mappedBy: 'posts', + }), +}) diff --git a/apps/medusa/src/modules/page-builder/models/site-settings.ts b/apps/medusa/src/modules/page-builder/models/site-settings.ts new file mode 100644 index 000000000..8f97c169b --- /dev/null +++ b/apps/medusa/src/modules/page-builder/models/site-settings.ts @@ -0,0 +1,32 @@ +import { model } from '@medusajs/framework/utils' +import { ImageModel } from './image' + +export const SiteSettingsModel = model.define('site_settings', { + id: model.id({ prefix: 'site_sett' }).primaryKey(), + description: model.text().nullable(), + header_code: model.text().nullable(), + footer_code: model.text().nullable(), + storefront_url: model.text().nullable(), + primary_theme_colors: model.json().nullable(), + accent_theme_colors: model.json().nullable(), + highlight_theme_colors: model.json().nullable(), + display_font: model.json().nullable(), + body_font: model.json().nullable(), + include_site_name_beside_logo: model.boolean(), + social_instagram: model.text().nullable(), + social_youtube: model.text().nullable(), + social_facebook: model.text().nullable(), + social_twitter: model.text().nullable(), + social_linkedin: model.text().nullable(), + social_pinterest: model.text().nullable(), + social_tiktok: model.text().nullable(), + social_snapchat: model.text().nullable(), + global_css: model.text().nullable(), + ga_property_id: model.text().nullable(), + shipping_sort: model.text().nullable(), + + // relations + favicon: model.hasOne(() => ImageModel, { + mappedBy: 'site_settings', + }), +}) diff --git a/apps/medusa/src/modules/page-builder/service.ts b/apps/medusa/src/modules/page-builder/service.ts new file mode 100644 index 000000000..fef52e9b3 --- /dev/null +++ b/apps/medusa/src/modules/page-builder/service.ts @@ -0,0 +1,24 @@ +import { MedusaService } from '@medusajs/framework/utils' +import { + PostAuthorModel, + PostModel, + PostTemplateModel, + PostTagModel, + PostSectionModel, + ImageModel, + SiteSettingsModel, + NavigationItemModel, +} from './models' + +class PageBuilderService extends MedusaService({ + PostAuthor: PostAuthorModel, + Post: PostModel, + PostTemplate: PostTemplateModel, + PostTag: PostTagModel, + PostSection: PostSectionModel, + Image: ImageModel, + SiteSettings: SiteSettingsModel, + NavigationItem: NavigationItemModel, +}) {} + +export default PageBuilderService diff --git a/apps/medusa/src/subscribers/README.md b/apps/medusa/src/subscribers/README.md index 9ff0d79d4..f053dcbad 100644 --- a/apps/medusa/src/subscribers/README.md +++ b/apps/medusa/src/subscribers/README.md @@ -9,7 +9,7 @@ For example, create the file `src/subscribers/product-created.ts` with the follo ```ts import { type SubscriberConfig, -} from "@medusajs/medusa" +} from "@medusajs/framework" // subscriber function export default async function productCreateHandler() { @@ -38,9 +38,7 @@ A subscriber receives an object having the following properties: import type { SubscriberArgs, SubscriberConfig, -} from "@medusajs/medusa" -import { IProductModuleService } from "@medusajs/types" -import { ModuleRegistrationName } from "@medusajs/utils" +} from "@medusajs/framework" export default async function productCreateHandler({ event: { data }, diff --git a/apps/medusa/src/workflows/create-post.ts b/apps/medusa/src/workflows/create-post.ts new file mode 100644 index 000000000..bb4604d99 --- /dev/null +++ b/apps/medusa/src/workflows/create-post.ts @@ -0,0 +1,25 @@ +import { transform } from '@medusajs/framework/workflows-sdk' +import { emitEventStep } from '@medusajs/medusa/core-flows' +import { WorkflowResponse, createWorkflow } from '@medusajs/workflows-sdk' + +import type { CreatePostWorkflowInput } from './types' +import { pageBuilderModuleEvents } from '../modules/page-builder' +import { createPostStep } from './steps/create-post' + +export const createPostWorkflow = createWorkflow( + 'create-post-workflow', + (input: CreatePostWorkflowInput) => { + const post = createPostStep(input.post) + + const emitData = transform({ post }, ({ post }) => { + return { + eventName: pageBuilderModuleEvents.POST_CREATED, + data: { id: post.id }, + } + }) + + emitEventStep(emitData) + + return new WorkflowResponse(post) + }, +) diff --git a/apps/medusa/src/workflows/delete-post.ts b/apps/medusa/src/workflows/delete-post.ts new file mode 100644 index 000000000..1d2c910dd --- /dev/null +++ b/apps/medusa/src/workflows/delete-post.ts @@ -0,0 +1,26 @@ +import { transform } from '@medusajs/framework/workflows-sdk' +import { emitEventStep } from '@medusajs/medusa/core-flows' +import { WorkflowResponse, createWorkflow } from '@medusajs/workflows-sdk' + +import type { DeletePostWorkflowInput } from './types' +import { pageBuilderModuleEvents } from '../modules/page-builder' +import { deletePostStep } from './steps/delete-post' + +// Delete post workflow +export const deletePostWorkflow = createWorkflow( + 'delete-post-workflow', + (input: DeletePostWorkflowInput) => { + const result = deletePostStep({ id: input.id }) + + const emitData = transform({ result }, ({ result }) => { + return { + eventName: pageBuilderModuleEvents.POST_DELETED, + data: { id: result.id }, + } + }) + + emitEventStep(emitData) + + return new WorkflowResponse(result) + }, +) diff --git a/apps/medusa/src/workflows/duplicate-post.ts b/apps/medusa/src/workflows/duplicate-post.ts new file mode 100644 index 000000000..7dc64ea80 --- /dev/null +++ b/apps/medusa/src/workflows/duplicate-post.ts @@ -0,0 +1,32 @@ +import { transform } from '@medusajs/framework/workflows-sdk' +import { emitEventStep } from '@medusajs/medusa/core-flows' +import { WorkflowResponse, createWorkflow } from '@medusajs/workflows-sdk' + +import type { DuplicatePostWorkflowInput } from './types' +import { pageBuilderModuleEvents } from '../modules/page-builder' +import { duplicatePostStep } from './steps/duplicate-post' +import { duplicatePostRelationsStep } from './steps/duplicate-post-relations' + +// Duplicate post workflow +export const duplicatePostWorkflow = createWorkflow( + 'duplicate-post-workflow', + (input: DuplicatePostWorkflowInput) => { + const newPost = duplicatePostStep({ id: input.id }) + + const postWithRelations = duplicatePostRelationsStep({ + originalId: input.id, + newId: newPost.id, + }) + + const emitData = transform({ post: newPost }, ({ post }) => { + return { + eventName: pageBuilderModuleEvents.POST_CREATED, + data: { id: post.id }, + } + }) + + emitEventStep(emitData) + + return new WorkflowResponse(postWithRelations) + }, +) diff --git a/apps/medusa/src/workflows/steps/create-post.ts b/apps/medusa/src/workflows/steps/create-post.ts new file mode 100644 index 000000000..93507a037 --- /dev/null +++ b/apps/medusa/src/workflows/steps/create-post.ts @@ -0,0 +1,37 @@ +import { StepResponse, createStep } from '@medusajs/workflows-sdk' + +import type { CreatePostStepInput } from '../types' +import { PAGE_BUILDER_MODULE } from '../../modules/page-builder' +import type PageBuilderService from '../../modules/page-builder/service' + +export const createPostStepId = 'create-post-step' + +export const createPostStep = createStep( + createPostStepId, + async (data: CreatePostStepInput, { container }) => { + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + const createData: CreatePostStepInput = { + ...data, + status: data.status || 'draft', + content_mode: data.content_mode || 'advanced', + } + + const post = await pageBuilderService.createPosts(createData) + + return new StepResponse(post, { + postId: post.id, + }) + }, + async (data, { container }) => { + if (!data) return + + const { postId } = data + + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + await pageBuilderService.deletePosts(postId) + }, +) diff --git a/apps/medusa/src/workflows/steps/delete-post.ts b/apps/medusa/src/workflows/steps/delete-post.ts new file mode 100644 index 000000000..b292731a8 --- /dev/null +++ b/apps/medusa/src/workflows/steps/delete-post.ts @@ -0,0 +1,49 @@ +import { StepResponse, createStep } from '@medusajs/workflows-sdk' + +import type { CreatePostStepInput, DeletePostStepInput } from '../types' +import { PAGE_BUILDER_MODULE } from '../../modules/page-builder' +import type PageBuilderService from '../../modules/page-builder/service' + +export const deletePostStepId = 'delete-post-step' + +export const deletePostStep = createStep( + deletePostStepId, + async (data: DeletePostStepInput, { container }) => { + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + // Get the existing post before deleting for rollback + const existingPost = await pageBuilderService.retrievePost(data.id, { + relations: ['root', 'featured_image', 'authors', 'sections', 'tags'], + }) + + await pageBuilderService.deletePosts(data.id) + + return new StepResponse({ id: data.id }, existingPost) + }, + async (existingPost, { container }) => { + if (!existingPost) return + + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + // Restore the deleted post + const createPostInput: { + id: string + sections?: string[] + } & CreatePostStepInput = { + ...existingPost, + + // relations + root_id: existingPost.root?.root?.id ?? undefined, + featured_image_id: existingPost.featured_image?.id, + authors: existingPost.authors?.map((author) => author.id), + sections: existingPost.sections?.map((section) => section.id), + tags: existingPost.tags?.map((tag) => tag.id), + } + + const restoredPost = await pageBuilderService.createPosts(createPostInput) + + return restoredPost + }, +) diff --git a/apps/medusa/src/workflows/steps/duplicate-post-relations.ts b/apps/medusa/src/workflows/steps/duplicate-post-relations.ts new file mode 100644 index 000000000..2c0989dda --- /dev/null +++ b/apps/medusa/src/workflows/steps/duplicate-post-relations.ts @@ -0,0 +1,82 @@ +import { StepResponse, createStep } from '@medusajs/workflows-sdk' +import { PAGE_BUILDER_MODULE } from '../../modules/page-builder' +import type PageBuilderService from '../../modules/page-builder/service' + +export const duplicatePostRelationsStepId = 'duplicate-post-relations-step' + +type DuplicatePostRelationsStepInput = { + originalId: string + newId: string +} + +export const duplicatePostRelationsStep = createStep( + duplicatePostRelationsStepId, + async (data: DuplicatePostRelationsStepInput, { container }) => { + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + // Get the original post with all its relations + const originalPost = await pageBuilderService.retrievePost( + data.originalId, + { + relations: ['sections', 'featured_image', 'authors', 'tags'], + }, + ) + + const newPost = await pageBuilderService.retrievePost(data.newId) + const newPostSectionsIds: string[] = [] + + // Duplicate the sections since these should be unique to the post + if (originalPost.sections?.length > 0) { + type SectionInput = Parameters< + typeof pageBuilderService.createPostSections + >['0'][number] + + const sectionsToCreate: SectionInput[] = originalPost.sections.map( + (section) => ({ + ...section, + id: undefined, + post_template: undefined, + post_template_id: undefined, + + // Set the new post relation + post: newPost.id, + post_id: newPost.id, + }), + ) + + const newPostSections = + await pageBuilderService.createPostSections(sectionsToCreate) + + newPostSectionsIds.push(...newPostSections.map(({ id }) => id)) + } + + const relationsToUpdate = { + sections: newPostSectionsIds, + featured_image: originalPost.featured_image?.id, + authors: originalPost.authors?.map((author) => author.id) ?? [], + tags: originalPost.tags?.map((tag) => tag.id) ?? [], + } + + const updatedPost = await pageBuilderService.updatePosts({ + id: newPost.id, + ...relationsToUpdate, + }) + + return new StepResponse(updatedPost, { + relationsUpdated: relationsToUpdate, + }) + }, + async (data, { container }) => { + if (!data?.relationsUpdated) return + + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + const { sections, featured_image, authors, tags } = data.relationsUpdated + + if (sections?.length) { + await pageBuilderService.deletePostSections(sections) + } + }, +) diff --git a/apps/medusa/src/workflows/steps/duplicate-post.ts b/apps/medusa/src/workflows/steps/duplicate-post.ts new file mode 100644 index 000000000..5ded7251b --- /dev/null +++ b/apps/medusa/src/workflows/steps/duplicate-post.ts @@ -0,0 +1,51 @@ +import { StepResponse, createStep } from '@medusajs/workflows-sdk' + +import type { DuplicatePostStepInput } from '../types' +import { PAGE_BUILDER_MODULE } from '../../modules/page-builder' +import type PageBuilderService from '../../modules/page-builder/service' + +export const duplicatePostStepId = 'duplicate-post-step' + +export const duplicatePostStep = createStep( + duplicatePostStepId, + async (data: DuplicatePostStepInput, { container }) => { + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + // Get the existing post to duplicate + const existingPost = await pageBuilderService.retrievePost(data.id) + + // Create a new title with "(copy)" suffix + const newTitle = `${existingPost.title || 'Untitled'} (copy)` + + // Create a new handle or make it null to generate a new one + const handle = existingPost.handle ? `${existingPost.handle}-copy` : null + + // Create a new post with the copied data + const newPost = await pageBuilderService.createPosts({ + title: newTitle, + handle, + excerpt: existingPost.excerpt, + content: existingPost.content, + status: 'draft', // Always start as draft + type: existingPost.type, + content_mode: existingPost.content_mode, + seo: existingPost.seo ? { ...existingPost.seo } : undefined, + is_home_page: false, // Never copy home page status + }) + + return new StepResponse(newPost, { + originalId: existingPost.id, + newId: newPost.id, + }) + }, + async (data, { container }) => { + if (!data) return + + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + // Delete the created post if workflow fails + await pageBuilderService.deletePosts(data.newId) + }, +) diff --git a/apps/medusa/src/workflows/steps/update-post.ts b/apps/medusa/src/workflows/steps/update-post.ts new file mode 100644 index 000000000..24c771749 --- /dev/null +++ b/apps/medusa/src/workflows/steps/update-post.ts @@ -0,0 +1,42 @@ +import { StepResponse, createStep } from '@medusajs/workflows-sdk' + +import type { UpdatePostStepInput } from '../types' +import { PAGE_BUILDER_MODULE } from '../../modules/page-builder' +import type PageBuilderService from '../../modules/page-builder/service' + +export const updatePostStepId = 'update-post-step' + +export const updatePostStep = createStep( + updatePostStepId, + async (data: UpdatePostStepInput, { container }) => { + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + // Get the existing post before updating for rollback + const existingPost = await pageBuilderService.retrievePost(data.id, { + relations: ['root', 'featured_image', 'authors', 'sections', 'tags'], + }) + + const post = await pageBuilderService.updatePosts(data) + + return new StepResponse(post, { + ...existingPost, + + // relations + root_id: existingPost.root?.root?.id ?? undefined, + featured_image_id: existingPost.featured_image?.id, + authors: existingPost.authors?.map((author) => author.id), + sections: existingPost.sections?.map((section) => section.id), + tags: existingPost.tags?.map((tag) => tag.id), + } as UpdatePostStepInput) + }, + async (existingData, { container }) => { + if (!existingData) return + + const pageBuilderService = + container.resolve(PAGE_BUILDER_MODULE) + + // Rollback to the previous state with only the updatable fields + await pageBuilderService.updatePosts(existingData) + }, +) diff --git a/apps/medusa/src/workflows/types/index.ts b/apps/medusa/src/workflows/types/index.ts new file mode 100644 index 000000000..843aec5fa --- /dev/null +++ b/apps/medusa/src/workflows/types/index.ts @@ -0,0 +1,42 @@ +import type { Post } from '@lambdacurry/page-builder-types'; + +type PostInput = Omit< + Post, + 'id' | 'created_at' | 'updated_at' | 'featured_image' | 'root' | 'sections' | 'authors' | 'tags' +>; + +// Post types +export type CreatePostStepInput = Partial & { + featured_image_id?: string; + authors?: string[]; + tags?: string[]; +}; + +export type UpdatePostStepInput = { + id: string; + sections?: string[]; +} & Partial; + +export type DeletePostStepInput = { + id: string; +}; + +export type CreatePostWorkflowInput = { + post: CreatePostStepInput; +}; + +export type UpdatePostWorkflowInput = { + post: UpdatePostStepInput; +}; + +export type DeletePostWorkflowInput = { + id: string; +}; + +export type DuplicatePostStepInput = { + id: string; +}; + +export type DuplicatePostWorkflowInput = { + id: string; +}; diff --git a/apps/medusa/src/workflows/update-post.ts b/apps/medusa/src/workflows/update-post.ts new file mode 100644 index 000000000..bfedc5057 --- /dev/null +++ b/apps/medusa/src/workflows/update-post.ts @@ -0,0 +1,25 @@ +import { transform } from '@medusajs/framework/workflows-sdk' +import { emitEventStep } from '@medusajs/medusa/core-flows' +import { WorkflowResponse, createWorkflow } from '@medusajs/workflows-sdk' + +import type { UpdatePostWorkflowInput } from './types' +import { pageBuilderModuleEvents } from '../modules/page-builder' +import { updatePostStep } from './steps/update-post' + +export const updatePostWorkflow = createWorkflow( + 'update-post-workflow', + (input: UpdatePostWorkflowInput) => { + const post = updatePostStep(input.post) + + const emitData = transform({ post }, ({ post }) => { + return { + eventName: pageBuilderModuleEvents.POST_UPDATED, + data: { id: post.id }, + } + }) + + emitEventStep(emitData) + + return new WorkflowResponse(post) + }, +) diff --git a/apps/storefront/package.json b/apps/storefront/package.json index e03ae1d31..e3424e2e1 100644 --- a/apps/storefront/package.json +++ b/apps/storefront/package.json @@ -25,7 +25,7 @@ "directory": "packages/markethaus-storefront" }, "devDependencies": { - "@medusajs/types": "2.7.0", + "@medusajs/types": "2.8.2", "@react-router/dev": "^7.5.3", "@react-router/fs-routes": "^7.5.3", "@swc-node/register": "^1.4.2", @@ -83,8 +83,7 @@ "@heroicons/react": "^2.0.18", "@lambdacurry/forms": "^0.15.0", "@lambdacurry/medusa-plugins-sdk": "0.0.5", - "@loadable/component": "^5.15.3", - "@medusajs/js-sdk": "2.7.0", + "@medusajs/js-sdk": "2.8.2", "@mjackson/file-storage": "^0.6.1", "@mjackson/form-data-parser": "^0.7.0", "@radix-ui/react-slot": "^1.0.2", diff --git a/package.json b/package.json index 812b8edf0..77669a136 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "node": ">=20" }, "resolutions": { - "@medusajs/js-sdk": "2.7.0", - "@medusajs/types": "2.7.0" + "@medusajs/js-sdk": "2.8.2", + "@medusajs/types": "2.8.2" }, "packageManager": "yarn@4.5.0", "workspaces": [ diff --git a/packages/page-builder-sdk/.gitignore b/packages/page-builder-sdk/.gitignore new file mode 100644 index 000000000..f3f3b3c06 --- /dev/null +++ b/packages/page-builder-sdk/.gitignore @@ -0,0 +1,12 @@ +/dist +/node_modules + +.idea +.DS_Store + +yarn-error.log + +*.tsbuildinfo + +.cache +.turbo \ No newline at end of file diff --git a/packages/page-builder-sdk/README.md b/packages/page-builder-sdk/README.md new file mode 100644 index 000000000..6c3e8d1c8 --- /dev/null +++ b/packages/page-builder-sdk/README.md @@ -0,0 +1,182 @@ +# @lambdacurry/medusa-plugins-sdk + +SDK for Medusa plugins by Lambda Curry. + +This package is built on top of `@medusajs/js-sdk` and adds a set of resources and methods for interacting with the [Medusa Plugins Collection](https://github.com/lambda-curry/medusa-plugins?tab=readme-ov-file#available-plugins). + +## Installation + +```bash +yarn install @lambdacurry/medusa-plugins-sdk + +# or, if you're using yarn workspaces +yarn workspace my-app add @lambdacurry/medusa-plugins-sdk +``` + +> Read more about working with **monorepos** in the [Development](#development) section. + +## Usage + +```typescript +import { + MedusaPluginsSDK, + StoreListProductReviewsQuery, + StoreListProductReviewStatsQuery, +} from '@lambdacurry/medusa-plugins-sdk'; + +// Initialize the SDK +const sdk = new MedusaPluginsSDK({ + baseUrl: process.env.MEDUSA_BACKEND_URL || 'http://localhost:9000', + publishableKey: process.env.MEDUSA_PUBLISHABLE_KEY, +}); + +// List product reviews +const productReviews = await sdk.store.productReviews.list({ + product_id: product.id, + offset: 0, + limit: 10, +}) +``` + +### Extending my own SDK +If you need to extend the SDK with your own resources, you can do so by creating your own classes and extending the SDK. + +Available resources: +- `AdminProductReviewsResource` +- `StoreProductReviewsResource` + +#### Example +```typescript +import Medusa, { Admin, Store, type Client, type Config } from '@medusajs/js-sdk'; +import { AdminProductReviewsResource } from '@lambdacurry/medusa-plugins-sdk'; + +type MyCustom = { + id: string; + name: string; +}; + +type MyQuery = { + name: string; +}; + +type MyResponse = { + myCustom: MyCustom[]; +}; + +export class AdminMyCustomResource { + constructor(private client: Client) {} + + // example admin method + async list(query: MyQuery) { + return this.client.fetch(`/admin/my-custom`, { + method: 'GET', + query, + }); + } + + // custom admin methods +} + +class MyAdmin extends Admin { + public productReviews: AdminProductReviewsResource; + public myCustom: AdminMyCustomResource; + + constructor(client: Client) { + super(client); + + this.productReviews = new AdminProductReviewsResource(client); + this.myCustom = new AdminMyCustomResource(client); + } +} + +class StoreMyCustomResource { + constructor(private client: Client) {} + + // custom store methods +} + +class MyStore extends Store { + public store: StoreMyCustomResource; + + constructor(client: Client) { + super(client); + this.store = new StoreMyCustomResource(client); + } +} + +export class MyExtendedSDK extends Medusa { + public override admin: MyAdmin; + public override store: MyStore; + + constructor(config: Config) { + super(config); + this.admin = new MyAdmin(this.client); + this.store = new MyStore(this.client); + } +} +``` + +## Development +> Visit the [README.md](https://github.com/lambda-curry/medusa-plugins/blob/main/README.md) for setting up the development environment. + + +We use [`yalc`](https://github.com/wclr/yalc) for local development, which allows us to publish the package locally and use it in other projects. So, make sure you have `yalc` installed as a dev dependency in your project. + +To publish the package locally, run: +```bash +# from medusa-plugins/packages/plugins-sdk +yarn dev:publish + +# from your project +yarn yalc add @lambdacurry/medusa-plugins-sdk +``` + +### Working with medusa applications +When working with a Medusa application, you need to ensure that the SDK is included in the Vite config's `optimizeDeps` option. + +```typescript +// medusa-config.ts + +module.exports = defineConfig({ + // other configs... + admin: { + // other admin configs... + vite: () => { + return { + optimizeDeps: { + include: ['@lambdacurry/medusa-plugins-sdk'], + }, + }; + }, + }, +}); +``` + +### Working with Vite applications +When working with a Vite application, you need to ensure that the SDK is included in the Vite config's `ssr.noExternal` option. + +```typescript +// vite.config.ts + +export default defineConfig({ + // other configs... + ssr: { + noExternal: ['@medusajs/js-sdk', '@lambdacurry/medusa-plugins-sdk'], + }, +}); +``` + +### Working with monorepos +If you're using a monorepo setup, you can use the `hoistingLimits` option in your `package.json` to ensure that the SDK is installed in the correct location. +```typescript +// monorepo/path-to/your-app/package.json +{ + "installConfig": { + "hoistingLimits": "workspaces" + }, +} +``` + +## License + +MIT © [Lambda Curry](https://lambdacurry.dev) diff --git a/packages/page-builder-sdk/package.json b/packages/page-builder-sdk/package.json new file mode 100644 index 000000000..b767eff5d --- /dev/null +++ b/packages/page-builder-sdk/package.json @@ -0,0 +1,58 @@ +{ + "name": "@lambdacurry/page-builder-sdk", + "version": "0.0.6-beta.3", + "description": "SDK for Medusa plugins", + "author": "Lambda Curry (https://lambdacurry.dev)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/lambda-curry/medusa-plugins" + }, + "homepage": "https://github.com/lambda-curry/medusa-plugins/tree/main/packages/plugins-sdk", + "files": [ + "dist" + ], + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/esm/index.d.ts", + "exports": { + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js", + "types": "./dist/esm/index.d.ts" + }, + "keywords": [ + "medusa", + "plugin", + "sdk", + "medusa-plugins-sdk", + "medusa-v2", + "lambdacurry" + ], + "scripts": { + "build": "rimraf dist && tsc -p tsconfig.json && tsc -p tsconfig.esm.json", + "clean": "rm -rf dist", + "typecheck": "tsc --noEmit", + "lint": "prettier --check \"src/**/*.{ts,tsx}\"", + "format": "prettier --write \"src/**/*.{ts,tsx}\"", + "prepublishOnly": "yarn build", + "dev:publish": "yalc publish" + }, + "devDependencies": { + "@lambdacurry/page-builder-types": "workspace:*", + "@medusajs/types": "2.8.2", + "prettier": "^3.2.5", + "rimraf": "^6.0.1", + "tsup": "^8.0.2", + "typescript": "^5.7.2", + "yalc": "^1.0.0-pre.53" + }, + "dependencies": { + "@medusajs/js-sdk": "^2.8.2", + "@types/express": "^5.0.0", + "@types/multer": "^1.4.12", + "form-data": "^4.0.2" + }, + "engines": { + "node": ">=20" + } +} diff --git a/packages/page-builder-sdk/src/index.ts b/packages/page-builder-sdk/src/index.ts new file mode 100644 index 000000000..e28e54c22 --- /dev/null +++ b/packages/page-builder-sdk/src/index.ts @@ -0,0 +1,2 @@ +export * from './sdk' +export * from './types' diff --git a/packages/page-builder-sdk/src/sdk/admin/admin-page-builder.ts b/packages/page-builder-sdk/src/sdk/admin/admin-page-builder.ts new file mode 100644 index 000000000..013075a95 --- /dev/null +++ b/packages/page-builder-sdk/src/sdk/admin/admin-page-builder.ts @@ -0,0 +1,48 @@ +import type { Client } from '@medusajs/js-sdk'; +import type { + AdminPageBuilderCreatePostBody, + AdminPageBuilderCreatePostResponse, + AdminPageBuilderListPostsQuery, + AdminPageBuilderListPostsResponse, + AdminPageBuilderDeletePostResponse, + AdminPageBuilderUpdatePostBody, + AdminPageBuilderUpdatePostResponse, + AdminPageBuilderDuplicatePostResponse, +} from '@lambdacurry/page-builder-types'; + +export class AdminPageBuilderResource { + constructor(private client: Client) {} + + async listPosts(query: AdminPageBuilderListPostsQuery) { + return this.client.fetch('/admin/content/posts', { + method: 'GET', + query, + }); + } + + async createPost(data: AdminPageBuilderCreatePostBody) { + return this.client.fetch('/admin/content/posts', { + method: 'POST', + body: data, + }); + } + + async updatePost(id: string, data: AdminPageBuilderUpdatePostBody) { + return this.client.fetch(`/admin/content/posts/${id}`, { + method: 'PUT', + body: data, + }); + } + + async deletePost(id: string) { + return this.client.fetch(`/admin/content/posts/${id}`, { + method: 'DELETE', + }); + } + + async duplicatePost(id: string) { + return this.client.fetch(`/admin/content/posts/${id}/duplicate`, { + method: 'POST', + }); + } +} diff --git a/packages/page-builder-sdk/src/sdk/admin/index.ts b/packages/page-builder-sdk/src/sdk/admin/index.ts new file mode 100644 index 000000000..5f20f3043 --- /dev/null +++ b/packages/page-builder-sdk/src/sdk/admin/index.ts @@ -0,0 +1,12 @@ +import type { Client } from '@medusajs/js-sdk'; +import { Admin } from '@medusajs/js-sdk'; +import { AdminPageBuilderResource } from './admin-page-builder'; +export class ExtendedAdminSDK extends Admin { + public pageBuilder: AdminPageBuilderResource; + + constructor(client: Client) { + super(client); + + this.pageBuilder = new AdminPageBuilderResource(client); + } +} diff --git a/packages/page-builder-sdk/src/sdk/index.ts b/packages/page-builder-sdk/src/sdk/index.ts new file mode 100644 index 000000000..f58db23d6 --- /dev/null +++ b/packages/page-builder-sdk/src/sdk/index.ts @@ -0,0 +1,15 @@ +import Medusa, { type Config } from '@medusajs/js-sdk'; +import { ExtendedAdminSDK } from './admin'; +import { ExtendedStorefrontSDK } from './store'; + +export class PageBuilderSDK extends Medusa { + public admin: ExtendedAdminSDK; + public store: ExtendedStorefrontSDK; + + constructor(config: Config) { + super(config); + + this.admin = new ExtendedAdminSDK(this.client); + this.store = new ExtendedStorefrontSDK(this.client); + } +} diff --git a/packages/page-builder-sdk/src/sdk/store/index.ts b/packages/page-builder-sdk/src/sdk/store/index.ts new file mode 100644 index 000000000..0e345e5f0 --- /dev/null +++ b/packages/page-builder-sdk/src/sdk/store/index.ts @@ -0,0 +1,13 @@ +import type { Client } from '@medusajs/js-sdk'; +import { Store } from '@medusajs/js-sdk'; +import { StorePageBuilderResource } from './store-page-builder'; + +export class ExtendedStorefrontSDK extends Store { + public pageBuilder: StorePageBuilderResource; + + constructor(client: Client) { + super(client); + + this.pageBuilder = new StorePageBuilderResource(client); + } +} diff --git a/packages/page-builder-sdk/src/sdk/store/store-page-builder.ts b/packages/page-builder-sdk/src/sdk/store/store-page-builder.ts new file mode 100644 index 000000000..0ad85f04c --- /dev/null +++ b/packages/page-builder-sdk/src/sdk/store/store-page-builder.ts @@ -0,0 +1,12 @@ +import type { Client } from '@medusajs/js-sdk' + +export class StorePageBuilderResource { + constructor(private client: Client) {} + + async test() { + console.log(this.client) + return { + message: 'Hello, world!', + } + } +} diff --git a/packages/page-builder-sdk/src/types/index.ts b/packages/page-builder-sdk/src/types/index.ts new file mode 100644 index 000000000..72b77b2cd --- /dev/null +++ b/packages/page-builder-sdk/src/types/index.ts @@ -0,0 +1,2 @@ +export * from './product-reviews' +export * from './product-review-stats' diff --git a/packages/page-builder-sdk/src/types/product-review-stats.ts b/packages/page-builder-sdk/src/types/product-review-stats.ts new file mode 100644 index 000000000..9f1cc68fa --- /dev/null +++ b/packages/page-builder-sdk/src/types/product-review-stats.ts @@ -0,0 +1,34 @@ +export type StoreProductReviewStats = { + id: string; + product_id: string; + average_rating: number | null; + review_count: number; + rating_count_1: number; + rating_count_2: number; + rating_count_3: number; + rating_count_4: number; + rating_count_5: number; + raw_average_rating: Record | null; + created_at: Date; + updated_at: Date; + deleted_at: Date | null; +} + +export type StoreListProductReviewStatsResponse = { + product_review_stats: StoreProductReviewStats[]; + count: number; + offset: number; + limit: number; +} + +export type StoreListProductReviewStatsQuery = { + offset: number; + limit: number; + fields?: string | undefined; + order?: string | undefined; + id?: string | string[] | undefined; + product_id?: string | string[] | undefined; + average_rating?: number | number[] | undefined; + created_at?: any; + updated_at?: any; +} diff --git a/packages/page-builder-sdk/src/types/product-reviews.ts b/packages/page-builder-sdk/src/types/product-reviews.ts new file mode 100644 index 000000000..516730800 --- /dev/null +++ b/packages/page-builder-sdk/src/types/product-reviews.ts @@ -0,0 +1,136 @@ +export type ProductReviewStatus = 'pending' | 'approved' | 'flagged'; + +export type AdminCreateProductReviewResponseDTO = { + content: string; +}; + +export type AdminUpdateProductReviewResponseDTO = { + content: string; +}; + +export type AdminListProductReviewsQuery = { + q?: string; + id?: string | string[]; + product_id?: string | string[]; + order_id?: string | string[]; + order_item_id?: string | string[]; + rating?: number | number[]; + limit?: number; + offset?: number; +}; + +export type AdminListProductReviewsResponse = { + product_reviews: AdminProductReview[]; + count: number; + offset: number; + limit: number; +}; + +export type AdminProductReview = { + id: string; + status: ProductReviewStatus; + content: string; + rating: number; + name: string; + email: string; + order_id?: string; + product_id?: string; + order_item_id?: string; + images: { + url: string; + }[]; + created_at: string; + updated_at: string; + product: { + id: string; + thumbnail?: string; + title: string; + }; + order: { + id: string; + display_id: string; + }; + response?: AdminProductReviewResponse; +}; + +export type AdminProductReviewResponse = { + content: string; + product_review_id: string; + created_at: string; + updated_at: string; +}; + +// Storefront + +export type StoreListProductReviewsQuery = { + offset: number; + limit: number; + fields?: string | undefined; + order?: string | undefined; + id?: string | string[] | undefined; + status?: ProductReviewStatus | ProductReviewStatus[] | undefined; + product_id?: string | string[] | undefined; + order_id?: string | string[] | undefined; + rating?: number | number[] | undefined; + created_at?: any; + updated_at?: any; +} + +export type StoreListProductReviewsResponse = { + product_reviews: StoreProductReview[]; + count: number; + offset: number; + limit: number; +}; + + +export type StoreProductReviewResponse = { + id: string; + content: string; + created_at: string; + updated_at: string; + deleted_at: string | null; + product_review_id: string; +} + +export type StoreProductReview = { + id: string; + content: string; + rating: number; + name: string; + email: string; + product_id?: string; + order_item_id?: string; + images: { + url: string; + }[]; + created_at: string; + updated_at: string; + response?: StoreProductReviewResponse; +}; + + +export type StoreUpsertProductReviewsDTO = { + reviews: { + order_id: string; + order_line_item_id: string; + rating: number; + content: string; + images: {url:string}[]; + }[]; +}; + +export type StoreUpsertProductReviewsResponse = { + product_reviews: StoreProductReview[]; +}; + + +export type StoreUploadProductReviewImagesResponse = { + uploads: [{ + url: string; + key: string; + }] | { + url: string; + key: string; + } | undefined +} \ No newline at end of file diff --git a/packages/page-builder-sdk/tsconfig.esm.json b/packages/page-builder-sdk/tsconfig.esm.json new file mode 100644 index 000000000..3375b5edf --- /dev/null +++ b/packages/page-builder-sdk/tsconfig.esm.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "target": "ES2022", + "outDir": "./dist/esm", + "esModuleInterop": true, + "declarationMap": true, + "declaration": true, + "module": "ES2022", + "moduleResolution": "Bundler", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "noImplicitReturns": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["./src/**/*"], + "exclude": ["./dist/**/*", "./src/**/__tests__", "./src/**/__mocks__", "node_modules"] +} diff --git a/packages/page-builder-sdk/tsconfig.json b/packages/page-builder-sdk/tsconfig.json new file mode 100644 index 000000000..2d665dc5e --- /dev/null +++ b/packages/page-builder-sdk/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "lib": ["ES2022"], + "target": "ES2022", + "outDir": "./dist/cjs", + "esModuleInterop": true, + "declaration": true, + "declarationMap": true, + "noUnusedLocals": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "noImplicitReturns": true, + "resolveJsonModule": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "allowJs": true, + "skipLibCheck": true, + "incremental": true, + "isolatedModules": true + }, + "include": ["./src/**/*"], + "exclude": ["./dist", "node_modules", "./src/**/__tests__", "./src/**/__mocks__"] +} diff --git a/packages/page-builder-sdk/tsup.config.ts b/packages/page-builder-sdk/tsup.config.ts new file mode 100644 index 000000000..f9e8c23e8 --- /dev/null +++ b/packages/page-builder-sdk/tsup.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'tsup' + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['cjs'], + dts: true, + splitting: false, + sourcemap: true, + clean: true, + treeshake: true, + external: ['@medusajs/js-sdk'] +}) diff --git a/packages/page-builder-types/.gitignore b/packages/page-builder-types/.gitignore new file mode 100644 index 000000000..b512c09d4 --- /dev/null +++ b/packages/page-builder-types/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/packages/page-builder-types/package.json b/packages/page-builder-types/package.json new file mode 100644 index 000000000..f43404f4d --- /dev/null +++ b/packages/page-builder-types/package.json @@ -0,0 +1,18 @@ +{ + "name": "@lambdacurry/page-builder-types", + "version": "0.0.4", + "packageManager": "yarn@4.6.0", + "types": "./src/index.d.ts", + "devDependencies": { + "typescript": "5.7.3" + }, + "exports": { + ".": "./src/index.d.ts" + }, + "installConfig": { + "hoistingLimits": "workspaces" + }, + "files": [ + "src" + ] +} diff --git a/packages/page-builder-types/src/admins.d.ts b/packages/page-builder-types/src/admins.d.ts new file mode 100644 index 000000000..cf4e1f4c1 --- /dev/null +++ b/packages/page-builder-types/src/admins.d.ts @@ -0,0 +1,79 @@ +import { PostContentMode, PostStatus, PostType } from './common'; +import type { Post } from './models'; + +// Response Types +export interface PaginatedResponse { + count: number; + offset: number; + limit: number; +} + +export type AdminPageBuilderListPostsQuery = { + offset?: number; + limit?: number; + q?: string; + id?: string | string[]; + title?: string; + handle?: string; + status?: PostStatus | PostStatus[]; + type?: PostType | PostType[]; + content_mode?: PostContentMode | PostContentMode[]; + is_home_page?: boolean; + // biome-ignore lint/suspicious/noExplicitAny: medusa infered type + published_at?: any; + // biome-ignore lint/suspicious/noExplicitAny: medusa infered type + archived_at?: any; + // biome-ignore lint/suspicious/noExplicitAny: medusa infered type + created_at?: any; + // biome-ignore lint/suspicious/noExplicitAny: medusa infered type + updated_at?: any; + order?: string; + fields?: string; +}; + +export interface AdminPageBuilderListPostsResponse extends PaginatedResponse { + posts: Post[]; +} + +export type AdminPageBuilderCreatePostBody = { + title: string; + handle?: string; + excerpt?: string; + content?: Record; + status?: PostStatus; + type?: PostType; + content_mode?: PostContentMode; + seo?: Record; + is_home_page?: boolean; +}; + +export interface AdminPageBuilderCreatePostResponse { + post: Post; +} + +export type AdminPageBuilderUpdatePostBody = { + id: string; + title?: string; + handle?: string; + excerpt?: string; + content?: Record; + status?: PostStatus; + type?: PostType; + content_mode?: PostContentMode; + seo?: Record; + is_home_page?: boolean; +}; + +export interface AdminPageBuilderUpdatePostResponse { + post: Post; +} + +export interface AdminPageBuilderDeletePostResponse { + id: string; + object: string; + deleted: boolean; +} + +export interface AdminPageBuilderDuplicatePostResponse { + post: Post; +} diff --git a/packages/page-builder-types/src/common.d.ts b/packages/page-builder-types/src/common.d.ts new file mode 100644 index 000000000..b57fef775 --- /dev/null +++ b/packages/page-builder-types/src/common.d.ts @@ -0,0 +1,39 @@ +/** + * Common type declarations for page builder + */ + +export type PostStatus = 'draft' | 'published' | 'archived' + +export type PostType = 'page' | 'post' + +export type PostContentMode = 'basic' | 'advanced' + +// These would be defined in the implementation file +export declare const postStatuses: readonly PostStatus[] +export declare const postTypes: readonly PostType[] +export declare const postContentModes: readonly PostContentMode[] + +export interface SortOptions { + sort?: string + order?: 'ASC' | 'DESC' +} + +export interface PaginationOptions { + limit?: number + offset?: number +} + +export interface FilterOptions { + q?: string + [key: string]: unknown +} + +export type QueryOptions = SortOptions & PaginationOptions & FilterOptions + +export interface FindConfig extends QueryOptions { + select?: (keyof T)[] + relations?: string[] + where?: { [K in keyof T]?: T[K] | T[K][] } & { + [key: string]: unknown + } +} diff --git a/packages/page-builder-types/src/index.d.ts b/packages/page-builder-types/src/index.d.ts new file mode 100644 index 000000000..cd043c0b3 --- /dev/null +++ b/packages/page-builder-types/src/index.d.ts @@ -0,0 +1,4 @@ +export * from './admins' +export * from './common' +export * from './models' +export * from './storefronts' diff --git a/packages/page-builder-types/src/models.d.ts b/packages/page-builder-types/src/models.d.ts new file mode 100644 index 000000000..1e22ad161 --- /dev/null +++ b/packages/page-builder-types/src/models.d.ts @@ -0,0 +1,92 @@ +/** + * Type declarations for page builder models + */ + +import type { PostContentMode, PostStatus, PostType } from './common' + +export interface Base { + id: string + created_at: string + updated_at: string | undefined +} + +export interface Post extends Base { + title: string + handle?: string | null + excerpt?: string | null + content?: Record | null + status: PostStatus + type: PostType + content_mode: PostContentMode + seo?: Record | null + is_home_page: boolean + published_at?: string | null + archived_at?: string | null + featured_image_id?: string + featured_image?: Image + authors?: PostAuthor[] + tags?: PostTag[] + sections?: PostSection[] + root_id?: string + root?: PostTemplate +} + +export interface Image extends Base { + url: string + alt?: string + width?: number + height?: number + mime_type?: string + file_size?: number + metadata?: Record +} + +export interface NavigationItem extends Base { + title: string + url: string + parent_id?: string + parent?: NavigationItem + children?: NavigationItem[] +} + +export interface PostAuthor extends Base { + name: string + bio?: string + posts?: Post[] +} + +export interface PostSection extends Base { + name: string + data?: Record + order: number + post_id?: string + post?: Post + parent_section_id?: string + parent_section?: PostSection + child_sections?: PostSection[] +} + +export interface PostTag extends Base { + name: string + posts?: Post[] +} + +export interface PostTemplate extends Base { + name: string + data?: Record + posts?: Post[] +} + +export interface SiteSettings extends Base { + site_name: string + site_url?: string + logo_id?: string + logo?: Image + favicon_id?: string + favicon?: Image + social_links?: Record + navigation?: Record + custom_css?: string + custom_js?: string + meta_defaults?: Record +} diff --git a/packages/page-builder-types/src/storefronts.d.ts b/packages/page-builder-types/src/storefronts.d.ts new file mode 100644 index 000000000..e6096dabb --- /dev/null +++ b/packages/page-builder-types/src/storefronts.d.ts @@ -0,0 +1,49 @@ +/** + * Storefront type declarations for page builder + */ + +import type { Post, PostAuthor, PostTag, SiteSettings } from './models' + +export interface StorefrontGetPostParams { + handle: string +} + +export interface StorefrontGetPostResponse { + post: Post +} + +export interface StorefrontListPostsParams { + limit?: number + offset?: number + type?: string + tag?: string + author?: string + sort?: string + order?: 'asc' | 'desc' +} + +export interface StorefrontListPostsResponse { + posts: Post[] + count: number + offset: number + limit: number +} + +export interface StorefrontGetTagsResponse { + tags: PostTag[] +} + +export interface StorefrontGetAuthorsResponse { + authors: PostAuthor[] +} + +export interface StorefrontGetSiteSettingsResponse { + settings: SiteSettings +} + +export interface StorefrontRenderOptions { + cacheControl?: string + handle?: string + language?: string + preview?: boolean +} diff --git a/yarn.lock b/yarn.lock index 2d373d339..bd14fafa3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2432,7 +2432,7 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/merge@npm:^9.0.19, @graphql-tools/merge@npm:^9.0.7": +"@graphql-tools/merge@npm:^9.0.19": version: 9.0.19 resolution: "@graphql-tools/merge@npm:9.0.19" dependencies: @@ -2444,6 +2444,18 @@ __metadata: languageName: node linkType: hard +"@graphql-tools/merge@npm:^9.0.7": + version: 9.0.21 + resolution: "@graphql-tools/merge@npm:9.0.21" + dependencies: + "@graphql-tools/utils": "npm:^10.8.3" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/35bbaea2bbc9e86a631019397e3ca1f53705e2fb608c688aed1d162426de826192b74fc7a8f90d95aa91e2d2bef12ded88674c91d5f42a26b6eb9f516c07fbd6 + languageName: node + linkType: hard + "@graphql-tools/optimize@npm:^2.0.0": version: 2.0.0 resolution: "@graphql-tools/optimize@npm:2.0.0" @@ -2481,7 +2493,22 @@ __metadata: languageName: node linkType: hard -"@graphql-tools/utils@npm:^10.0.0, @graphql-tools/utils@npm:^10.8.1": +"@graphql-tools/utils@npm:^10.0.0, @graphql-tools/utils@npm:^10.8.3": + version: 10.8.3 + resolution: "@graphql-tools/utils@npm:10.8.3" + dependencies: + "@graphql-typed-document-node/core": "npm:^3.1.1" + "@whatwg-node/promise-helpers": "npm:^1.0.0" + cross-inspect: "npm:1.0.1" + dset: "npm:^3.1.4" + tslib: "npm:^2.4.0" + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + checksum: 10c0/0a3b67e3984adae28955be018ee54c919ba6be5aff88365b26103cb7f7a98bdbc2213289234224fcc094b9f30a85bacc70151d2d9d16318a127877bbe6b57a76 + languageName: node + linkType: hard + +"@graphql-tools/utils@npm:^10.8.1": version: 10.8.1 resolution: "@graphql-tools/utils@npm:10.8.1" dependencies: @@ -3555,6 +3582,32 @@ __metadata: languageName: node linkType: hard +"@lambdacurry/page-builder-sdk@workspace:packages/page-builder-sdk": + version: 0.0.0-use.local + resolution: "@lambdacurry/page-builder-sdk@workspace:packages/page-builder-sdk" + dependencies: + "@lambdacurry/page-builder-types": "workspace:*" + "@medusajs/js-sdk": "npm:^2.8.2" + "@medusajs/types": "npm:2.8.2" + "@types/express": "npm:^5.0.0" + "@types/multer": "npm:^1.4.12" + form-data: "npm:^4.0.2" + prettier: "npm:^3.2.5" + rimraf: "npm:^6.0.1" + tsup: "npm:^8.0.2" + typescript: "npm:^5.7.2" + yalc: "npm:^1.0.0-pre.53" + languageName: unknown + linkType: soft + +"@lambdacurry/page-builder-types@workspace:*, @lambdacurry/page-builder-types@workspace:packages/page-builder-types": + version: 0.0.0-use.local + resolution: "@lambdacurry/page-builder-types@workspace:packages/page-builder-types" + dependencies: + typescript: "npm:5.7.3" + languageName: unknown + linkType: soft + "@loadable/component@npm:^5.15.3": version: 5.16.4 resolution: "@loadable/component@npm:5.16.4" @@ -3568,13 +3621,13 @@ __metadata: languageName: node linkType: hard -"@medusajs/admin-bundler@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/admin-bundler@npm:2.7.0" +"@medusajs/admin-bundler@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/admin-bundler@npm:2.8.2" dependencies: - "@medusajs/admin-shared": "npm:2.7.0" - "@medusajs/admin-vite-plugin": "npm:2.7.0" - "@medusajs/dashboard": "npm:2.7.0" + "@medusajs/admin-shared": "npm:2.8.2" + "@medusajs/admin-vite-plugin": "npm:2.8.2" + "@medusajs/dashboard": "npm:2.8.2" "@vitejs/plugin-react": "npm:^4.2.1" autoprefixer: "npm:^10.4.16" compression: "npm:^1.7.4" @@ -3585,35 +3638,35 @@ __metadata: postcss: "npm:^8.4.32" tailwindcss: "npm:^3.3.6" vite: "npm:^5.4.14" - checksum: 10c0/7bfc6325bde88f5765470c576a939a45216954a256d90913c6a69dfcc8be6e9a4c60da3f7d9e57712b5973a6036b2cec87ca7cc840c85ce18db06dd64133df52 + checksum: 10c0/049ca6ffaf2ee80c06073b1a0047e8c402d2b2bad16bd8de8819aac9bb7df622838ca2a411c41cab28a88ef46e73c8b6bcbcef7f8f5c008d1745071651e3ef98 languageName: node linkType: hard -"@medusajs/admin-sdk@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/admin-sdk@npm:2.7.0" +"@medusajs/admin-sdk@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/admin-sdk@npm:2.8.2" dependencies: - "@medusajs/admin-shared": "npm:2.7.0" + "@medusajs/admin-shared": "npm:2.8.2" zod: "npm:3.22.4" - checksum: 10c0/47e93d724500b9919d410ba39191aa573f66dc2ca3b7460b113f0a6fbf7dc25d37d423d92cb7a13a9e025c46599d3627aa4e64933391e72d221f028d7de51f1e + checksum: 10c0/be78e3ecfe213348d50bec8d6b683664dd249ba2e1a6553ef9943e4329c9033ace0c5fda31487f74f0a987c865721f747580e2ce33aceee3fbc654cb5ccc519a languageName: node linkType: hard -"@medusajs/admin-shared@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/admin-shared@npm:2.7.0" - checksum: 10c0/5bcde151bc325e66d42632d63d57d70bad235d303602d4dbd21062dcf9c5a9fb731c4ea9fb8b143bd81909bf47df0c105ee980d6653cc32f00d7c96cbd20118f +"@medusajs/admin-shared@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/admin-shared@npm:2.8.2" + checksum: 10c0/acf4c54c58939bf257747f9857e712443cf53e8af74f0e2b9eb9f33b2ee92b98d93cf93679b24720dd9e684bf48fb021be439fd14bd019dc7f5a617a8e241ca1 languageName: node linkType: hard -"@medusajs/admin-vite-plugin@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/admin-vite-plugin@npm:2.7.0" +"@medusajs/admin-vite-plugin@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/admin-vite-plugin@npm:2.8.2" dependencies: "@babel/parser": "npm:7.25.6" "@babel/traverse": "npm:7.25.6" "@babel/types": "npm:7.25.6" - "@medusajs/admin-shared": "npm:2.7.0" + "@medusajs/admin-shared": "npm:2.8.2" chokidar: "npm:3.5.3" fdir: "npm:6.1.1" magic-string: "npm:0.30.5" @@ -3621,107 +3674,107 @@ __metadata: picocolors: "npm:^1.1.0" peerDependencies: vite: ^5.0.0 - checksum: 10c0/2a7c82863acf58cc159040fe56e1ba15001279d8ec7784faf572fedbc4cc37cd8241d2c02c87275afd59670b976b967e055848f8110f92330de671ca38d6c405 + checksum: 10c0/38d38c933936048675d8cd5001e7ce816de411a921c6f635462803629556d4752b142e996684047632e81e6d80d2feed60b7be90a54c2efd2c19a96fa9b88d8d languageName: node linkType: hard -"@medusajs/api-key@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/api-key@npm:2.7.0" +"@medusajs/api-key@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/api-key@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/999dac6dde6a66686f41dbf4f161f5551c02f665de0f6ec47e44926be789906ea100b867101ce56573b22d81c3cb2f6902debfff96fb7c0bb48054b53056eec6 + checksum: 10c0/4b3a20cdcd11f107d25cfe08a95fe214c0ddd04db709f16fa527b9bfd0c7ac31145b51162c53b3a5ed82a43fa063079412d895f3d15d4075a780bc07a1019e72 languageName: node linkType: hard -"@medusajs/auth-emailpass@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/auth-emailpass@npm:2.7.0" +"@medusajs/auth-emailpass@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/auth-emailpass@npm:2.8.2" dependencies: scrypt-kdf: "npm:^2.0.1" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/7f81945bb40c3ac0503c94baf4fefaad8f2577f9f826c236294dd2fa9867c46af94523755a80341c946c702c2f4a1c8f18ea5f68bb82f240f5375bc90bb127e6 + "@medusajs/framework": 2.8.2 + checksum: 10c0/54e8ae15e61f9442debb33c4d19e3c0c98b3ec1c02808b7853330670cc54ba5f34d5ec2b262f0451cd3f71173ee6959cf2a4681cfa5dfcf2686757c4315825fd languageName: node linkType: hard -"@medusajs/auth-github@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/auth-github@npm:2.7.0" +"@medusajs/auth-github@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/auth-github@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/e641294cd456f61e6c05db97398fbd7fe26f8a317f6de92aa9ea59c39458e00893e59b810bae3bc01c7f7c54fe37a757ab61db4138b31c322b11880839821e79 + "@medusajs/framework": 2.8.2 + checksum: 10c0/a5a2140e88a3793923c4ead8158be2cdeff9fa502068d15a365f47294ec476b1875b39f6d323d0a85465fa0bfd7d1dbdf67305308d8a234299397c3148939a7c languageName: node linkType: hard -"@medusajs/auth-google@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/auth-google@npm:2.7.0" +"@medusajs/auth-google@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/auth-google@npm:2.8.2" dependencies: jsonwebtoken: "npm:^9.0.2" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/e4b99861f1d42d60329dac85e85819c02c4670b043d70394d5a2795abe8a61d455f5b3fa74b2286e45e84efa8295108a75d2f8237456c887a42287ca01b151ea + "@medusajs/framework": 2.8.2 + checksum: 10c0/56f3737751ded89ebb3a49ce3c108267fa4f846d1c91c7c5119f8e4d2b2dd12375e949d10dcead3513d65ec27f27b3cac05d04fb5fcb6ff9d7fc8179c6e52434 languageName: node linkType: hard -"@medusajs/auth@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/auth@npm:2.7.0" +"@medusajs/auth@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/auth@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/106aae8c874fcf6b31db66b8c00a07faf31f981ca04129439f29542edc2f9ff02007c79d3f6754007fe2775f267cf5f9144240710b3aa88bd0bf6cfc4c575d23 + checksum: 10c0/877309aba07046386255a289b61fbbab21b73b657d275b14c95aa6dae7246f9a52b5376ed1dc9dbc9c0c1895bb41738460fa8b8bf1e79b5f25c0e1c1018a91b6 languageName: node linkType: hard -"@medusajs/cache-inmemory@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/cache-inmemory@npm:2.7.0" +"@medusajs/cache-inmemory@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/cache-inmemory@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/a5dc069785a3869771c3b764cc39be87a80549dbfb84356c588710d2cd72b283d34432715e7ebf3d7f9d0cb6d06e230b1f51b19facc81be174ab3c96dae43084 + "@medusajs/framework": 2.8.2 + checksum: 10c0/e9d15eedda8156b189eefed0e54d2575b9592d355db221f320925d707324a6d5c5a98ac6134b2fdc1c14971444486ee048feea2392afe66f451c4f3ed9e7f066 languageName: node linkType: hard -"@medusajs/cache-redis@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/cache-redis@npm:2.7.0" +"@medusajs/cache-redis@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/cache-redis@npm:2.8.2" dependencies: ioredis: "npm:^5.4.1" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 awilix: ^8.0.1 - checksum: 10c0/75adb4b2e2c6f87148f533e57ee20f6513c5625e1e0a197788fa863b563bc1c5fee9192d991b53fd9077c7ee9b2e9df75e0d1ab90974750045dfeefaa39267ea + checksum: 10c0/1640d56569b249a4e68d7020ba9af8a66b22d06f965d157c9aca6917c650db065b2835c3d26f3eb0c8ec0c6fe17b5366bcb8f866515655bdf68ce7b8086c549c languageName: node linkType: hard -"@medusajs/cart@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/cart@npm:2.7.0" +"@medusajs/cart@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/cart@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/236fc7291c4b295ccad4cbc3fef0b6f590a3ebde2afe538bc963eea5cef20f350479c4478acd07f625da0d83dbed0bef701490dd1b037d1ba672e9017a8a0731 + checksum: 10c0/24251db7334faeca7b5ec3739fc4b3a52d5624be47045714a8aaddc8058c166ced24daaed9ec42616bb4f3a73648f5263612cfe528ef1f91df4a3f3c7c188b55 languageName: node linkType: hard -"@medusajs/cli@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/cli@npm:2.7.0" +"@medusajs/cli@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/cli@npm:2.8.2" dependencies: - "@medusajs/telemetry": "npm:2.7.0" - "@medusajs/utils": "npm:2.7.0" + "@medusajs/telemetry": "npm:2.8.2" + "@medusajs/utils": "npm:2.8.2" "@types/express": "npm:^4.17.17" chalk: "npm:^4.0.0" configstore: "npm:5.0.1" @@ -3753,66 +3806,68 @@ __metadata: pg: ^8.13.0 bin: medusa: cli.js - checksum: 10c0/12018ebe82b71f20f6f077f6223d1155538d891f70c5d906463eebc3d11b2a2be0f78e8ad07b6a56b89924005e2373968bf5f51eec2733bf281003a82922a12a + checksum: 10c0/45070a44c293cb94c104213ab05e54ab2960b0a36ec56dff8440b8ac86f4d8e1ae47ead13b7115c04c0999875e700d2208d47fa04e2f91edd6be6a29553e9e98 languageName: node linkType: hard -"@medusajs/core-flows@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/core-flows@npm:2.7.0" +"@medusajs/core-flows@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/core-flows@npm:2.8.2" dependencies: json-2-csv: "npm:^5.5.4" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 awilix: ^8.0.1 - checksum: 10c0/7a7774b4bb8879886fd90dc20a29ff716e2453307ac89bd0764964e10bdaab92aa15ddb7dfa38773c4294f531c691d76b8dc5df34d81bc9119930705343ee4af + checksum: 10c0/d8e7a03d0203b58ba2db9b1833496fbdb6407e0b543a8c474bc4f27407d426622f103bae00e67f561d91cbaa1ab816a70a5d22cdec8460ac08f6eb784ce7a4c4 languageName: node linkType: hard -"@medusajs/currency@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/currency@npm:2.7.0" +"@medusajs/currency@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/currency@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/b1d121bfaf27e184af6945885a39a748c1f213cd32f76c09c76c207cb49c00e029c708da3043e4417ef5ed88ca84aaa4bb295185a43435aa460b0d25983d24a9 + checksum: 10c0/2703c0c1b901e7fe7a4af4ead8adda5137e6741889d89473d411c34396d51947b38e9c3d60c7dee6b670aaf57363e7fbc75c652bd11d438f35e9c1ec5f2c839c languageName: node linkType: hard -"@medusajs/customer@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/customer@npm:2.7.0" +"@medusajs/customer@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/customer@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/92ad543adbeaae6dde2845060b4e93205007e4257c9df89b42b0b2658a2445388cd7bedf12462e80e692474351d55ebcacd51853a6e3c050344af60746840d2d + checksum: 10c0/6cce7326ca4c9361e327f9efd0b5e3850c6c4d6fa8ef23f35dd772c6b03d188120808ba8a077ad4a433f28e94d849c007bb158c7e9e69108722ac98914960f27 languageName: node linkType: hard -"@medusajs/dashboard@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/dashboard@npm:2.7.0" +"@medusajs/dashboard@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/dashboard@npm:2.8.2" dependencies: "@ariakit/react": "npm:^0.4.15" "@dnd-kit/core": "npm:^6.1.0" "@dnd-kit/sortable": "npm:^8.0.0" + "@dnd-kit/utilities": "npm:^3.2.2" "@hookform/error-message": "npm:^2.0.1" "@hookform/resolvers": "npm:3.4.2" - "@medusajs/admin-shared": "npm:2.7.0" - "@medusajs/icons": "npm:2.7.0" - "@medusajs/js-sdk": "npm:2.7.0" - "@medusajs/ui": "npm:4.0.8" + "@medusajs/admin-shared": "npm:2.8.2" + "@medusajs/icons": "npm:2.8.2" + "@medusajs/js-sdk": "npm:2.8.2" + "@medusajs/ui": "npm:4.0.12" "@tanstack/react-query": "npm:5.64.2" "@tanstack/react-table": "npm:8.20.5" "@tanstack/react-virtual": "npm:^3.8.3" "@uiw/react-json-view": "npm:^2.0.0-alpha.17" cmdk: "npm:^0.2.0" + copy-to-clipboard: "npm:^3.3.3" date-fns: "npm:^3.6.0" i18next: "npm:23.7.11" i18next-browser-languagedetector: "npm:7.2.0" @@ -3832,77 +3887,77 @@ __metadata: react-jwt: "npm:^1.2.0" react-router-dom: "npm:6.20.1" zod: "npm:3.22.4" - checksum: 10c0/a55dec5dc91249b4212103f1e5de88daee5844dde4af17fcefd120e1eaade616fb82225056d203243f6c043634b025e97eb4163e5553d71c7fd50c213228c841 + checksum: 10c0/d973dd3e18f6632728b08d38f0f6c701dfb229dbadee59e6a5b41f24abfa8b64745f68a051061f7dcd6eda4d59eab7df01c0de1dc039046ae5ef2e7eec56a058 languageName: node linkType: hard -"@medusajs/event-bus-local@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/event-bus-local@npm:2.7.0" +"@medusajs/event-bus-local@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/event-bus-local@npm:2.8.2" dependencies: ulid: "npm:^2.3.0" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/ac93fcf328b5b850d3d643bc44ed943cffbada8bacae4f9a918228d9b9e5a2c7f596ae4e8a206cba460afd199396206aaa0ce601d61c81ee15aba8b76aeb4bae + "@medusajs/framework": 2.8.2 + checksum: 10c0/0eeed4909cbeba4afe3f417f33a97eca8549e16a1ae0d9bcb4a2c78d09deaf8c824f5618506e5b8bfa4da4a2d5ad9279d39b7eccf0cb97a875c2570de61a2ce4 languageName: node linkType: hard -"@medusajs/event-bus-redis@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/event-bus-redis@npm:2.7.0" +"@medusajs/event-bus-redis@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/event-bus-redis@npm:2.8.2" dependencies: bullmq: "npm:5.13.0" ioredis: "npm:^5.4.1" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 awilix: ^8.0.1 - checksum: 10c0/552cfd3c0997c1e8e3f4d587ebdf1a238cb385f88d14c99e4d58fa5029a8ead1e03383564cc6e231565c8e62185e41afa7f8f51ede842ada66b6ab1d06cae299 + checksum: 10c0/f797c249c88549f8cf0998f8db4ed9d279c9ef076310973ea3b98cace2f7ff5e48b4348324994153b266f23dd5e9f12c3a297b8b4e38e192bffefdd7e15f157b languageName: node linkType: hard -"@medusajs/file-local@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/file-local@npm:2.7.0" +"@medusajs/file-local@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/file-local@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/45ab84ab922a4956fdb4dc82c99208ea6434ab300dfe269987b1c537d0d712132d8c05197160cc630255dda11418eb076cabcd1a54c81a3a75114cbeb5c1563b + "@medusajs/framework": 2.8.2 + checksum: 10c0/ce06955ceebb116e73b86f4cf10312058203ce5dfcc63581d66519fde54712459f5f606899c473781f5fb129499949cecdb0fa6ca6e3138e87e3a299f4bf9423 languageName: node linkType: hard -"@medusajs/file-s3@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/file-s3@npm:2.7.0" +"@medusajs/file-s3@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/file-s3@npm:2.8.2" dependencies: "@aws-sdk/client-s3": "npm:^3.556.0" "@aws-sdk/s3-request-presigner": "npm:^3.556.0" ulid: "npm:^2.3.0" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/e0250f49efa04726666d16a86376adc78b3274faf70eaa3fdcc2665072615bfea580acef6761320fe1b9a86a3de05bb7fdcd68a2f85bdd3152b3af4a36c95c33 + "@medusajs/framework": 2.8.2 + checksum: 10c0/987e5b1d5115fc2f215686e17395e50fa8bea820c022c933b1334e3bb72ff4d7a7d4b93485caad7409858fb041fb108c33e6804293b891ed1195893fd27be257 languageName: node linkType: hard -"@medusajs/file@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/file@npm:2.7.0" +"@medusajs/file@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/file@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 awilix: ^8.0.1 - checksum: 10c0/8ba954567457df88825d39c84f54f2a235f88fe497c3a008b4186ed044baa07f3510f19a7d79d4a7115c9be3ac88f4c20a6f194414faba36df3d492ed9a405c6 + checksum: 10c0/8a6521b292687366d4cfc6a3772e22b9ff645b495ac45f468d8d948d5709ea3998f93425d980d1345934c927f9c6464ba8acc861659016d1e7216700e6329a76 languageName: node linkType: hard -"@medusajs/framework@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/framework@npm:2.7.0" +"@medusajs/framework@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/framework@npm:2.8.2" dependencies: "@jercle/yargonaut": "npm:^1.1.5" - "@medusajs/modules-sdk": "npm:2.7.0" - "@medusajs/orchestration": "npm:2.7.0" - "@medusajs/telemetry": "npm:2.7.0" - "@medusajs/types": "npm:2.7.0" - "@medusajs/utils": "npm:2.7.0" - "@medusajs/workflows-sdk": "npm:2.7.0" + "@medusajs/modules-sdk": "npm:2.8.2" + "@medusajs/orchestration": "npm:2.8.2" + "@medusajs/telemetry": "npm:2.8.2" + "@medusajs/types": "npm:2.8.2" + "@medusajs/utils": "npm:2.8.2" + "@medusajs/workflows-sdk": "npm:2.8.2" "@opentelemetry/api": "npm:^1.9.0" "@types/express": "npm:^4.17.17" chokidar: "npm:^3.4.2" @@ -3920,193 +3975,200 @@ __metadata: tsconfig-paths: "npm:^4.2.0" zod: "npm:3.22.4" peerDependencies: - "@medusajs/cli": 2.7.0 + "@aws-sdk/client-dynamodb": ^3.218.0 + "@medusajs/cli": 2.8.2 "@mikro-orm/cli": 6.4.3 "@mikro-orm/core": 6.4.3 "@mikro-orm/knex": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 + connect-dynamodb: ^3.0.5 ioredis: ^5.4.1 pg: ^8.13.0 vite: ^5.4.14 peerDependenciesMeta: + "@aws-sdk/client-dynamodb": + optional: true "@mikro-orm/cli": optional: true + connect-dynamodb: + optional: true ioredis: optional: true vite: optional: true bin: medusa-mikro-orm: dist/mikro-orm-cli/bin.js - checksum: 10c0/05530a98a182dfc2c2a7dfb277940e110e5612e8bf79c1bb1c0b0c4cc1dad5deee0cdf54cb3e2690abed3ce6ccc729d7df89cbf9cbda7fe50f4f58fd568fd374 + checksum: 10c0/91cae636b241decb64fb379ef9fe8e2eddc2a4c79ffdc009a3739011d6e306d5734b26545407e481488c0cbdb6de3e7e97a45a3af4d49127af86fefcad078f8f languageName: node linkType: hard -"@medusajs/fulfillment-manual@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/fulfillment-manual@npm:2.7.0" +"@medusajs/fulfillment-manual@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/fulfillment-manual@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/1f1e606c83a180e43e4cbf413151ae8b9e7aef3819bf1c3edd45b61ff200c03bc933d0b690d1913ad3cd83df7374226eadcaeffe085660d98c6ec9ff152166c2 + "@medusajs/framework": 2.8.2 + checksum: 10c0/c1d314a5356183493b1345047dadd77c536a67b819b53e9da1d4c68feda57d635e477b411e487fa6cb740ffd5a37dd457ab2296db0d6fc68ff2a55234803e183 languageName: node linkType: hard -"@medusajs/fulfillment@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/fulfillment@npm:2.7.0" +"@medusajs/fulfillment@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/fulfillment@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/bfa1c24704ba9cb2dc7a0e1dd7b93d583190cb38ddfddfbd83c81908d92e7c16e57ecf97926b3d6a2865b4d27f7480fa1c980df648078deb66d28b58ddd57375 + checksum: 10c0/ef06c36e4b78375e6a05c74698d3afd8f41467936c4fcee74576f28384dbf437f3a7ea006014c57daeb29ce5f9734c212e86881b6c444c6a5e9b63ddd0d69279 languageName: node linkType: hard -"@medusajs/icons@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/icons@npm:2.7.0" +"@medusajs/icons@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/icons@npm:2.8.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - checksum: 10c0/17069e2c1dd1300773def2991e491be067df943aeb461ba52c54ae142f387f7f093887f559e7bfc937b92e422feaa52bacfb439329662ead7fd4780d47784c5c + checksum: 10c0/e23cf69bf81d22f1ad6758a1b1a9af5f5733c3dccfdbf9228f3e1b9be245d699ed3a7a1e9dce3a1ce8086d07b913295857070ad4be56018893e8868014ea9993 languageName: node linkType: hard -"@medusajs/index@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/index@npm:2.7.0" +"@medusajs/index@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/index@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/knex": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/42c19c61d27b05aea248d493ff28b35b2c5036dc3db387be9d07e484b095cb527dafb39b22dfc3379344c3e5db5da724dab047085f8893e7db8c62fc281302f6 + checksum: 10c0/7efa5ea45d6cf8c4525d2b99018e9086a1a9eb1c6b1fa3a6386a3172217c14c468c1090fff44cf0445cdf2f665a6e5d6d33eddf28ae956d997d8a3fdbb29ef3d languageName: node linkType: hard -"@medusajs/inventory@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/inventory@npm:2.7.0" +"@medusajs/inventory@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/inventory@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/bfa85e83e3bd8cda2ce04a8bd492dfc22f31c288ad94797f7780d75cee4eef525d011d166dd8eaa3c258fe60e403b16418d5f811a7937ec10463c49890a8cb8f + checksum: 10c0/23d642fd02f627054826057cca9d044d3b3b30c345ac06bf82e52b8b6c5dd485a51c425596f2e350e351310afdd390dd933f46ed8adc503a49d25b4edd054ce3 languageName: node linkType: hard -"@medusajs/js-sdk@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/js-sdk@npm:2.7.0" +"@medusajs/js-sdk@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/js-sdk@npm:2.8.2" dependencies: - "@medusajs/types": "npm:2.7.0" + "@medusajs/types": "npm:2.8.2" fetch-event-stream: "npm:^0.1.5" qs: "npm:^6.12.1" - checksum: 10c0/3bf9ffb0e801108787436b02c2f0e3bc92d45a50dc3ac20002e3e58b6479049e378afeb65b3c81e7d06fb310c9280f6afd326858842eb4a7e868a241d6eac0cc + checksum: 10c0/aaa1301aab1affd30f89a9af3101d2af60c58f009aaa6945fea6353670aa40fc1d986bc221078db857acb32866864a6661808991acd34437ca4a120f46cd4d69 languageName: node linkType: hard -"@medusajs/link-modules@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/link-modules@npm:2.7.0" +"@medusajs/link-modules@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/link-modules@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/4005071936589661fd94458682f1d264e357fb15a3a7eade54a557accb0bd55eb4c39dcec1b5b2db9f33a8aad0c2a6fc1d1bf24922399bc53c195dd29ad8eafd + checksum: 10c0/f61d0aead50453c50ec4c18af125409b944b3e19f66ed887042e0123cf82e548676a5188a54a013261918a13930303f8f2bd806913af9b4111b0633796811765 languageName: node linkType: hard -"@medusajs/locking-postgres@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/locking-postgres@npm:2.7.0" +"@medusajs/locking-postgres@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/locking-postgres@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/69b03c84bafc7c7eb3fca58f5bf5982aa1bc3d50c411e0f006f759ac32a371edefa709137723d0103e6ecd84d1f9b561e9b4acbbe1d3417766d8849c8a0bd48d + "@medusajs/framework": 2.8.2 + checksum: 10c0/3a9d4694e20ef7734f32afe2f991151caad1bb4f3e9f8e86eafe9ba58eca6ef39169795de29f75f4153a4a57bf3d881d9b27df285358daf968f2e668476de00b languageName: node linkType: hard -"@medusajs/locking-redis@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/locking-redis@npm:2.7.0" +"@medusajs/locking-redis@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/locking-redis@npm:2.8.2" dependencies: ioredis: "npm:^5.4.1" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/64a86f2bf09a819687ec9804d6ee9e91d9d8662954f77918f3bf19140522b04af18818903657541c79e7c143468c568e48ec39adb87c1e04a465abc1c265fbf3 + "@medusajs/framework": 2.8.2 + checksum: 10c0/3d8537ebc86f3d7d6c0a38facb0182e119f7fbed0ce9f74cb218a65c778f08716deb68b5c3cff241a720e6c1d711298d63faec11f916779d836d5aa41b3cec92 languageName: node linkType: hard -"@medusajs/locking@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/locking@npm:2.7.0" +"@medusajs/locking@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/locking@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/631f88146be7ec88b7e74da8ab98ec0a938642655777b5c0e367e33eb85fdcce8b9ae9adfd85ba16f72cc430f3fad13e025d95a80609479b785433ed09cd1014 + checksum: 10c0/00702568abce5f106f9ee8a9f5e72596794117ff993b49484ccfba50c31ee73ed227648e88dc8a10236d5baa515fa7880e56a50fbb9d1bbef2d35ce0dc173ba7 languageName: node linkType: hard -"@medusajs/medusa@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/medusa@npm:2.7.0" +"@medusajs/medusa@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/medusa@npm:2.8.2" dependencies: "@inquirer/checkbox": "npm:^2.3.11" "@inquirer/input": "npm:^2.2.9" - "@medusajs/admin-bundler": "npm:2.7.0" - "@medusajs/api-key": "npm:2.7.0" - "@medusajs/auth": "npm:2.7.0" - "@medusajs/auth-emailpass": "npm:2.7.0" - "@medusajs/auth-github": "npm:2.7.0" - "@medusajs/auth-google": "npm:2.7.0" - "@medusajs/cache-inmemory": "npm:2.7.0" - "@medusajs/cache-redis": "npm:2.7.0" - "@medusajs/cart": "npm:2.7.0" - "@medusajs/core-flows": "npm:2.7.0" - "@medusajs/currency": "npm:2.7.0" - "@medusajs/customer": "npm:2.7.0" - "@medusajs/event-bus-local": "npm:2.7.0" - "@medusajs/event-bus-redis": "npm:2.7.0" - "@medusajs/file": "npm:2.7.0" - "@medusajs/file-local": "npm:2.7.0" - "@medusajs/file-s3": "npm:2.7.0" - "@medusajs/fulfillment": "npm:2.7.0" - "@medusajs/fulfillment-manual": "npm:2.7.0" - "@medusajs/index": "npm:2.7.0" - "@medusajs/inventory": "npm:2.7.0" - "@medusajs/link-modules": "npm:2.7.0" - "@medusajs/locking": "npm:2.7.0" - "@medusajs/locking-postgres": "npm:2.7.0" - "@medusajs/locking-redis": "npm:2.7.0" - "@medusajs/notification": "npm:2.7.0" - "@medusajs/notification-local": "npm:2.7.0" - "@medusajs/notification-sendgrid": "npm:2.7.0" - "@medusajs/order": "npm:2.7.0" - "@medusajs/payment": "npm:2.7.0" - "@medusajs/payment-stripe": "npm:2.7.0" - "@medusajs/pricing": "npm:2.7.0" - "@medusajs/product": "npm:2.7.0" - "@medusajs/promotion": "npm:2.7.0" - "@medusajs/region": "npm:2.7.0" - "@medusajs/sales-channel": "npm:2.7.0" - "@medusajs/stock-location": "npm:2.7.0" - "@medusajs/store": "npm:2.7.0" - "@medusajs/tax": "npm:2.7.0" - "@medusajs/telemetry": "npm:2.7.0" - "@medusajs/user": "npm:2.7.0" - "@medusajs/workflow-engine-inmemory": "npm:2.7.0" - "@medusajs/workflow-engine-redis": "npm:2.7.0" + "@medusajs/admin-bundler": "npm:2.8.2" + "@medusajs/api-key": "npm:2.8.2" + "@medusajs/auth": "npm:2.8.2" + "@medusajs/auth-emailpass": "npm:2.8.2" + "@medusajs/auth-github": "npm:2.8.2" + "@medusajs/auth-google": "npm:2.8.2" + "@medusajs/cache-inmemory": "npm:2.8.2" + "@medusajs/cache-redis": "npm:2.8.2" + "@medusajs/cart": "npm:2.8.2" + "@medusajs/core-flows": "npm:2.8.2" + "@medusajs/currency": "npm:2.8.2" + "@medusajs/customer": "npm:2.8.2" + "@medusajs/event-bus-local": "npm:2.8.2" + "@medusajs/event-bus-redis": "npm:2.8.2" + "@medusajs/file": "npm:2.8.2" + "@medusajs/file-local": "npm:2.8.2" + "@medusajs/file-s3": "npm:2.8.2" + "@medusajs/fulfillment": "npm:2.8.2" + "@medusajs/fulfillment-manual": "npm:2.8.2" + "@medusajs/index": "npm:2.8.2" + "@medusajs/inventory": "npm:2.8.2" + "@medusajs/link-modules": "npm:2.8.2" + "@medusajs/locking": "npm:2.8.2" + "@medusajs/locking-postgres": "npm:2.8.2" + "@medusajs/locking-redis": "npm:2.8.2" + "@medusajs/notification": "npm:2.8.2" + "@medusajs/notification-local": "npm:2.8.2" + "@medusajs/notification-sendgrid": "npm:2.8.2" + "@medusajs/order": "npm:2.8.2" + "@medusajs/payment": "npm:2.8.2" + "@medusajs/payment-stripe": "npm:2.8.2" + "@medusajs/pricing": "npm:2.8.2" + "@medusajs/product": "npm:2.8.2" + "@medusajs/promotion": "npm:2.8.2" + "@medusajs/region": "npm:2.8.2" + "@medusajs/sales-channel": "npm:2.8.2" + "@medusajs/stock-location": "npm:2.8.2" + "@medusajs/store": "npm:2.8.2" + "@medusajs/tax": "npm:2.8.2" + "@medusajs/telemetry": "npm:2.8.2" + "@medusajs/user": "npm:2.8.2" + "@medusajs/workflow-engine-inmemory": "npm:2.8.2" + "@medusajs/workflow-engine-redis": "npm:2.8.2" + "@opentelemetry/api": "npm:^1.9.0" boxen: "npm:^5.0.1" chalk: "npm:^4.0.0" chokidar: "npm:^3.4.2" @@ -4123,23 +4185,35 @@ __metadata: uuid: "npm:^9.0.0" zod: "npm:3.22.4" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/knex": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 + "@opentelemetry/instrumentation-pg": ^0.52.0 + "@opentelemetry/resources": ^2.0.0 + "@opentelemetry/sdk-node": ^0.200.0 + "@opentelemetry/sdk-trace-node": ^2.0.0 "@swc/core": 1.5.7 awilix: ^8.0.1 react-dom: ^18.0.0 yalc: 1.0.0-pre.53 peerDependenciesMeta: + "@opentelemetry/instrumentation-pg": + optional: true + "@opentelemetry/resources": + optional: true + "@opentelemetry/sdk-node": + optional: true + "@opentelemetry/sdk-trace-node": + optional: true "@swc/core": optional: true react-dom: optional: true yalc: optional: true - checksum: 10c0/1e2a856749b1fe8a3168621eefadaa733cc3cbd78f836ec16fa0347213855bc67b4a85fb70e04e35180f59e952a674c4ebf6f9469c9a64d9ff98754c5ed93f32 + checksum: 10c0/839751b6a87d6f0e2d180b7c11dacff50f1cb9a6e8180a92e810b4f9c693fa5570d2ee11c4ed784b18a6418f7bf30a4b70fd56866190fd6a98dbe85434448ae3 languageName: node linkType: hard @@ -4162,36 +4236,55 @@ __metadata: languageName: node linkType: hard -"@medusajs/notification-local@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/notification-local@npm:2.7.0" +"@medusajs/modules-sdk@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/modules-sdk@npm:2.8.2" + dependencies: + "@medusajs/orchestration": "npm:2.8.2" + "@medusajs/types": "npm:2.8.2" + "@medusajs/utils": "npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/4f1ec23a97213af4e0f0926c4b403afadb5a82d48a6bdf7f362b3da1fbea530a8a6097e4dd885da4a7184aaf1695724465f4fac621d5a126700a93812279d8d6 + "@mikro-orm/core": 6.4.3 + "@mikro-orm/knex": 6.4.3 + "@mikro-orm/migrations": 6.4.3 + "@mikro-orm/postgresql": 6.4.3 + awilix: ^8.0.1 + express: ^4.21.0 + pg: ^8.13.0 + checksum: 10c0/4e339aa0d2517654a173ffbcb1a394af9cee729832c6469f3c9eef6622fcf7f15a8319f236a43d2d7f61818c41eb0540f9892e9f0ef7cadaf6d0f0979d4f22e6 languageName: node linkType: hard -"@medusajs/notification-sendgrid@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/notification-sendgrid@npm:2.7.0" +"@medusajs/notification-local@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/notification-local@npm:2.8.2" + peerDependencies: + "@medusajs/framework": 2.8.2 + checksum: 10c0/17864f99b0fe774d76796413f58aff9fccd8d680c430aa5d847c7266efef4ed21b12efb3254f3a8918553be25f90b8a3db00621ab2ead99ec8e456fa58b2515f + languageName: node + linkType: hard + +"@medusajs/notification-sendgrid@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/notification-sendgrid@npm:2.8.2" dependencies: "@sendgrid/mail": "npm:^8.1.3" peerDependencies: - "@medusajs/framework": 2.7.0 - checksum: 10c0/af1a4da17c264a9d58270906ad6bbe271da8d448e2fc8175ae43b8ce9b2ec04ea7a90703152e11ff88297ed558ecbe91ef98f6f72b470fbec887e7b37915efc9 + "@medusajs/framework": 2.8.2 + checksum: 10c0/c576debe0a3872cf1d29f357381bf47bd3c710f14713a5a1e00c47dbd5d1092fbf4c45384c126c2ebbc64fe76eebc74ca43c44d9f436aea50e70308d1659ecf3 languageName: node linkType: hard -"@medusajs/notification@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/notification@npm:2.7.0" +"@medusajs/notification@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/notification@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/b7a0316b518959ac9be789715655b04b705a95bf40f457f9fcfb1fe7a39d472e8841a1b949fab5c11b44d8272b9ff1881696e3437bcd4678a017d1bd29e800ef + checksum: 10c0/d765a5796d1fc7ac31e5bf286e0db563dbb0d0969465f1e77f8ffedba9d3d3b1d800ca8c7b0e281c7e1ef9460bb1a1cc9c35a4bdcf72f3382d958856948c14c7 languageName: node linkType: hard @@ -4213,151 +4306,170 @@ __metadata: languageName: node linkType: hard -"@medusajs/order@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/order@npm:2.7.0" +"@medusajs/orchestration@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/orchestration@npm:2.8.2" + dependencies: + "@medusajs/types": "npm:2.8.2" + "@medusajs/utils": "npm:2.8.2" + ulid: "npm:^2.3.0" peerDependencies: - "@medusajs/framework": 2.7.0 "@mikro-orm/core": 6.4.3 + "@mikro-orm/knex": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/86e973e25ff15ba176f9762895e25c338151e437c4b1e92034a1491af447c8a14057a59cd928f154e58a9c8856ad7cf326c75c3f30ac08d0c1f7841c723a4a27 + express: ^4.21.0 + pg: ^8.13.0 + checksum: 10c0/d7394bbc3a69815d6cb9fa2b037d3b153fa1b0294954ca6f0f7f47238cc79bf25bb60b340b40b6942b6232d06b274866b870dbe45e7380dee036439132210838 languageName: node linkType: hard -"@medusajs/payment-stripe@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/payment-stripe@npm:2.7.0" +"@medusajs/order@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/order@npm:2.8.2" + peerDependencies: + "@medusajs/framework": 2.8.2 + "@mikro-orm/core": 6.4.3 + "@mikro-orm/migrations": 6.4.3 + "@mikro-orm/postgresql": 6.4.3 + awilix: ^8.0.1 + checksum: 10c0/dd08b0dd221915142c910177c10502b75565f23cb5e9bd6d9cd8c41f8d5dd9ce48df20093e8e86b302610383265bc8b8a5f9177739af15a4a78389c6ceb5bbaf + languageName: node + linkType: hard + +"@medusajs/payment-stripe@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/payment-stripe@npm:2.8.2" dependencies: stripe: "npm:^15.5.0" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 awilix: ^8.0.1 - checksum: 10c0/e42aa357335f7b0811fda2f36f2fcecddfa1e8101b2c522a51d9986c20df90884c31f755be1dda1fbe2fc497e0af31e5ae219dff16cca5fbd6c21787e03cf206 + checksum: 10c0/c57b9d763236f7821f193eb1ed7561699ee05219977fec9ccdc9738cb3bebf0b9368e707c53c170d30479204784c9c42b23ee86c4a215621725a4e521f1c3f9c languageName: node linkType: hard -"@medusajs/payment@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/payment@npm:2.7.0" +"@medusajs/payment@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/payment@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/7c28d7169937fff77c2bf5b13604d7efe11d836f4fa95137108ef7b8bd19451ce3492976c52b1acf8dc9742d1a16dce5417874a4e01cf758a1104d764b735662 + checksum: 10c0/81a5e201c52c7cf75d255dc9d171531ac67748a99631824bf46eea0d2384f4e4a63cf08209fa1e9c9b960c82e702d28b63e0e4406f4933d2125efe02288a3ce5 languageName: node linkType: hard -"@medusajs/pricing@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/pricing@npm:2.7.0" +"@medusajs/pricing@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/pricing@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/480db8a1c99fc3945253c5394c42ac101dfa1af8ef633b540671ec7f7e274ea24244009b464a6a84c37626da331efcb11d6116abce764e7693c96d41e9f4bbec + checksum: 10c0/1c326bfade90f172564602c3f75d2f6677149d7a9267bb7f4b25c49c8389dca5de78f395b67b22a66a6ebfec73674499c784038977461eb5ce60f86743f704ca languageName: node linkType: hard -"@medusajs/product@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/product@npm:2.7.0" +"@medusajs/product@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/product@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/f4a86bb0c248d7973374fb1463b7f1f8d444a93296820ee129d626c10fedbd65aa0136ba40830d5383d2d5826c53a428cf565418441233a7ffd88fb5da91ba07 + checksum: 10c0/5ff149c37be365aacede740dca7cb48b34683c9cb676b1e44c370effadc175acdc8d7c59e38db2af8c32c9285eb228d5977334b20956c45bcef8755a5008fe72 languageName: node linkType: hard -"@medusajs/promotion@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/promotion@npm:2.7.0" +"@medusajs/promotion@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/promotion@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/19567e9c5fa33e277c0ef58e49f755c2da9d89e1300b190f69aeb4828c50721c7fe2b86a740dd69efd2143306c75d0c519390497a953873526fe41cf2cb9fcb0 + checksum: 10c0/be0cfa9ee76332ed6ac42315a2f00802535c4f264736196a86cbac2b96bf06738f9ef2c81f2494f8dcc81c7c350c35397cbcdad9151d8bbce0a6234ecf693ec9 languageName: node linkType: hard -"@medusajs/region@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/region@npm:2.7.0" +"@medusajs/region@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/region@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/efe26d6c9e25884b249cc58b410952a947480c2ec60d5ef01e2173a9a678a2eeee1b808213745d88d3df81783b79330628e8317bf522dab82bf7b08406913bd1 + checksum: 10c0/24943c4685a3f78bc315358e0e8f35121f31b92a4cce7a0d0b97e13b35d5bbc85befe09adee796559270b388e4667bdb323a7340208aa5d6c5e07217c8095b13 languageName: node linkType: hard -"@medusajs/sales-channel@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/sales-channel@npm:2.7.0" +"@medusajs/sales-channel@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/sales-channel@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/de8e331e3386e4a789f9fe688f0f0234ed7fa287afe38f57f5ee9173786a06f8a92fa126a1af657e5cf4a62a54bfdac8d1e07137b6d49f4501c44aba92b7fa07 + checksum: 10c0/2683daee9ba84b265b02b61c57e77a2b298d56325ece5d10e042ace6c947e154cb785844a24957e154cf7992dc8e0d790211191699dfa2c19c6967e82f749b24 languageName: node linkType: hard -"@medusajs/stock-location@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/stock-location@npm:2.7.0" +"@medusajs/stock-location@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/stock-location@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/10cce73da3bb7c64f54c430ab57f656a67e57479d381e84bc882a6e76b5f5dcc5c506891c1f04b5169a4b5cb478a3f83220c8c4448e75ab1fa40ffe9b2964602 + checksum: 10c0/65112da2e94fed7ec7e9445e9c0b9573a80f0e7b05a9ec9dd05e2006a069b91bd829d2d03bda123e028b576e02201d52d194952b760b0d6b5885a44f49e3f425 languageName: node linkType: hard -"@medusajs/store@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/store@npm:2.7.0" +"@medusajs/store@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/store@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/918d675ff1394e1762c9d5dc90c227fdbcfb676123d00a15a6fa7c37adca20d1dd558d3c5deb99cdb6348c3d98da9c1bd4897816cf1f13369be5b3f9cf9c77e6 + checksum: 10c0/5cea82f6460f86d496808b3eaaf055225e131ec95048f42260d21cffdec6e3cfb3bf9dd597121047e3c0ef2b76e3d5cc96707a4c5745533ac46c8627d6e656b5 languageName: node linkType: hard -"@medusajs/tax@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/tax@npm:2.7.0" +"@medusajs/tax@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/tax@npm:2.8.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/96f353a7fa37551022fa55759e0ae69b8aea8573164cec241ac4f05fffced497f642684b8b89d092df0706c8eaba37adc6f6238175b38e5c968bb8959c933714 + checksum: 10c0/008733f5400f826fd975dbce3d4a943b54249db2cc1187a097aa54e1cdaec41e1540bf234c0185bab079f51eaff92181c6d1243259c22a4d9a42ea954b7a47ba languageName: node linkType: hard -"@medusajs/telemetry@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/telemetry@npm:2.7.0" +"@medusajs/telemetry@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/telemetry@npm:2.8.2" dependencies: "@babel/runtime": "npm:^7.22.10" axios: "npm:^0.21.4" @@ -4369,13 +4481,13 @@ __metadata: is-docker: "npm:^2.2.1" remove-trailing-slash: "npm:^0.1.1" uuid: "npm:^8.3.2" - checksum: 10c0/bafff3eb439f8eb7570658f0d46dc791615b0572358f761a608db6db173df6fef4f843fb52566933b4341620ef152ee4277641cddce426a50792b12651c09bec + checksum: 10c0/463955ec3ea47beeb91d29e233ad5dc48a4bd634cb5881bc3dab662719504984c4c0014de0063592a395d0da96cdef32b2381033ae68aa9402e73b9e99df8b6f languageName: node linkType: hard -"@medusajs/test-utils@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/test-utils@npm:2.7.0" +"@medusajs/test-utils@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/test-utils@npm:2.8.2" dependencies: "@types/express": "npm:^4.17.17" axios: "npm:^0.21.4" @@ -4383,20 +4495,20 @@ __metadata: get-port: "npm:^5.1.0" randomatic: "npm:^3.1.1" peerDependencies: - "@medusajs/framework": 2.7.0 - "@medusajs/medusa": 2.7.0 + "@medusajs/framework": 2.8.2 + "@medusajs/medusa": 2.8.2 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 peerDependenciesMeta: "@medusajs/medusa": optional: true - checksum: 10c0/3efbc17f3e589a9d2474a2e4802cbafc85b4d2036a88b512506d51af133e8b13f69393d206df18fec6636bf2c8cefe74e3c0d1f9cb5f66991ac078252e24b663 + checksum: 10c0/79335c1d5cae8e70534366fe6a792f6670dc0a3631b0d57e9348e7a85759382a3f9a8e765d63547ed76abfe3ba12e4c8244ffee694d58128acdfd805fd62b8f3 languageName: node linkType: hard -"@medusajs/types@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/types@npm:2.7.0" +"@medusajs/types@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/types@npm:2.8.2" dependencies: bignumber.js: "npm:^9.1.2" peerDependencies: @@ -4408,15 +4520,15 @@ __metadata: optional: true vite: optional: true - checksum: 10c0/4a7d1bd00eed033bbfcbe21b36b15ae4341ac6e9bd06a28163aeeda5b5e0b0c12ba48f48a89232fa57d4e31859fc5313d620c2db67460d4c608e9b5cbd966d34 + checksum: 10c0/dc554e2bd4dd292916ee8ce308879c6948fe0d1281cbb8b22fecc83091451eb08e5aa60829ed2c8bbbac2f6b9b8fd98d4bf394d9b9eb00330854314acf2c045f languageName: node linkType: hard -"@medusajs/ui@npm:4.0.8": - version: 4.0.8 - resolution: "@medusajs/ui@npm:4.0.8" +"@medusajs/ui@npm:4.0.12": + version: 4.0.12 + resolution: "@medusajs/ui@npm:4.0.12" dependencies: - "@medusajs/icons": "npm:2.7.0" + "@medusajs/icons": "npm:2.8.2" "@tanstack/react-table": "npm:8.20.5" clsx: "npm:^1.2.1" copy-to-clipboard: "npm:^3.3.3" @@ -4432,22 +4544,22 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - checksum: 10c0/063a5416a1060f7930daf2f7cf7456ca3ee042a83979a9d146ca2d29bf833d9b1e712f4a7077b21cc49fb6415dd55b1b5995a15cd16c50aa6e36aba1dcb314a9 + checksum: 10c0/e84bc75af328d6fb03e32ed403cc124021d420f7c0c5e999f3dcfa6783b9dbcee4532f055c1d38f78bcfa26e8da2d174c98ac921103ee2c47e9160816534ac07 languageName: node linkType: hard -"@medusajs/user@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/user@npm:2.7.0" +"@medusajs/user@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/user@npm:2.8.2" dependencies: jsonwebtoken: "npm:^9.0.2" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/1cd0fbb498287c0992fddaa162705cb80dc9907bce12679a64f3cfb33c8884f840aebd62108c511dad3110d28defbd6688070dfbecceb267ea2e4b11813a0f8b + checksum: 10c0/71703c11765250f3da5644ed48ab01180289935a84d950f6204b22cac5c5ac1e171132e21c5d595ef5532deb23bb4e0a69968910c25c3d4c82aeccc15d5c716a languageName: node linkType: hard @@ -4481,40 +4593,92 @@ __metadata: languageName: node linkType: hard -"@medusajs/workflow-engine-inmemory@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/workflow-engine-inmemory@npm:2.7.0" +"@medusajs/utils@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/utils@npm:2.8.2" + dependencies: + "@graphql-codegen/core": "npm:^4.0.2" + "@graphql-codegen/typescript": "npm:^4.0.9" + "@graphql-tools/merge": "npm:^9.0.7" + "@graphql-tools/schema": "npm:^10.0.6" + "@medusajs/types": "npm:2.8.2" + "@types/pluralize": "npm:^0.0.33" + bignumber.js: "npm:^9.1.2" + dotenv: "npm:^16.4.5" + dotenv-expand: "npm:^11.0.6" + graphql: "npm:^16.9.0" + jsonwebtoken: "npm:^9.0.2" + pg-connection-string: "npm:^2.7.0" + pluralize: "npm:^8.0.0" + ulid: "npm:^2.3.0" + peerDependencies: + "@mikro-orm/core": 6.4.3 + "@mikro-orm/knex": 6.4.3 + "@mikro-orm/migrations": 6.4.3 + "@mikro-orm/postgresql": 6.4.3 + awilix: ^8.0.1 + express: ^4.21.0 + pg: ^8.13.0 + checksum: 10c0/3b7139245591562ee913e5214405a5782bc8ba52b7b2b6a16fe185488bef70357ff340a66ca19be1316c4cd6e4322931b4c80b7e5fd10fc56648987a96b40579 + languageName: node + linkType: hard + +"@medusajs/workflow-engine-inmemory@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/workflow-engine-inmemory@npm:2.8.2" dependencies: cron-parser: "npm:^4.9.0" ulid: "npm:^2.3.0" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/7816edd8dae81a81a4a45c74faa3da767b147feb3a4081fc132545ae808b19b8197a3f1f7454a5cba3404a60ea9df90d559ec8eb97b775104da1e10399366a66 + checksum: 10c0/ebb74b835ac9cf6140a8a04b81595e39981971e398bab7aec3763907084a6ebdb6eecfca299ca6bc63695c3987ae50e1833b3b6e5641e36deace4daaa9635f86 languageName: node linkType: hard -"@medusajs/workflow-engine-redis@npm:2.7.0": - version: 2.7.0 - resolution: "@medusajs/workflow-engine-redis@npm:2.7.0" +"@medusajs/workflow-engine-redis@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/workflow-engine-redis@npm:2.8.2" dependencies: bullmq: "npm:5.13.0" ioredis: "npm:^5.4.1" ulid: "npm:^2.3.0" peerDependencies: - "@medusajs/framework": 2.7.0 + "@medusajs/framework": 2.8.2 "@mikro-orm/core": 6.4.3 "@mikro-orm/migrations": 6.4.3 "@mikro-orm/postgresql": 6.4.3 awilix: ^8.0.1 - checksum: 10c0/385d1135ffea8a9ada957b4a742123d664f90cb049971c4954bd9c50ba86fbf1b7eb86d5538ec47d1cb39509f84360240f23f76c61007d0b6dc131f09c42df37 + checksum: 10c0/064f1dacad99b1dedd118255ac4f73b121297f0d727ecb4bf0616d1f3c5e66c68d9272562f3b9cdc2fb1c82c92702a7f2d97621d2a10de897e3aa6add695679e languageName: node linkType: hard -"@medusajs/workflows-sdk@npm:2.7.0, @medusajs/workflows-sdk@npm:^2.7.0": +"@medusajs/workflows-sdk@npm:2.8.2": + version: 2.8.2 + resolution: "@medusajs/workflows-sdk@npm:2.8.2" + dependencies: + "@medusajs/modules-sdk": "npm:2.8.2" + "@medusajs/orchestration": "npm:2.8.2" + "@medusajs/types": "npm:2.8.2" + "@medusajs/utils": "npm:2.8.2" + ulid: "npm:^2.3.0" + peerDependencies: + "@mikro-orm/core": 6.4.3 + "@mikro-orm/knex": 6.4.3 + "@mikro-orm/migrations": 6.4.3 + "@mikro-orm/postgresql": 6.4.3 + awilix: ^8.0.1 + express: ^4.21.0 + pg: ^8.13.0 + zod: 3.22.4 + checksum: 10c0/190e75a327f87609fc1da07d34069c2042c79b470d3dd85ad68725fa9f44269ff51c510dee9bc9ee5ff0e7634ff6e436cb7f350757da3eb6c6fa33cab8874639 + languageName: node + linkType: hard + +"@medusajs/workflows-sdk@npm:^2.7.0": version: 2.7.0 resolution: "@medusajs/workflows-sdk@npm:2.7.0" dependencies: @@ -10074,6 +10238,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm-eabi@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.38.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@rollup/rollup-android-arm-eabi@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-android-arm-eabi@npm:4.40.1" @@ -10088,6 +10259,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-android-arm64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-android-arm64@npm:4.38.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-android-arm64@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-android-arm64@npm:4.40.1" @@ -10102,6 +10280,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-darwin-arm64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.38.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-darwin-arm64@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-darwin-arm64@npm:4.40.1" @@ -10116,6 +10301,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-darwin-x64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.38.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@rollup/rollup-darwin-x64@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-darwin-x64@npm:4.40.1" @@ -10130,6 +10322,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-freebsd-arm64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.38.0" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-freebsd-arm64@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-freebsd-arm64@npm:4.40.1" @@ -10144,6 +10343,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-freebsd-x64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.38.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@rollup/rollup-freebsd-x64@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-freebsd-x64@npm:4.40.1" @@ -10158,6 +10364,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm-gnueabihf@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.38.0" + conditions: os=linux & cpu=arm & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-arm-gnueabihf@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.40.1" @@ -10172,6 +10385,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm-musleabihf@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.38.0" + conditions: os=linux & cpu=arm & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-linux-arm-musleabihf@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.40.1" @@ -10186,6 +10406,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.38.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-arm64-gnu@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.40.1" @@ -10200,6 +10427,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-arm64-musl@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.38.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-linux-arm64-musl@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-arm64-musl@npm:4.40.1" @@ -10214,6 +10448,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-loongarch64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.38.0" + conditions: os=linux & cpu=loong64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-loongarch64-gnu@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.40.1" @@ -10228,6 +10469,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.38.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.1" @@ -10242,6 +10490,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-riscv64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.38.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-riscv64-gnu@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.40.1" @@ -10249,6 +10504,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-riscv64-musl@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.38.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-linux-riscv64-musl@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.40.1" @@ -10263,6 +10525,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-s390x-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.38.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-s390x-gnu@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.40.1" @@ -10277,6 +10546,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-x64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.38.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@rollup/rollup-linux-x64-gnu@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-x64-gnu@npm:4.40.1" @@ -10291,6 +10567,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-linux-x64-musl@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.38.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@rollup/rollup-linux-x64-musl@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-linux-x64-musl@npm:4.40.1" @@ -10305,6 +10588,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-arm64-msvc@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.38.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@rollup/rollup-win32-arm64-msvc@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.40.1" @@ -10319,6 +10609,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-ia32-msvc@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.38.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@rollup/rollup-win32-ia32-msvc@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.40.1" @@ -10333,6 +10630,13 @@ __metadata: languageName: node linkType: hard +"@rollup/rollup-win32-x64-msvc@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.38.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@rollup/rollup-win32-x64-msvc@npm:4.40.1": version: 4.40.1 resolution: "@rollup/rollup-win32-x64-msvc@npm:4.40.1" @@ -10766,19 +11070,19 @@ __metadata: languageName: node linkType: hard -"@smithy/core@npm:^3.1.4": - version: 3.1.4 - resolution: "@smithy/core@npm:3.1.4" +"@smithy/core@npm:^3.1.4, @smithy/core@npm:^3.1.5": + version: 3.1.5 + resolution: "@smithy/core@npm:3.1.5" dependencies: "@smithy/middleware-serde": "npm:^4.0.2" "@smithy/protocol-http": "npm:^5.0.1" "@smithy/types": "npm:^4.1.0" "@smithy/util-body-length-browser": "npm:^4.0.0" "@smithy/util-middleware": "npm:^4.0.1" - "@smithy/util-stream": "npm:^4.1.1" + "@smithy/util-stream": "npm:^4.1.2" "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/8c91573fe679eecc160440b66895bb22e1549a320c86066d01ec63aa9bf756e16bb0135e0d48b039b1ccd0f8f6b580d20242d784236b6c5ca566e1cb6bf0901a + checksum: 10c0/3f705fd7cc4eb4fc8c9cc1a9466012f3f08ec7427528fd51d32353e7adb964bd59426adf188e9a933ee9d1e5fa57cefc1917da2ccee1737edb0eb9fe460e90a9 languageName: node linkType: hard @@ -10948,11 +11252,11 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-endpoint@npm:^4.0.5": - version: 4.0.5 - resolution: "@smithy/middleware-endpoint@npm:4.0.5" +"@smithy/middleware-endpoint@npm:^4.0.5, @smithy/middleware-endpoint@npm:^4.0.6": + version: 4.0.6 + resolution: "@smithy/middleware-endpoint@npm:4.0.6" dependencies: - "@smithy/core": "npm:^3.1.4" + "@smithy/core": "npm:^3.1.5" "@smithy/middleware-serde": "npm:^4.0.2" "@smithy/node-config-provider": "npm:^4.0.1" "@smithy/shared-ini-file-loader": "npm:^4.0.1" @@ -10960,7 +11264,7 @@ __metadata: "@smithy/url-parser": "npm:^4.0.1" "@smithy/util-middleware": "npm:^4.0.1" tslib: "npm:^2.6.2" - checksum: 10c0/4573b7fb9525c3b887050183dc0c31bb6fd2801c98a8e94984474634e940a5efd73bbfc49c50d90245089112519bfcdbd8b5c2f279b2f4e64bd8df2203d5221c + checksum: 10c0/0745d4eb28a1d0419e1f6efe9b726b5ff1389c2e9fcde407e0739a262b66b0e0eb130fe7e80e99e95e3c7472af4d597a592ec8be751f2184ca6947e77e31d0ea languageName: node linkType: hard @@ -11013,16 +11317,16 @@ __metadata: languageName: node linkType: hard -"@smithy/node-http-handler@npm:^4.0.2": - version: 4.0.2 - resolution: "@smithy/node-http-handler@npm:4.0.2" +"@smithy/node-http-handler@npm:^4.0.2, @smithy/node-http-handler@npm:^4.0.3": + version: 4.0.3 + resolution: "@smithy/node-http-handler@npm:4.0.3" dependencies: "@smithy/abort-controller": "npm:^4.0.1" "@smithy/protocol-http": "npm:^5.0.1" "@smithy/querystring-builder": "npm:^4.0.1" "@smithy/types": "npm:^4.1.0" tslib: "npm:^2.6.2" - checksum: 10c0/6a3446dcf3bf006cf55b065edfbe7636f2aa13073f2937e224890902de44b191a5214dce4cb61e98b1ad53889bdbb35386e8810a338bc75ea3743f8d4550a2ad + checksum: 10c0/03e0e40725ac8884dc1715288bdbe6f05e8073c623c7d4eb4d6859e6ffdee1c831e407b1d286860580d7cb341d5ec41274e8888f2aeac6f865c0890ac4e9403c languageName: node linkType: hard @@ -11103,17 +11407,17 @@ __metadata: linkType: hard "@smithy/smithy-client@npm:^4.1.5": - version: 4.1.5 - resolution: "@smithy/smithy-client@npm:4.1.5" + version: 4.1.6 + resolution: "@smithy/smithy-client@npm:4.1.6" dependencies: - "@smithy/core": "npm:^3.1.4" - "@smithy/middleware-endpoint": "npm:^4.0.5" + "@smithy/core": "npm:^3.1.5" + "@smithy/middleware-endpoint": "npm:^4.0.6" "@smithy/middleware-stack": "npm:^4.0.1" "@smithy/protocol-http": "npm:^5.0.1" "@smithy/types": "npm:^4.1.0" - "@smithy/util-stream": "npm:^4.1.1" + "@smithy/util-stream": "npm:^4.1.2" tslib: "npm:^2.6.2" - checksum: 10c0/7dbb54f2cff8d502ac93b03181e78ca051f1f6028df0643805f3aceefb4bbe492e4a7e4496933a8bfc146eb65879554bf9a17d083351ff2e9302d0494b67fa28 + checksum: 10c0/d3989f9af17e35e01ef09d3db52136548e9fa0433ec35ee4f192cd618e93a4a0472d79288655763142c7832d643ee3f0ecf6b84ea520bb07aa319615a2ed9629 languageName: node linkType: hard @@ -11264,19 +11568,19 @@ __metadata: languageName: node linkType: hard -"@smithy/util-stream@npm:^4.1.1": - version: 4.1.1 - resolution: "@smithy/util-stream@npm:4.1.1" +"@smithy/util-stream@npm:^4.1.1, @smithy/util-stream@npm:^4.1.2": + version: 4.1.2 + resolution: "@smithy/util-stream@npm:4.1.2" dependencies: "@smithy/fetch-http-handler": "npm:^5.0.1" - "@smithy/node-http-handler": "npm:^4.0.2" + "@smithy/node-http-handler": "npm:^4.0.3" "@smithy/types": "npm:^4.1.0" "@smithy/util-base64": "npm:^4.0.0" "@smithy/util-buffer-from": "npm:^4.0.0" "@smithy/util-hex-encoding": "npm:^4.0.0" "@smithy/util-utf8": "npm:^4.0.0" tslib: "npm:^2.6.2" - checksum: 10c0/9088e4e9baeac8af4de3bc8694cc57d49b3c9ef45c6441cc572b3d14fb88e0929624070d1528c3afe27ab710a2e0eb4a7c2938d676795b78788ab135b2f66e32 + checksum: 10c0/639328ec53d44f703b1e3cb9363397f6b506626584b22c68897133831b25026359f99f2b89c6d6c597e72773ff3508a374ae13cc266f1d1f761bcfbe9e4318d5 languageName: node linkType: hard @@ -13078,7 +13382,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:*, @types/express@npm:^5.0.0": +"@types/express@npm:*": version: 5.0.0 resolution: "@types/express@npm:5.0.0" dependencies: @@ -13102,6 +13406,17 @@ __metadata: languageName: node linkType: hard +"@types/express@npm:^5.0.0": + version: 5.0.1 + resolution: "@types/express@npm:5.0.1" + dependencies: + "@types/body-parser": "npm:*" + "@types/express-serve-static-core": "npm:^5.0.0" + "@types/serve-static": "npm:*" + checksum: 10c0/e1385028c7251360ce916aab0e304187b613ca18cb9aa3fa90794a337e5b2e0c76330d467f41d3b3e936ce5336c4f3e63e323dc01192cf20f9686905daa6d00a + languageName: node + linkType: hard + "@types/glob@npm:*": version: 8.1.0 resolution: "@types/glob@npm:8.1.0" @@ -13817,6 +14132,15 @@ __metadata: languageName: node linkType: hard +"@whatwg-node/promise-helpers@npm:^1.0.0": + version: 1.2.1 + resolution: "@whatwg-node/promise-helpers@npm:1.2.1" + dependencies: + tslib: "npm:^2.6.3" + checksum: 10c0/fe0e14fc8dd987bbb3b90db9191887783140e0753dc322cfb245070da378b295bd12d3b45bddfe26f537022dbb43026051090a42fe4e15e523c9b9e785b177b4 + languageName: node + linkType: hard + "abab@npm:^2.0.6": version: 2.0.6 resolution: "abab@npm:2.0.6" @@ -14772,6 +15096,17 @@ __metadata: languageName: node linkType: hard +"bundle-require@npm:^5.1.0": + version: 5.1.0 + resolution: "bundle-require@npm:5.1.0" + dependencies: + load-tsconfig: "npm:^0.2.3" + peerDependencies: + esbuild: ">=0.18" + checksum: 10c0/8bff9df68eb686f05af952003c78e70ffed2817968f92aebb2af620cc0b7428c8154df761d28f1b38508532204278950624ef86ce63644013dc57660a9d1810f + languageName: node + linkType: hard + "busboy@npm:^1.0.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" @@ -15067,7 +15402,7 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^4.0.0": +"chokidar@npm:^4.0.0, chokidar@npm:^4.0.3": version: 4.0.3 resolution: "chokidar@npm:4.0.3" dependencies: @@ -15566,6 +15901,13 @@ __metadata: languageName: node linkType: hard +"consola@npm:^3.4.0": + version: 3.4.2 + resolution: "consola@npm:3.4.2" + checksum: 10c0/7cebe57ecf646ba74b300bcce23bff43034ed6fbec9f7e39c27cee1dc00df8a21cd336b466ad32e304ea70fba04ec9e890c200270de9a526ce021ba8a7e4c11a + languageName: node + linkType: hard + "constant-case@npm:^3.0.4": version: 3.0.4 resolution: "constant-case@npm:3.0.4" @@ -17702,6 +18044,18 @@ __metadata: languageName: node linkType: hard +"fdir@npm:^6.4.3": + version: 6.4.3 + resolution: "fdir@npm:6.4.3" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/d13c10120e9625adf21d8d80481586200759928c19405a816b77dd28eaeb80e7c59c5def3e2941508045eb06d34eb47fad865ccc8bf98e6ab988bb0ed160fb6f + languageName: node + linkType: hard + "fdir@npm:^6.4.4": version: 6.4.4 resolution: "fdir@npm:6.4.4" @@ -18255,6 +18609,22 @@ __metadata: languageName: node linkType: hard +"glob@npm:^11.0.0": + version: 11.0.1 + resolution: "glob@npm:11.0.1" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^4.0.1" + minimatch: "npm:^10.0.0" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^2.0.0" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/2b32588be52e9e90f914c7d8dec32f3144b81b84054b0f70e9adfebf37cd7014570489f2a79d21f7801b9a4bd4cca94f426966bfd00fb64a5b705cfe10da3a03 + languageName: node + linkType: hard + "glob@npm:^8.0.0": version: 8.1.0 resolution: "glob@npm:8.1.0" @@ -19525,6 +19895,15 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^4.0.1": + version: 4.1.0 + resolution: "jackspeak@npm:4.1.0" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + checksum: 10c0/08a6a24a366c90b83aef3ad6ec41dcaaa65428ffab8d80bc7172add0fbb8b134a34f415ad288b2a6fbd406526e9a62abdb40ed4f399fbe00cb45c44056d4dce0 + languageName: node + linkType: hard + "javascript-stringify@npm:^2.0.1": version: 2.1.0 resolution: "javascript-stringify@npm:2.1.0" @@ -20435,6 +20814,13 @@ __metadata: languageName: node linkType: hard +"joycon@npm:^3.1.1": + version: 3.1.1 + resolution: "joycon@npm:3.1.1" + checksum: 10c0/131fb1e98c9065d067fd49b6e685487ac4ad4d254191d7aa2c9e3b90f4e9ca70430c43cad001602bdbdabcf58717d3b5c5b7461c1bd8e39478c8de706b3fe6ae + languageName: node + linkType: hard + "js-base64@npm:^3.7.2": version: 3.7.7 resolution: "js-base64@npm:3.7.7" @@ -20919,7 +21305,7 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:^3.0.0, lilconfig@npm:^3.1.3": +"lilconfig@npm:^3.0.0, lilconfig@npm:^3.1.1, lilconfig@npm:^3.1.3": version: 3.1.3 resolution: "lilconfig@npm:3.1.3" checksum: 10c0/f5604e7240c5c275743561442fbc5abf2a84ad94da0f5adc71d25e31fa8483048de3dcedcb7a44112a942fed305fd75841cdf6c9681c7f640c63f1049e9a5dcc @@ -20949,6 +21335,13 @@ __metadata: languageName: node linkType: hard +"load-tsconfig@npm:^0.2.3": + version: 0.2.5 + resolution: "load-tsconfig@npm:0.2.5" + checksum: 10c0/bf2823dd26389d3497b6567f07435c5a7a58d9df82e879b0b3892f87d8db26900f84c85bc329ef41c0540c0d6a448d1c23ddc64a80f3ff6838b940f3915a3fcb + languageName: node + linkType: hard + "locate-path@npm:^5.0.0": version: 5.0.0 resolution: "locate-path@npm:5.0.0" @@ -21079,6 +21472,13 @@ __metadata: languageName: node linkType: hard +"lodash.sortby@npm:^4.7.0": + version: 4.7.0 + resolution: "lodash.sortby@npm:4.7.0" + checksum: 10c0/fc48fb54ff7669f33bb32997cab9460757ee99fafaf72400b261c3e10fde21538e47d8cfcbe6a25a31bcb5b7b727c27d52626386fc2de24eb059a6d64a89cdf5 + languageName: node + linkType: hard + "lodash@npm:4.17.21, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:~4.17.0": version: 4.17.21 resolution: "lodash@npm:4.17.21" @@ -21167,6 +21567,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^11.0.0": + version: 11.1.0 + resolution: "lru-cache@npm:11.1.0" + checksum: 10c0/85c312f7113f65fae6a62de7985348649937eb34fb3d212811acbf6704dc322a421788aca253b62838f1f07049a84cc513d88f494e373d3756514ad263670a64 + languageName: node + linkType: hard + "lru-cache@npm:^4.0.1": version: 4.1.5 resolution: "lru-cache@npm:4.1.5" @@ -21390,13 +21797,13 @@ __metadata: resolution: "medusa@workspace:apps/medusa" dependencies: "@lambdacurry/medusa-product-reviews": "npm:1.2.0" - "@medusajs/admin-sdk": "npm:2.7.0" - "@medusajs/cli": "npm:2.7.0" - "@medusajs/framework": "npm:2.7.0" - "@medusajs/js-sdk": "npm:2.7.0" - "@medusajs/medusa": "npm:2.7.0" - "@medusajs/test-utils": "npm:2.7.0" - "@medusajs/types": "npm:2.7.0" + "@medusajs/admin-sdk": "npm:2.8.2" + "@medusajs/cli": "npm:2.8.2" + "@medusajs/framework": "npm:2.8.2" + "@medusajs/js-sdk": "npm:2.8.2" + "@medusajs/medusa": "npm:2.8.2" + "@medusajs/test-utils": "npm:2.8.2" + "@medusajs/types": "npm:2.8.2" "@mikro-orm/cli": "npm:6.4.3" "@mikro-orm/core": "npm:6.4.3" "@mikro-orm/knex": "npm:6.4.3" @@ -21559,6 +21966,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^10.0.0": + version: 10.0.1 + resolution: "minimatch@npm:10.0.1" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/e6c29a81fe83e1877ad51348306be2e8aeca18c88fdee7a99df44322314279e15799e41d7cb274e4e8bb0b451a3bc622d6182e157dfa1717d6cda75e9cd8cd5d + languageName: node + linkType: hard + "minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -22713,6 +23129,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^2.0.0": + version: 2.0.0 + resolution: "path-scurry@npm:2.0.0" + dependencies: + lru-cache: "npm:^11.0.0" + minipass: "npm:^7.1.2" + checksum: 10c0/3da4adedaa8e7ef8d6dc4f35a0ff8f05a9b4d8365f2b28047752b62d4c1ad73eec21e37b1579ef2d075920157856a3b52ae8309c480a6f1a8bbe06ff8e52b33c + languageName: node + linkType: hard + "path-to-regexp@npm:0.1.12, path-to-regexp@npm:^0.1.10": version: 0.1.12 resolution: "path-to-regexp@npm:0.1.12" @@ -23014,6 +23440,29 @@ __metadata: languageName: node linkType: hard +"postcss-load-config@npm:^6.0.1": + version: 6.0.1 + resolution: "postcss-load-config@npm:6.0.1" + dependencies: + lilconfig: "npm:^3.1.1" + peerDependencies: + jiti: ">=1.21.0" + postcss: ">=8.0.9" + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + checksum: 10c0/74173a58816dac84e44853f7afbd283f4ef13ca0b6baeba27701214beec33f9e309b128f8102e2b173e8d45ecba45d279a9be94b46bf48d219626aa9b5730848 + languageName: node + linkType: hard + "postcss-nested@npm:^6.0.1, postcss-nested@npm:^6.2.0": version: 6.2.0 resolution: "postcss-nested@npm:6.2.0" @@ -24611,6 +25060,18 @@ __metadata: languageName: node linkType: hard +"rimraf@npm:^6.0.1": + version: 6.0.1 + resolution: "rimraf@npm:6.0.1" + dependencies: + glob: "npm:^11.0.0" + package-json-from-dist: "npm:^1.0.0" + bin: + rimraf: dist/esm/bin.mjs + checksum: 10c0/b30b6b072771f0d1e73b4ca5f37bb2944ee09375be9db5f558fcd3310000d29dfcfa93cf7734d75295ad5a7486dc8e40f63089ced1722a664539ffc0c3ece8c6 + languageName: node + linkType: hard + "rollup@npm:^4.20.0": version: 4.34.8 resolution: "rollup@npm:4.34.8" @@ -24683,6 +25144,81 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^4.34.8": + version: 4.38.0 + resolution: "rollup@npm:4.38.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.38.0" + "@rollup/rollup-android-arm64": "npm:4.38.0" + "@rollup/rollup-darwin-arm64": "npm:4.38.0" + "@rollup/rollup-darwin-x64": "npm:4.38.0" + "@rollup/rollup-freebsd-arm64": "npm:4.38.0" + "@rollup/rollup-freebsd-x64": "npm:4.38.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.38.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.38.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.38.0" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.38.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.38.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.38.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-x64-musl": "npm:4.38.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.38.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.38.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.38.0" + "@types/estree": "npm:1.0.7" + fsevents: "npm:~2.3.2" + dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-freebsd-arm64": + optional: true + "@rollup/rollup-freebsd-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm-musleabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-loongarch64-gnu": + optional: true + "@rollup/rollup-linux-powerpc64le-gnu": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true + "@rollup/rollup-linux-s390x-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/931a6d3bf34fa13adec44a8660319bb7b2f61fbabbf2030f4d29df991fb37b6a685cd7dc203fde8d4ab8b4fe783f1fe8814e448a97f651dc4727511faf958cb4 + languageName: node + linkType: hard + "rollup@npm:^4.34.9": version: 4.40.1 resolution: "rollup@npm:4.40.1" @@ -25363,6 +25899,15 @@ __metadata: languageName: node linkType: hard +"source-map@npm:0.8.0-beta.0": + version: 0.8.0-beta.0 + resolution: "source-map@npm:0.8.0-beta.0" + dependencies: + whatwg-url: "npm:^7.0.0" + checksum: 10c0/fb4d9bde9a9fdb2c29b10e5eae6c71d10e09ef467e1afb75fdec2eb7e11fa5b343a2af553f74f18b695dbc0b81f9da2e9fa3d7a317d5985e9939499ec6087835 + languageName: node + linkType: hard + "source-map@npm:^0.5.7": version: 0.5.7 resolution: "source-map@npm:0.5.7" @@ -25522,8 +26067,8 @@ __metadata: "@lambdacurry/forms": "npm:^0.15.0" "@lambdacurry/medusa-plugins-sdk": "npm:0.0.5" "@loadable/component": "npm:^5.15.3" - "@medusajs/js-sdk": "npm:2.7.0" - "@medusajs/types": "npm:2.7.0" + "@medusajs/js-sdk": "npm:2.8.2" + "@medusajs/types": "npm:2.8.2" "@mjackson/file-storage": "npm:^0.6.1" "@mjackson/form-data-parser": "npm:^0.7.0" "@radix-ui/react-slot": "npm:^1.0.2" @@ -26151,6 +26696,23 @@ __metadata: languageName: node linkType: hard +"tinyexec@npm:^0.3.2": + version: 0.3.2 + resolution: "tinyexec@npm:0.3.2" + checksum: 10c0/3efbf791a911be0bf0821eab37a3445c2ba07acc1522b1fa84ae1e55f10425076f1290f680286345ed919549ad67527d07281f1c19d584df3b74326909eb1f90 + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.11": + version: 0.2.12 + resolution: "tinyglobby@npm:0.2.12" + dependencies: + fdir: "npm:^6.4.3" + picomatch: "npm:^4.0.2" + checksum: 10c0/7c9be4fd3625630e262dcb19015302aad3b4ba7fc620f269313e688f2161ea8724d6cb4444baab5ef2826eb6bed72647b169a33ec8eea37501832a2526ff540f + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.13": version: 0.2.13 resolution: "tinyglobby@npm:0.2.13" @@ -26252,6 +26814,15 @@ __metadata: languageName: node linkType: hard +"tr46@npm:^1.0.1": + version: 1.0.1 + resolution: "tr46@npm:1.0.1" + dependencies: + punycode: "npm:^2.1.0" + checksum: 10c0/41525c2ccce86e3ef30af6fa5e1464e6d8bb4286a58ea8db09228f598889581ef62347153f6636cd41553dc41685bdfad0a9d032ef58df9fbb0792b3447d0f04 + languageName: node + linkType: hard + "tr46@npm:^3.0.0": version: 3.0.0 resolution: "tr46@npm:3.0.0" @@ -26467,6 +27038,47 @@ __metadata: languageName: node linkType: hard +"tsup@npm:^8.0.2": + version: 8.4.0 + resolution: "tsup@npm:8.4.0" + dependencies: + bundle-require: "npm:^5.1.0" + cac: "npm:^6.7.14" + chokidar: "npm:^4.0.3" + consola: "npm:^3.4.0" + debug: "npm:^4.4.0" + esbuild: "npm:^0.25.0" + joycon: "npm:^3.1.1" + picocolors: "npm:^1.1.1" + postcss-load-config: "npm:^6.0.1" + resolve-from: "npm:^5.0.0" + rollup: "npm:^4.34.8" + source-map: "npm:0.8.0-beta.0" + sucrase: "npm:^3.35.0" + tinyexec: "npm:^0.3.2" + tinyglobby: "npm:^0.2.11" + tree-kill: "npm:^1.2.2" + peerDependencies: + "@microsoft/api-extractor": ^7.36.0 + "@swc/core": ^1 + postcss: ^8.4.12 + typescript: ">=4.5.0" + peerDependenciesMeta: + "@microsoft/api-extractor": + optional: true + "@swc/core": + optional: true + postcss: + optional: true + typescript: + optional: true + bin: + tsup: dist/cli-default.js + tsup-node: dist/cli-node.js + checksum: 10c0/c6636ffd6ade59d3544cd424c7115449f8712eb5c872e1e36d25817436f9ea9424d8ee8f1b6244ac7c9a887b0fcf6cc42c102baa55a9080236afc18ba73871e6 + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -26688,7 +27300,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.6.2, typescript@npm:^5.7.3": +"typescript@npm:5.7.3, typescript@npm:^5.6.2, typescript@npm:^5.7.3": version: 5.7.3 resolution: "typescript@npm:5.7.3" bin: @@ -26698,7 +27310,17 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.6.2#optional!builtin, typescript@patch:typescript@npm%3A^5.7.3#optional!builtin": +"typescript@npm:^5.7.2": + version: 5.8.2 + resolution: "typescript@npm:5.8.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/5c4f6fbf1c6389b6928fe7b8fcd5dc73bb2d58cd4e3883f1d774ed5bd83b151cbac6b7ecf11723de56d4676daeba8713894b1e9af56174f2f9780ae7848ec3c6 + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A5.7.3#optional!builtin, typescript@patch:typescript@npm%3A^5.6.2#optional!builtin, typescript@patch:typescript@npm%3A^5.7.3#optional!builtin": version: 5.7.3 resolution: "typescript@patch:typescript@npm%3A5.7.3#optional!builtin::version=5.7.3&hash=8c6c40" bin: @@ -26708,6 +27330,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A^5.7.2#optional!builtin": + version: 5.8.2 + resolution: "typescript@patch:typescript@npm%3A5.8.2#optional!builtin::version=5.8.2&hash=8c6c40" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/8a6cd29dfb59bd5a978407b93ae0edb530ee9376a5b95a42ad057a6f80ffb0c410489ccd6fe48d1d0dfad6e8adf5d62d3874bbd251f488ae30e11a1ce6dabd28 + languageName: node + linkType: hard + "ua-parser-js@npm:^1.0.35": version: 1.0.40 resolution: "ua-parser-js@npm:1.0.40" @@ -27307,6 +27939,13 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^4.0.2": + version: 4.0.2 + resolution: "webidl-conversions@npm:4.0.2" + checksum: 10c0/def5c5ac3479286dffcb604547628b2e6b46c5c5b8a8cfaa8c71dc3bafc85859bde5fbe89467ff861f571ab38987cf6ab3d6e7c80b39b999e50e803c12f3164f + languageName: node + linkType: hard + "webidl-conversions@npm:^7.0.0": version: 7.0.0 resolution: "webidl-conversions@npm:7.0.0" @@ -27350,6 +27989,17 @@ __metadata: languageName: node linkType: hard +"whatwg-url@npm:^7.0.0": + version: 7.1.0 + resolution: "whatwg-url@npm:7.1.0" + dependencies: + lodash.sortby: "npm:^4.7.0" + tr46: "npm:^1.0.1" + webidl-conversions: "npm:^4.0.2" + checksum: 10c0/2785fe4647690e5a0225a79509ba5e21fdf4a71f9de3eabdba1192483fe006fc79961198e0b99f82751557309f17fc5a07d4d83c251aa5b2f85ba71e674cbee9 + languageName: node + linkType: hard + "which-boxed-primitive@npm:^1.0.2, which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": version: 1.1.1 resolution: "which-boxed-primitive@npm:1.1.1" From 14c872e53634dfc47597b05be966229a6935df4f Mon Sep 17 00:00:00 2001 From: Derek Wene Date: Wed, 21 May 2025 09:02:34 -0500 Subject: [PATCH 02/15] chore: yarn.lock --- yarn.lock | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/yarn.lock b/yarn.lock index bd14fafa3..280659a7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1289,7 +1289,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.18, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.8": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.10, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.8": version: 7.26.9 resolution: "@babel/runtime@npm:7.26.9" dependencies: @@ -3608,19 +3608,6 @@ __metadata: languageName: unknown linkType: soft -"@loadable/component@npm:^5.15.3": - version: 5.16.4 - resolution: "@loadable/component@npm:5.16.4" - dependencies: - "@babel/runtime": "npm:^7.12.18" - hoist-non-react-statics: "npm:^3.3.1" - react-is: "npm:^16.12.0" - peerDependencies: - react: ^16.3.0 || ^17.0.0 || ^18.0.0 - checksum: 10c0/5d12056178232773e5fdd9ef218858991b97ff6cfece5902a0fa7243580f964545c9c013053c61bcdb8aaab0b54ac0075e55a900d976671679d76872c559f4a4 - languageName: node - linkType: hard - "@medusajs/admin-bundler@npm:2.8.2": version: 2.8.2 resolution: "@medusajs/admin-bundler@npm:2.8.2" @@ -18892,7 +18879,7 @@ __metadata: languageName: node linkType: hard -"hoist-non-react-statics@npm:^3.0.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2": +"hoist-non-react-statics@npm:^3.0.0, hoist-non-react-statics@npm:^3.3.2": version: 3.3.2 resolution: "hoist-non-react-statics@npm:3.3.2" dependencies: @@ -24274,7 +24261,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.7.0": +"react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 @@ -26066,7 +26053,6 @@ __metadata: "@heroicons/react": "npm:^2.0.18" "@lambdacurry/forms": "npm:^0.15.0" "@lambdacurry/medusa-plugins-sdk": "npm:0.0.5" - "@loadable/component": "npm:^5.15.3" "@medusajs/js-sdk": "npm:2.8.2" "@medusajs/types": "npm:2.8.2" "@mjackson/file-storage": "npm:^0.6.1" From b55b4408467873e2a94962f9fcc4a9d6642eabde Mon Sep 17 00:00:00 2001 From: Derek Wene Date: Wed, 21 May 2025 09:18:07 -0500 Subject: [PATCH 03/15] wip: page builder --- apps/medusa/medusa-config.ts | 4 + apps/medusa/src/modules/page-builder/index.ts | 10 +- ...ilder.json => .snapshot-page-builder.json} | 180 +++++++++--------- .../migrations/Migration20250305164601.ts | 103 ---------- .../migrations/Migration20250313155933.ts | 15 -- .../migrations/Migration20250521141500.ts | 103 ++++++++++ .../src/modules/page-builder/models/image.ts | 45 +++-- .../page-builder/models/navigation-item.ts | 21 +- .../page-builder/models/post-author.ts | 25 +-- .../page-builder/models/post-section.ts | 77 ++++---- .../modules/page-builder/models/post-tag.ts | 29 +-- .../page-builder/models/post-template.ts | 27 +-- .../src/modules/page-builder/models/post.ts | 71 ++++--- .../page-builder/models/site-settings.ts | 63 +++--- apps/medusa/src/scripts/seed.ts | 5 + 15 files changed, 396 insertions(+), 382 deletions(-) rename apps/medusa/src/modules/page-builder/migrations/{.snapshot-medusa-page-builder.json => .snapshot-page-builder.json} (83%) delete mode 100644 apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts delete mode 100644 apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts create mode 100644 apps/medusa/src/modules/page-builder/migrations/Migration20250521141500.ts diff --git a/apps/medusa/medusa-config.ts b/apps/medusa/medusa-config.ts index 5b83b3fda..268e89b96 100644 --- a/apps/medusa/medusa-config.ts +++ b/apps/medusa/medusa-config.ts @@ -76,6 +76,10 @@ module.exports = defineConfig({ cacheModule, eventBusModule, workflowEngineModule, + { + resolve: './src/modules/page-builder', + options: {}, + }, ], admin: { backendUrl: process.env.ADMIN_BACKEND_URL, diff --git a/apps/medusa/src/modules/page-builder/index.ts b/apps/medusa/src/modules/page-builder/index.ts index 42f96ad0f..37320abc9 100644 --- a/apps/medusa/src/modules/page-builder/index.ts +++ b/apps/medusa/src/modules/page-builder/index.ts @@ -1,15 +1,15 @@ -import { Module } from '@medusajs/framework/utils' +import { Module } from '@medusajs/framework/utils'; -import PageBuilderService from './service' +import PageBuilderService from './service'; -export const PAGE_BUILDER_MODULE = 'page-builder' +export const PAGE_BUILDER_MODULE = 'page_builder'; export const pageBuilderModuleEvents = Object.freeze({ POST_CREATED: 'post.created', POST_UPDATED: 'post.updated', POST_DELETED: 'post.deleted', -}) +}); export default Module(PAGE_BUILDER_MODULE, { service: PageBuilderService, -}) +}); diff --git a/apps/medusa/src/modules/page-builder/migrations/.snapshot-medusa-page-builder.json b/apps/medusa/src/modules/page-builder/migrations/.snapshot-page-builder.json similarity index 83% rename from apps/medusa/src/modules/page-builder/migrations/.snapshot-medusa-page-builder.json rename to apps/medusa/src/modules/page-builder/migrations/.snapshot-page-builder.json index 66eeab377..14c5ec289 100644 --- a/apps/medusa/src/modules/page-builder/migrations/.snapshot-medusa-page-builder.json +++ b/apps/medusa/src/modules/page-builder/migrations/.snapshot-page-builder.json @@ -99,20 +99,20 @@ "mappedType": "datetime" } }, - "name": "navigation_item", + "name": "page_builder_navigation_item", "schema": "public", "indexes": [ { - "keyName": "IDX_navigation_item_deleted_at", + "keyName": "IDX_page_builder_navigation_item_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_navigation_item_deleted_at\" ON \"navigation_item\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_navigation_item_deleted_at\" ON \"page_builder_navigation_item\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "navigation_item_pkey", + "keyName": "page_builder_navigation_item_pkey", "columnNames": [ "id" ], @@ -294,38 +294,38 @@ "mappedType": "datetime" } }, - "name": "post", + "name": "page_builder_post", "schema": "public", "indexes": [ { - "keyName": "IDX_post_handle_unique", + "keyName": "IDX_page_builder_post_handle_unique", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_post_handle_unique\" ON \"post\" (handle) WHERE deleted_at IS NULL" + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_page_builder_post_handle_unique\" ON \"page_builder_post\" (handle) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_post_root_id", + "keyName": "IDX_page_builder_post_root_id", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_root_id\" ON \"post\" (root_id) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_root_id\" ON \"page_builder_post\" (root_id) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_post_deleted_at", + "keyName": "IDX_page_builder_post_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_deleted_at\" ON \"post\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_deleted_at\" ON \"page_builder_post\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "post_pkey", + "keyName": "page_builder_post_pkey", "columnNames": [ "id" ], @@ -337,16 +337,16 @@ ], "checks": [], "foreignKeys": { - "post_root_id_foreign": { - "constraintName": "post_root_id_foreign", + "page_builder_post_root_id_foreign": { + "constraintName": "page_builder_post_root_id_foreign", "columnNames": [ "root_id" ], - "localTableName": "public.post", + "localTableName": "public.page_builder_post", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post", + "referencedTableName": "public.page_builder_post", "deleteRule": "set null", "updateRule": "cascade" } @@ -415,29 +415,29 @@ "mappedType": "datetime" } }, - "name": "post_author", + "name": "page_builder_post_author", "schema": "public", "indexes": [ { - "keyName": "IDX_post_author_medusa_user_id_unique", + "keyName": "IDX_page_builder_post_author_medusa_user_id_unique", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_post_author_medusa_user_id_unique\" ON \"post_author\" (medusa_user_id) WHERE deleted_at IS NULL" + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_page_builder_post_author_medusa_user_id_unique\" ON \"page_builder_post_author\" (medusa_user_id) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_post_author_deleted_at", + "keyName": "IDX_page_builder_post_author_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_author_deleted_at\" ON \"post_author\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_author_deleted_at\" ON \"page_builder_post_author\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "post_author_pkey", + "keyName": "page_builder_post_author_pkey", "columnNames": [ "id" ], @@ -472,11 +472,11 @@ "mappedType": "text" } }, - "name": "post_post_authors", + "name": "page_builder_post_page_builder_post_authors", "schema": "public", "indexes": [ { - "keyName": "post_post_authors_pkey", + "keyName": "page_builder_post_page_builder_post_authors_pkey", "columnNames": [ "post_id", "post_author_id" @@ -489,29 +489,29 @@ ], "checks": [], "foreignKeys": { - "post_post_authors_post_id_foreign": { - "constraintName": "post_post_authors_post_id_foreign", + "page_builder_post_page_builder_post_authors_post_id_foreign": { + "constraintName": "page_builder_post_page_builder_post_authors_post_id_foreign", "columnNames": [ "post_id" ], - "localTableName": "public.post_post_authors", + "localTableName": "public.page_builder_post_page_builder_post_authors", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post", + "referencedTableName": "public.page_builder_post", "deleteRule": "cascade", "updateRule": "cascade" }, - "post_post_authors_post_author_id_foreign": { - "constraintName": "post_post_authors_post_author_id_foreign", + "page_builder_post_page_builder_post_authors_post_c619d_foreign": { + "constraintName": "page_builder_post_page_builder_post_authors_post_c619d_foreign", "columnNames": [ "post_author_id" ], - "localTableName": "public.post_post_authors", + "localTableName": "public.page_builder_post_page_builder_post_authors", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post_author", + "referencedTableName": "public.page_builder_post_author", "deleteRule": "cascade", "updateRule": "cascade" } @@ -598,29 +598,29 @@ "mappedType": "datetime" } }, - "name": "post_tag", + "name": "page_builder_post_tag", "schema": "public", "indexes": [ { - "keyName": "IDX_post_tag_handle_unique", + "keyName": "IDX_page_builder_post_tag_handle_unique", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_post_tag_handle_unique\" ON \"post_tag\" (handle) WHERE deleted_at IS NULL" + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_page_builder_post_tag_handle_unique\" ON \"page_builder_post_tag\" (handle) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_post_tag_deleted_at", + "keyName": "IDX_page_builder_post_tag_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_tag_deleted_at\" ON \"post_tag\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_tag_deleted_at\" ON \"page_builder_post_tag\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "post_tag_pkey", + "keyName": "page_builder_post_tag_pkey", "columnNames": [ "id" ], @@ -655,11 +655,11 @@ "mappedType": "text" } }, - "name": "post_post_tags", + "name": "page_builder_post_page_builder_post_tags", "schema": "public", "indexes": [ { - "keyName": "post_post_tags_pkey", + "keyName": "page_builder_post_page_builder_post_tags_pkey", "columnNames": [ "post_id", "post_tag_id" @@ -672,29 +672,29 @@ ], "checks": [], "foreignKeys": { - "post_post_tags_post_id_foreign": { - "constraintName": "post_post_tags_post_id_foreign", + "page_builder_post_page_builder_post_tags_post_id_foreign": { + "constraintName": "page_builder_post_page_builder_post_tags_post_id_foreign", "columnNames": [ "post_id" ], - "localTableName": "public.post_post_tags", + "localTableName": "public.page_builder_post_page_builder_post_tags", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post", + "referencedTableName": "public.page_builder_post", "deleteRule": "cascade", "updateRule": "cascade" }, - "post_post_tags_post_tag_id_foreign": { - "constraintName": "post_post_tags_post_tag_id_foreign", + "page_builder_post_page_builder_post_tags_post_tag_id_foreign": { + "constraintName": "page_builder_post_page_builder_post_tags_post_tag_id_foreign", "columnNames": [ "post_tag_id" ], - "localTableName": "public.post_post_tags", + "localTableName": "public.page_builder_post_page_builder_post_tags", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post_tag", + "referencedTableName": "public.page_builder_post_tag", "deleteRule": "cascade", "updateRule": "cascade" } @@ -801,20 +801,20 @@ "mappedType": "datetime" } }, - "name": "post_template", + "name": "page_builder_post_template", "schema": "public", "indexes": [ { - "keyName": "IDX_post_template_deleted_at", + "keyName": "IDX_page_builder_post_template_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_template_deleted_at\" ON \"post_template\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_template_deleted_at\" ON \"page_builder_post_template\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "post_template_pkey", + "keyName": "page_builder_post_template_pkey", "columnNames": [ "id" ], @@ -991,38 +991,38 @@ "mappedType": "datetime" } }, - "name": "post_section", + "name": "page_builder_post_section", "schema": "public", "indexes": [ { - "keyName": "IDX_post_section_post_id", + "keyName": "IDX_page_builder_post_section_post_id", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_section_post_id\" ON \"post_section\" (post_id) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_section_post_id\" ON \"page_builder_post_section\" (post_id) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_post_section_post_template_id", + "keyName": "IDX_page_builder_post_section_post_template_id", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_section_post_template_id\" ON \"post_section\" (post_template_id) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_section_post_template_id\" ON \"page_builder_post_section\" (post_template_id) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_post_section_deleted_at", + "keyName": "IDX_page_builder_post_section_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_post_section_deleted_at\" ON \"post_section\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_post_section_deleted_at\" ON \"page_builder_post_section\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "post_section_pkey", + "keyName": "page_builder_post_section_pkey", "columnNames": [ "id" ], @@ -1034,29 +1034,29 @@ ], "checks": [], "foreignKeys": { - "post_section_post_id_foreign": { - "constraintName": "post_section_post_id_foreign", + "page_builder_post_section_post_id_foreign": { + "constraintName": "page_builder_post_section_post_id_foreign", "columnNames": [ "post_id" ], - "localTableName": "public.post_section", + "localTableName": "public.page_builder_post_section", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post", + "referencedTableName": "public.page_builder_post", "deleteRule": "set null", "updateRule": "cascade" }, - "post_section_post_template_id_foreign": { - "constraintName": "post_section_post_template_id_foreign", + "page_builder_post_section_post_template_id_foreign": { + "constraintName": "page_builder_post_section_post_template_id_foreign", "columnNames": [ "post_template_id" ], - "localTableName": "public.post_section", + "localTableName": "public.page_builder_post_section", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post_template", + "referencedTableName": "public.page_builder_post_template", "deleteRule": "set null", "updateRule": "cascade" } @@ -1296,20 +1296,20 @@ "mappedType": "datetime" } }, - "name": "site_settings", + "name": "page_builder_site_settings", "schema": "public", "indexes": [ { - "keyName": "IDX_site_settings_deleted_at", + "keyName": "IDX_page_builder_site_settings_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_site_settings_deleted_at\" ON \"site_settings\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_site_settings_deleted_at\" ON \"page_builder_site_settings\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "site_settings_pkey", + "keyName": "page_builder_site_settings_pkey", "columnNames": [ "id" ], @@ -1403,47 +1403,47 @@ "mappedType": "datetime" } }, - "name": "image", + "name": "page_builder_image", "schema": "public", "indexes": [ { - "keyName": "IDX_image_post_id_unique", + "keyName": "IDX_page_builder_image_post_id_unique", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_image_post_id_unique\" ON \"image\" (post_id) WHERE deleted_at IS NULL" + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_page_builder_image_post_id_unique\" ON \"page_builder_image\" (post_id) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_image_site_settings_id_unique", + "keyName": "IDX_page_builder_image_site_settings_id_unique", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_image_site_settings_id_unique\" ON \"image\" (site_settings_id) WHERE deleted_at IS NULL" + "expression": "CREATE UNIQUE INDEX IF NOT EXISTS \"IDX_page_builder_image_site_settings_id_unique\" ON \"page_builder_image\" (site_settings_id) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_image_deleted_at", + "keyName": "IDX_page_builder_image_deleted_at", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_image_deleted_at\" ON \"image\" (deleted_at) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_image_deleted_at\" ON \"page_builder_image\" (deleted_at) WHERE deleted_at IS NULL" }, { - "keyName": "IDX_product_image_url", + "keyName": "IDX_page_builder_image_url", "columnNames": [], "composite": false, "constraint": false, "primary": false, "unique": false, - "expression": "CREATE INDEX IF NOT EXISTS \"IDX_product_image_url\" ON \"image\" (url) WHERE deleted_at IS NULL" + "expression": "CREATE INDEX IF NOT EXISTS \"IDX_page_builder_image_url\" ON \"page_builder_image\" (url) WHERE deleted_at IS NULL" }, { - "keyName": "image_pkey", + "keyName": "page_builder_image_pkey", "columnNames": [ "id" ], @@ -1455,29 +1455,29 @@ ], "checks": [], "foreignKeys": { - "image_post_id_foreign": { - "constraintName": "image_post_id_foreign", + "page_builder_image_post_id_foreign": { + "constraintName": "page_builder_image_post_id_foreign", "columnNames": [ "post_id" ], - "localTableName": "public.image", + "localTableName": "public.page_builder_image", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.post", + "referencedTableName": "public.page_builder_post", "deleteRule": "set null", "updateRule": "cascade" }, - "image_site_settings_id_foreign": { - "constraintName": "image_site_settings_id_foreign", + "page_builder_image_site_settings_id_foreign": { + "constraintName": "page_builder_image_site_settings_id_foreign", "columnNames": [ "site_settings_id" ], - "localTableName": "public.image", + "localTableName": "public.page_builder_image", "referencedColumnNames": [ "id" ], - "referencedTableName": "public.site_settings", + "referencedTableName": "public.page_builder_site_settings", "deleteRule": "set null", "updateRule": "cascade" } diff --git a/apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts b/apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts deleted file mode 100644 index 914a57ed3..000000000 --- a/apps/medusa/src/modules/page-builder/migrations/Migration20250305164601.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Migration } from '@mikro-orm/migrations'; - -export class Migration20250305164601 extends Migration { - - override async up(): Promise { - this.addSql(`alter table if exists "image" drop constraint if exists "image_site_settings_id_unique";`); - this.addSql(`alter table if exists "image" drop constraint if exists "image_post_id_unique";`); - this.addSql(`alter table if exists "post_tag" drop constraint if exists "post_tag_handle_unique";`); - this.addSql(`alter table if exists "post_author" drop constraint if exists "post_author_medusa_user_id_unique";`); - this.addSql(`alter table if exists "post" drop constraint if exists "post_handle_unique";`); - this.addSql(`create table if not exists "navigation_item" ("id" text not null, "label" text not null, "location" text check ("location" in ('header', 'footer')) not null, "url" text not null, "new_tab" boolean not null default false, "sort_order" integer not null default 0, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "navigation_item_pkey" primary key ("id"));`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_navigation_item_deleted_at" ON "navigation_item" (deleted_at) WHERE deleted_at IS NULL;`); - - this.addSql(`create table if not exists "post" ("id" text not null, "type" text check ("type" in ('page', 'post')) not null, "title" text not null, "handle" text not null, "excerpt" text null, "content" jsonb null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "content_mode" text check ("content_mode" in ('basic', 'advanced')) not null, "seo" jsonb null, "published_at" text null, "archived_at" text null, "is_home_page" boolean not null default false, "root_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_pkey" primary key ("id"));`); - this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_post_handle_unique" ON "post" (handle) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_root_id" ON "post" (root_id) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_deleted_at" ON "post" (deleted_at) WHERE deleted_at IS NULL;`); - - this.addSql(`create table if not exists "post_author" ("id" text not null, "name" text not null, "medusa_user_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_author_pkey" primary key ("id"));`); - this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_post_author_medusa_user_id_unique" ON "post_author" (medusa_user_id) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_author_deleted_at" ON "post_author" (deleted_at) WHERE deleted_at IS NULL;`); - - this.addSql(`create table if not exists "post_post_authors" ("post_id" text not null, "post_author_id" text not null, constraint "post_post_authors_pkey" primary key ("post_id", "post_author_id"));`); - - this.addSql(`create table if not exists "post_tag" ("id" text not null, "label" text not null, "handle" text not null, "description" text not null, "created_by_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_tag_pkey" primary key ("id"));`); - this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_post_tag_handle_unique" ON "post_tag" (handle) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_tag_deleted_at" ON "post_tag" (deleted_at) WHERE deleted_at IS NULL;`); - - this.addSql(`create table if not exists "post_post_tags" ("post_id" text not null, "post_tag_id" text not null, constraint "post_post_tags_pkey" primary key ("post_id", "post_tag_id"));`); - - this.addSql(`create table if not exists "post_template" ("id" text not null, "title" text not null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "type" text check ("type" in ('page', 'post')) not null, "description" text null, "sort_order" integer not null default 0, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_template_pkey" primary key ("id"));`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_template_deleted_at" ON "post_template" (deleted_at) WHERE deleted_at IS NULL;`); - - this.addSql(`create table if not exists "post_section" ("id" text not null, "type" text check ("type" in ('button_list', 'cta', 'header', 'hero', 'product_carousel', 'product_grid', 'image_gallery', 'raw_html', 'rich_text', 'blog_list')) not null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "name" text not null, "content" jsonb not null, "settings" jsonb not null, "styles" jsonb null, "is_reusable" boolean not null default false, "usage_count" integer not null default 1, "sort_order" integer not null, "post_id" text null, "post_template_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "post_section_pkey" primary key ("id"));`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_section_post_id" ON "post_section" (post_id) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_section_post_template_id" ON "post_section" (post_template_id) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_post_section_deleted_at" ON "post_section" (deleted_at) WHERE deleted_at IS NULL;`); - - this.addSql(`create table if not exists "site_settings" ("id" text not null, "description" text null, "header_code" text null, "footer_code" text null, "storefront_url" text null, "primary_theme_colors" jsonb null, "accent_theme_colors" jsonb null, "highlight_theme_colors" jsonb null, "display_font" jsonb null, "body_font" jsonb null, "include_site_name_beside_logo" boolean not null, "social_instagram" text null, "social_youtube" text null, "social_facebook" text null, "social_twitter" text null, "social_linkedin" text null, "social_pinterest" text null, "social_tiktok" text null, "social_snapchat" text null, "global_css" text null, "ga_property_id" text null, "shipping_sort" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "site_settings_pkey" primary key ("id"));`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_site_settings_deleted_at" ON "site_settings" (deleted_at) WHERE deleted_at IS NULL;`); - - this.addSql(`create table if not exists "image" ("id" text not null, "url" text not null, "metadata" jsonb null, "post_id" text null, "site_settings_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "image_pkey" primary key ("id"));`); - this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_image_post_id_unique" ON "image" (post_id) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_image_site_settings_id_unique" ON "image" (site_settings_id) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_image_deleted_at" ON "image" (deleted_at) WHERE deleted_at IS NULL;`); - this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_product_image_url" ON "image" (url) WHERE deleted_at IS NULL;`); - - this.addSql(`alter table if exists "post" add constraint "post_root_id_foreign" foreign key ("root_id") references "post" ("id") on update cascade on delete set null;`); - - this.addSql(`alter table if exists "post_post_authors" add constraint "post_post_authors_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete cascade;`); - this.addSql(`alter table if exists "post_post_authors" add constraint "post_post_authors_post_author_id_foreign" foreign key ("post_author_id") references "post_author" ("id") on update cascade on delete cascade;`); - - this.addSql(`alter table if exists "post_post_tags" add constraint "post_post_tags_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete cascade;`); - this.addSql(`alter table if exists "post_post_tags" add constraint "post_post_tags_post_tag_id_foreign" foreign key ("post_tag_id") references "post_tag" ("id") on update cascade on delete cascade;`); - - this.addSql(`alter table if exists "post_section" add constraint "post_section_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete set null;`); - this.addSql(`alter table if exists "post_section" add constraint "post_section_post_template_id_foreign" foreign key ("post_template_id") references "post_template" ("id") on update cascade on delete set null;`); - - this.addSql(`alter table if exists "image" add constraint "image_post_id_foreign" foreign key ("post_id") references "post" ("id") on update cascade on delete set null;`); - this.addSql(`alter table if exists "image" add constraint "image_site_settings_id_foreign" foreign key ("site_settings_id") references "site_settings" ("id") on update cascade on delete set null;`); - } - - override async down(): Promise { - this.addSql(`alter table if exists "post" drop constraint if exists "post_root_id_foreign";`); - - this.addSql(`alter table if exists "post_post_authors" drop constraint if exists "post_post_authors_post_id_foreign";`); - - this.addSql(`alter table if exists "post_post_tags" drop constraint if exists "post_post_tags_post_id_foreign";`); - - this.addSql(`alter table if exists "post_section" drop constraint if exists "post_section_post_id_foreign";`); - - this.addSql(`alter table if exists "image" drop constraint if exists "image_post_id_foreign";`); - - this.addSql(`alter table if exists "post_post_authors" drop constraint if exists "post_post_authors_post_author_id_foreign";`); - - this.addSql(`alter table if exists "post_post_tags" drop constraint if exists "post_post_tags_post_tag_id_foreign";`); - - this.addSql(`alter table if exists "post_section" drop constraint if exists "post_section_post_template_id_foreign";`); - - this.addSql(`alter table if exists "image" drop constraint if exists "image_site_settings_id_foreign";`); - - this.addSql(`drop table if exists "navigation_item" cascade;`); - - this.addSql(`drop table if exists "post" cascade;`); - - this.addSql(`drop table if exists "post_author" cascade;`); - - this.addSql(`drop table if exists "post_post_authors" cascade;`); - - this.addSql(`drop table if exists "post_tag" cascade;`); - - this.addSql(`drop table if exists "post_post_tags" cascade;`); - - this.addSql(`drop table if exists "post_template" cascade;`); - - this.addSql(`drop table if exists "post_section" cascade;`); - - this.addSql(`drop table if exists "site_settings" cascade;`); - - this.addSql(`drop table if exists "image" cascade;`); - } - -} diff --git a/apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts b/apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts deleted file mode 100644 index 4016e27fb..000000000 --- a/apps/medusa/src/modules/page-builder/migrations/Migration20250313155933.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Migration } from '@mikro-orm/migrations'; - -export class Migration20250313155933 extends Migration { - - override async up(): Promise { - this.addSql(`alter table if exists "post" alter column "handle" type text using ("handle"::text);`); - this.addSql(`alter table if exists "post" alter column "handle" drop not null;`); - } - - override async down(): Promise { - this.addSql(`alter table if exists "post" alter column "handle" type text using ("handle"::text);`); - this.addSql(`alter table if exists "post" alter column "handle" set not null;`); - } - -} diff --git a/apps/medusa/src/modules/page-builder/migrations/Migration20250521141500.ts b/apps/medusa/src/modules/page-builder/migrations/Migration20250521141500.ts new file mode 100644 index 000000000..7ebfa2a4a --- /dev/null +++ b/apps/medusa/src/modules/page-builder/migrations/Migration20250521141500.ts @@ -0,0 +1,103 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20250521141500 extends Migration { + + override async up(): Promise { + this.addSql(`alter table if exists "page_builder_image" drop constraint if exists "page_builder_image_site_settings_id_unique";`); + this.addSql(`alter table if exists "page_builder_image" drop constraint if exists "page_builder_image_post_id_unique";`); + this.addSql(`alter table if exists "page_builder_post_tag" drop constraint if exists "page_builder_post_tag_handle_unique";`); + this.addSql(`alter table if exists "page_builder_post_author" drop constraint if exists "page_builder_post_author_medusa_user_id_unique";`); + this.addSql(`alter table if exists "page_builder_post" drop constraint if exists "page_builder_post_handle_unique";`); + this.addSql(`create table if not exists "page_builder_navigation_item" ("id" text not null, "label" text not null, "location" text check ("location" in ('header', 'footer')) not null, "url" text not null, "new_tab" boolean not null default false, "sort_order" integer not null default 0, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_navigation_item_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_navigation_item_deleted_at" ON "page_builder_navigation_item" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "page_builder_post" ("id" text not null, "type" text check ("type" in ('page', 'post')) not null, "title" text not null, "handle" text null, "excerpt" text null, "content" jsonb null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "content_mode" text check ("content_mode" in ('basic', 'advanced')) not null default 'advanced', "seo" jsonb null, "published_at" text null, "archived_at" text null, "is_home_page" boolean not null default false, "root_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_post_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_page_builder_post_handle_unique" ON "page_builder_post" (handle) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_root_id" ON "page_builder_post" (root_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_deleted_at" ON "page_builder_post" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "page_builder_post_author" ("id" text not null, "name" text not null, "medusa_user_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_post_author_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_page_builder_post_author_medusa_user_id_unique" ON "page_builder_post_author" (medusa_user_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_author_deleted_at" ON "page_builder_post_author" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "page_builder_post_page_builder_post_authors" ("post_id" text not null, "post_author_id" text not null, constraint "page_builder_post_page_builder_post_authors_pkey" primary key ("post_id", "post_author_id"));`); + + this.addSql(`create table if not exists "page_builder_post_tag" ("id" text not null, "label" text not null, "handle" text not null, "description" text not null, "created_by_id" text not null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_post_tag_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_page_builder_post_tag_handle_unique" ON "page_builder_post_tag" (handle) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_tag_deleted_at" ON "page_builder_post_tag" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "page_builder_post_page_builder_post_tags" ("post_id" text not null, "post_tag_id" text not null, constraint "page_builder_post_page_builder_post_tags_pkey" primary key ("post_id", "post_tag_id"));`); + + this.addSql(`create table if not exists "page_builder_post_template" ("id" text not null, "title" text not null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "type" text check ("type" in ('page', 'post')) not null, "description" text null, "sort_order" integer not null default 0, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_post_template_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_template_deleted_at" ON "page_builder_post_template" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "page_builder_post_section" ("id" text not null, "type" text check ("type" in ('button_list', 'cta', 'header', 'hero', 'product_carousel', 'product_grid', 'image_gallery', 'raw_html', 'rich_text', 'blog_list')) not null, "status" text check ("status" in ('draft', 'published', 'archived')) not null default 'draft', "name" text not null, "content" jsonb not null, "settings" jsonb not null, "styles" jsonb null, "is_reusable" boolean not null default false, "usage_count" integer not null default 1, "sort_order" integer not null, "post_id" text null, "post_template_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_post_section_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_section_post_id" ON "page_builder_post_section" (post_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_section_post_template_id" ON "page_builder_post_section" (post_template_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_post_section_deleted_at" ON "page_builder_post_section" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "page_builder_site_settings" ("id" text not null, "description" text null, "header_code" text null, "footer_code" text null, "storefront_url" text null, "primary_theme_colors" jsonb null, "accent_theme_colors" jsonb null, "highlight_theme_colors" jsonb null, "display_font" jsonb null, "body_font" jsonb null, "include_site_name_beside_logo" boolean not null, "social_instagram" text null, "social_youtube" text null, "social_facebook" text null, "social_twitter" text null, "social_linkedin" text null, "social_pinterest" text null, "social_tiktok" text null, "social_snapchat" text null, "global_css" text null, "ga_property_id" text null, "shipping_sort" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_site_settings_pkey" primary key ("id"));`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_site_settings_deleted_at" ON "page_builder_site_settings" (deleted_at) WHERE deleted_at IS NULL;`); + + this.addSql(`create table if not exists "page_builder_image" ("id" text not null, "url" text not null, "metadata" jsonb null, "post_id" text null, "site_settings_id" text null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "page_builder_image_pkey" primary key ("id"));`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_page_builder_image_post_id_unique" ON "page_builder_image" (post_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_page_builder_image_site_settings_id_unique" ON "page_builder_image" (site_settings_id) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_image_deleted_at" ON "page_builder_image" (deleted_at) WHERE deleted_at IS NULL;`); + this.addSql(`CREATE INDEX IF NOT EXISTS "IDX_page_builder_image_url" ON "page_builder_image" (url) WHERE deleted_at IS NULL;`); + + this.addSql(`alter table if exists "page_builder_post" add constraint "page_builder_post_root_id_foreign" foreign key ("root_id") references "page_builder_post" ("id") on update cascade on delete set null;`); + + this.addSql(`alter table if exists "page_builder_post_page_builder_post_authors" add constraint "page_builder_post_page_builder_post_authors_post_id_foreign" foreign key ("post_id") references "page_builder_post" ("id") on update cascade on delete cascade;`); + this.addSql(`alter table if exists "page_builder_post_page_builder_post_authors" add constraint "page_builder_post_page_builder_post_authors_post_c619d_foreign" foreign key ("post_author_id") references "page_builder_post_author" ("id") on update cascade on delete cascade;`); + + this.addSql(`alter table if exists "page_builder_post_page_builder_post_tags" add constraint "page_builder_post_page_builder_post_tags_post_id_foreign" foreign key ("post_id") references "page_builder_post" ("id") on update cascade on delete cascade;`); + this.addSql(`alter table if exists "page_builder_post_page_builder_post_tags" add constraint "page_builder_post_page_builder_post_tags_post_tag_id_foreign" foreign key ("post_tag_id") references "page_builder_post_tag" ("id") on update cascade on delete cascade;`); + + this.addSql(`alter table if exists "page_builder_post_section" add constraint "page_builder_post_section_post_id_foreign" foreign key ("post_id") references "page_builder_post" ("id") on update cascade on delete set null;`); + this.addSql(`alter table if exists "page_builder_post_section" add constraint "page_builder_post_section_post_template_id_foreign" foreign key ("post_template_id") references "page_builder_post_template" ("id") on update cascade on delete set null;`); + + this.addSql(`alter table if exists "page_builder_image" add constraint "page_builder_image_post_id_foreign" foreign key ("post_id") references "page_builder_post" ("id") on update cascade on delete set null;`); + this.addSql(`alter table if exists "page_builder_image" add constraint "page_builder_image_site_settings_id_foreign" foreign key ("site_settings_id") references "page_builder_site_settings" ("id") on update cascade on delete set null;`); + } + + override async down(): Promise { + this.addSql(`alter table if exists "page_builder_post" drop constraint if exists "page_builder_post_root_id_foreign";`); + + this.addSql(`alter table if exists "page_builder_post_page_builder_post_authors" drop constraint if exists "page_builder_post_page_builder_post_authors_post_id_foreign";`); + + this.addSql(`alter table if exists "page_builder_post_page_builder_post_tags" drop constraint if exists "page_builder_post_page_builder_post_tags_post_id_foreign";`); + + this.addSql(`alter table if exists "page_builder_post_section" drop constraint if exists "page_builder_post_section_post_id_foreign";`); + + this.addSql(`alter table if exists "page_builder_image" drop constraint if exists "page_builder_image_post_id_foreign";`); + + this.addSql(`alter table if exists "page_builder_post_page_builder_post_authors" drop constraint if exists "page_builder_post_page_builder_post_authors_post_c619d_foreign";`); + + this.addSql(`alter table if exists "page_builder_post_page_builder_post_tags" drop constraint if exists "page_builder_post_page_builder_post_tags_post_tag_id_foreign";`); + + this.addSql(`alter table if exists "page_builder_post_section" drop constraint if exists "page_builder_post_section_post_template_id_foreign";`); + + this.addSql(`alter table if exists "page_builder_image" drop constraint if exists "page_builder_image_site_settings_id_foreign";`); + + this.addSql(`drop table if exists "page_builder_navigation_item" cascade;`); + + this.addSql(`drop table if exists "page_builder_post" cascade;`); + + this.addSql(`drop table if exists "page_builder_post_author" cascade;`); + + this.addSql(`drop table if exists "page_builder_post_page_builder_post_authors" cascade;`); + + this.addSql(`drop table if exists "page_builder_post_tag" cascade;`); + + this.addSql(`drop table if exists "page_builder_post_page_builder_post_tags" cascade;`); + + this.addSql(`drop table if exists "page_builder_post_template" cascade;`); + + this.addSql(`drop table if exists "page_builder_post_section" cascade;`); + + this.addSql(`drop table if exists "page_builder_site_settings" cascade;`); + + this.addSql(`drop table if exists "page_builder_image" cascade;`); + } + +} diff --git a/apps/medusa/src/modules/page-builder/models/image.ts b/apps/medusa/src/modules/page-builder/models/image.ts index ab58e80a6..500af8797 100644 --- a/apps/medusa/src/modules/page-builder/models/image.ts +++ b/apps/medusa/src/modules/page-builder/models/image.ts @@ -1,30 +1,33 @@ -import { model } from '@medusajs/framework/utils' -import { PostModel } from './post' -import { SiteSettingsModel } from './site-settings' +import { model } from '@medusajs/framework/utils'; +import { PostModel } from './post'; +import { SiteSettingsModel } from './site-settings'; export const ImageModel = model - .define('image', { - id: model.id({ prefix: 'img' }).primaryKey(), - url: model.text(), - metadata: model.json().nullable(), + .define( + { name: 'image', tableName: 'page_builder_image' }, + { + id: model.id({ prefix: 'img' }).primaryKey(), + url: model.text(), + metadata: model.json().nullable(), - // relations fields - post: model - .belongsTo(() => PostModel, { - mappedBy: 'featured_image', - }) - .nullable(), - site_settings: model - .belongsTo(() => SiteSettingsModel, { - mappedBy: 'favicon', - }) - .nullable(), - }) + // relations fields + post: model + .belongsTo(() => PostModel, { + mappedBy: 'featured_image', + }) + .nullable(), + site_settings: model + .belongsTo(() => SiteSettingsModel, { + mappedBy: 'favicon', + }) + .nullable(), + }, + ) .indexes([ { - name: 'IDX_product_image_url', + name: 'IDX_page_builder_image_url', on: ['url'], unique: false, where: 'deleted_at IS NULL', }, - ]) + ]); diff --git a/apps/medusa/src/modules/page-builder/models/navigation-item.ts b/apps/medusa/src/modules/page-builder/models/navigation-item.ts index db55b3ab9..48f662d66 100644 --- a/apps/medusa/src/modules/page-builder/models/navigation-item.ts +++ b/apps/medusa/src/modules/page-builder/models/navigation-item.ts @@ -1,10 +1,13 @@ -import { model } from '@medusajs/framework/utils' +import { model } from '@medusajs/framework/utils'; -export const NavigationItemModel = model.define('navigation_item', { - id: model.id({ prefix: 'nav_item' }).primaryKey(), - label: model.text(), - location: model.enum(['header', 'footer']), - url: model.text(), - new_tab: model.boolean().default(false), - sort_order: model.number().default(0), -}) +export const NavigationItemModel = model.define( + { name: 'navigation_item', tableName: 'page_builder_navigation_item' }, + { + id: model.id({ prefix: 'nav_item' }).primaryKey(), + label: model.text(), + location: model.enum(['header', 'footer']), + url: model.text(), + new_tab: model.boolean().default(false), + sort_order: model.number().default(0), + }, +); diff --git a/apps/medusa/src/modules/page-builder/models/post-author.ts b/apps/medusa/src/modules/page-builder/models/post-author.ts index f9897b73b..968c2cec9 100644 --- a/apps/medusa/src/modules/page-builder/models/post-author.ts +++ b/apps/medusa/src/modules/page-builder/models/post-author.ts @@ -1,13 +1,16 @@ -import { model } from '@medusajs/framework/utils' -import { PostModel } from './post' +import { model } from '@medusajs/framework/utils'; +import { PostModel } from './post'; -export const PostAuthorModel = model.define('post_author', { - id: model.id({ prefix: 'post_author' }).primaryKey(), - name: model.text(), +export const PostAuthorModel = model.define( + { name: 'post_author', tableName: 'page_builder_post_author' }, + { + id: model.id({ prefix: 'post_author' }).primaryKey(), + name: model.text(), - // relations fields - medusa_user_id: model.text().unique(), - posts: model.manyToMany(() => PostModel, { - mappedBy: 'authors', - }), -}) + // relations fields + medusa_user_id: model.text().unique(), + posts: model.manyToMany(() => PostModel, { + mappedBy: 'authors', + }), + }, +); diff --git a/apps/medusa/src/modules/page-builder/models/post-section.ts b/apps/medusa/src/modules/page-builder/models/post-section.ts index 1a9823f3b..d80f3537b 100644 --- a/apps/medusa/src/modules/page-builder/models/post-section.ts +++ b/apps/medusa/src/modules/page-builder/models/post-section.ts @@ -1,39 +1,42 @@ -import { model } from '@medusajs/framework/utils' -import { PostModel } from './post' -import { PostTemplateModel } from './post-template' +import { model } from '@medusajs/framework/utils'; +import { PostModel } from './post'; +import { PostTemplateModel } from './post-template'; -export const PostSectionModel = model.define('post_section', { - id: model.id({ prefix: 'postsec' }).primaryKey(), - type: model.enum([ - 'button_list', - 'cta', - 'header', - 'hero', - 'product_carousel', - 'product_grid', - 'image_gallery', - 'raw_html', - 'rich_text', - 'blog_list', - ]), - status: model.enum(['draft', 'published', 'archived']).default('draft'), - name: model.text(), - content: model.json(), - settings: model.json(), - styles: model.json().nullable(), - is_reusable: model.boolean().default(false), - usage_count: model.number().default(1), - sort_order: model.number(), +export const PostSectionModel = model.define( + { name: 'post_section', tableName: 'page_builder_post_section' }, + { + id: model.id({ prefix: 'postsec' }).primaryKey(), + type: model.enum([ + 'button_list', + 'cta', + 'header', + 'hero', + 'product_carousel', + 'product_grid', + 'image_gallery', + 'raw_html', + 'rich_text', + 'blog_list', + ]), + status: model.enum(['draft', 'published', 'archived']).default('draft'), + name: model.text(), + content: model.json(), + settings: model.json(), + styles: model.json().nullable(), + is_reusable: model.boolean().default(false), + usage_count: model.number().default(1), + sort_order: model.number(), - // relations fields - post: model - .belongsTo(() => PostModel, { - mappedBy: 'sections', - }) - .nullable(), - post_template: model - .belongsTo(() => PostTemplateModel, { - mappedBy: 'sections', - }) - .nullable(), -}) + // relations fields + post: model + .belongsTo(() => PostModel, { + mappedBy: 'sections', + }) + .nullable(), + post_template: model + .belongsTo(() => PostTemplateModel, { + mappedBy: 'sections', + }) + .nullable(), + }, +); diff --git a/apps/medusa/src/modules/page-builder/models/post-tag.ts b/apps/medusa/src/modules/page-builder/models/post-tag.ts index 17e5e6c3a..1e2fcc28f 100644 --- a/apps/medusa/src/modules/page-builder/models/post-tag.ts +++ b/apps/medusa/src/modules/page-builder/models/post-tag.ts @@ -1,15 +1,18 @@ -import { model } from '@medusajs/framework/utils' -import { PostModel } from './post' +import { model } from '@medusajs/framework/utils'; +import { PostModel } from './post'; -export const PostTagModel = model.define('post_tag', { - id: model.id({ prefix: 'post_tag' }).primaryKey(), - label: model.text(), - handle: model.text().unique(), - description: model.text(), +export const PostTagModel = model.define( + { name: 'post_tag', tableName: 'page_builder_post_tag' }, + { + id: model.id({ prefix: 'post_tag' }).primaryKey(), + label: model.text(), + handle: model.text().unique(), + description: model.text(), - // relations fields - created_by_id: model.text(), - posts: model.manyToMany(() => PostModel, { - mappedBy: 'tags', - }), -}) + // relations fields + created_by_id: model.text(), + posts: model.manyToMany(() => PostModel, { + mappedBy: 'tags', + }), + }, +); diff --git a/apps/medusa/src/modules/page-builder/models/post-template.ts b/apps/medusa/src/modules/page-builder/models/post-template.ts index bc312b53f..14db63171 100644 --- a/apps/medusa/src/modules/page-builder/models/post-template.ts +++ b/apps/medusa/src/modules/page-builder/models/post-template.ts @@ -1,14 +1,17 @@ -import { model } from '@medusajs/framework/utils' -import { PostSectionModel } from './post-section' +import { model } from '@medusajs/framework/utils'; +import { PostSectionModel } from './post-section'; -export const PostTemplateModel = model.define('post_template', { - id: model.id({ prefix: 'post_temp' }).primaryKey(), - title: model.text(), - status: model.enum(['draft', 'published', 'archived']).default('draft'), - type: model.enum(['page', 'post']), - description: model.text().nullable(), - sort_order: model.number().default(0), +export const PostTemplateModel = model.define( + { name: 'post_template', tableName: 'page_builder_post_template' }, + { + id: model.id({ prefix: 'post_temp' }).primaryKey(), + title: model.text(), + status: model.enum(['draft', 'published', 'archived']).default('draft'), + type: model.enum(['page', 'post']), + description: model.text().nullable(), + sort_order: model.number().default(0), - // relations fields - sections: model.hasMany(() => PostSectionModel), -}) + // relations fields + sections: model.hasMany(() => PostSectionModel), + }, +); diff --git a/apps/medusa/src/modules/page-builder/models/post.ts b/apps/medusa/src/modules/page-builder/models/post.ts index d16f51690..e53fd86f4 100644 --- a/apps/medusa/src/modules/page-builder/models/post.ts +++ b/apps/medusa/src/modules/page-builder/models/post.ts @@ -1,41 +1,40 @@ -import { model } from '@medusajs/framework/utils' -import { PostSectionModel } from './post-section' -import { PostTagModel } from './post-tag' -import { PostAuthorModel } from './post-author' -import { ImageModel } from './image' -import { - postContentModeValues, - postStatusValues, - postTypeValues, -} from '../enum-values' +import { model } from '@medusajs/framework/utils'; +import { PostSectionModel } from './post-section'; +import { PostTagModel } from './post-tag'; +import { PostAuthorModel } from './post-author'; +import { ImageModel } from './image'; +import { postContentModeValues, postStatusValues, postTypeValues } from '../enum-values'; -export const PostModel = model.define('post', { - id: model.id({ prefix: 'post' }).primaryKey(), - type: model.enum([...postTypeValues]), - title: model.text().searchable(), - handle: model.text().unique().searchable().nullable(), - excerpt: model.text().searchable().nullable(), - content: model.json().nullable(), - status: model.enum([...postStatusValues]).default('draft'), - content_mode: model.enum([...postContentModeValues]).default('advanced'), - seo: model.json().nullable(), - published_at: model.text().nullable(), - archived_at: model.text().nullable(), - is_home_page: model.boolean().default(false), +export const PostModel = model.define( + { name: 'post', tableName: 'page_builder_post' }, + { + id: model.id({ prefix: 'post' }).primaryKey(), + type: model.enum([...postTypeValues]), + title: model.text().searchable(), + handle: model.text().unique().searchable().nullable(), + excerpt: model.text().searchable().nullable(), + content: model.json().nullable(), + status: model.enum([...postStatusValues]).default('draft'), + content_mode: model.enum([...postContentModeValues]).default('advanced'), + seo: model.json().nullable(), + published_at: model.text().nullable(), + archived_at: model.text().nullable(), + is_home_page: model.boolean().default(false), - // relations fields - featured_image: model.hasOne(() => ImageModel, { - mappedBy: 'post', - }), - authors: model.manyToMany(() => PostAuthorModel, { - mappedBy: 'posts', - }), + // relations fields + featured_image: model.hasOne(() => ImageModel, { + mappedBy: 'post', + }), + authors: model.manyToMany(() => PostAuthorModel, { + mappedBy: 'posts', + }), - root: model.belongsTo(() => PostModel).nullable(), + root: model.belongsTo(() => PostModel).nullable(), - sections: model.hasMany(() => PostSectionModel), + sections: model.hasMany(() => PostSectionModel), - tags: model.manyToMany(() => PostTagModel, { - mappedBy: 'posts', - }), -}) + tags: model.manyToMany(() => PostTagModel, { + mappedBy: 'posts', + }), + }, +); diff --git a/apps/medusa/src/modules/page-builder/models/site-settings.ts b/apps/medusa/src/modules/page-builder/models/site-settings.ts index 8f97c169b..0515a467f 100644 --- a/apps/medusa/src/modules/page-builder/models/site-settings.ts +++ b/apps/medusa/src/modules/page-builder/models/site-settings.ts @@ -1,32 +1,35 @@ -import { model } from '@medusajs/framework/utils' -import { ImageModel } from './image' +import { model } from '@medusajs/framework/utils'; +import { ImageModel } from './image'; -export const SiteSettingsModel = model.define('site_settings', { - id: model.id({ prefix: 'site_sett' }).primaryKey(), - description: model.text().nullable(), - header_code: model.text().nullable(), - footer_code: model.text().nullable(), - storefront_url: model.text().nullable(), - primary_theme_colors: model.json().nullable(), - accent_theme_colors: model.json().nullable(), - highlight_theme_colors: model.json().nullable(), - display_font: model.json().nullable(), - body_font: model.json().nullable(), - include_site_name_beside_logo: model.boolean(), - social_instagram: model.text().nullable(), - social_youtube: model.text().nullable(), - social_facebook: model.text().nullable(), - social_twitter: model.text().nullable(), - social_linkedin: model.text().nullable(), - social_pinterest: model.text().nullable(), - social_tiktok: model.text().nullable(), - social_snapchat: model.text().nullable(), - global_css: model.text().nullable(), - ga_property_id: model.text().nullable(), - shipping_sort: model.text().nullable(), +export const SiteSettingsModel = model.define( + { name: 'site_settings', tableName: 'page_builder_site_settings' }, + { + id: model.id({ prefix: 'site_sett' }).primaryKey(), + description: model.text().nullable(), + header_code: model.text().nullable(), + footer_code: model.text().nullable(), + storefront_url: model.text().nullable(), + primary_theme_colors: model.json().nullable(), + accent_theme_colors: model.json().nullable(), + highlight_theme_colors: model.json().nullable(), + display_font: model.json().nullable(), + body_font: model.json().nullable(), + include_site_name_beside_logo: model.boolean(), + social_instagram: model.text().nullable(), + social_youtube: model.text().nullable(), + social_facebook: model.text().nullable(), + social_twitter: model.text().nullable(), + social_linkedin: model.text().nullable(), + social_pinterest: model.text().nullable(), + social_tiktok: model.text().nullable(), + social_snapchat: model.text().nullable(), + global_css: model.text().nullable(), + ga_property_id: model.text().nullable(), + shipping_sort: model.text().nullable(), - // relations - favicon: model.hasOne(() => ImageModel, { - mappedBy: 'site_settings', - }), -}) + // relations + favicon: model.hasOne(() => ImageModel, { + mappedBy: 'site_settings', + }), + }, +); diff --git a/apps/medusa/src/scripts/seed.ts b/apps/medusa/src/scripts/seed.ts index 322e7ca1c..8d4fff51e 100644 --- a/apps/medusa/src/scripts/seed.ts +++ b/apps/medusa/src/scripts/seed.ts @@ -105,9 +105,14 @@ export default async function seedDemoData({ container }: ExecArgs) { logger.info('Seeding tax regions...'); + const taxModule = container.resolve(Modules.TAX); + + const taxProviders = await taxModule.listTaxProviders(); + await createTaxRegionsWorkflow(container).run({ input: allCountries.map((country_code) => ({ country_code, + tax_provider_id: taxProviders[0].id, })), }); From 83d10a4147f1c3568525e3f4a0f37d16a30d2cba Mon Sep 17 00:00:00 2001 From: Derek Wene Date: Wed, 21 May 2025 09:22:12 -0500 Subject: [PATCH 04/15] fix: seed data --- apps/medusa/src/scripts/seed.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/medusa/src/scripts/seed.ts b/apps/medusa/src/scripts/seed.ts index 8d4fff51e..03fef8a16 100644 --- a/apps/medusa/src/scripts/seed.ts +++ b/apps/medusa/src/scripts/seed.ts @@ -108,11 +108,12 @@ export default async function seedDemoData({ container }: ExecArgs) { const taxModule = container.resolve(Modules.TAX); const taxProviders = await taxModule.listTaxProviders(); + const taxProvider = taxProviders.find((provider) => provider.id.includes('system')); await createTaxRegionsWorkflow(container).run({ input: allCountries.map((country_code) => ({ country_code, - tax_provider_id: taxProviders[0].id, + provider_id: taxProvider?.id, })), }); From f826f876bd80040d897707f2d5b97463d986698d Mon Sep 17 00:00:00 2001 From: Derek Wene Date: Wed, 21 May 2025 11:35:27 -0500 Subject: [PATCH 05/15] wip: medusa cloud fizx --- apps/medusa/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/medusa/package.json b/apps/medusa/package.json index 9c1a4c2b3..e5731f519 100644 --- a/apps/medusa/package.json +++ b/apps/medusa/package.json @@ -47,6 +47,7 @@ "pg": "^8.13.0" }, "devDependencies": { + "@lambdacurry/page-builder-sdk": "0.0.1", "@medusajs/test-utils": "2.8.2", "@mikro-orm/cli": "6.4.3", "@mikro-orm/core": "6.4.3", From 05a84a773c7375b39f9e7cf8f5bf370d4783178c Mon Sep 17 00:00:00 2001 From: Derek Wene Date: Wed, 21 May 2025 11:43:51 -0500 Subject: [PATCH 06/15] wip: page builder --- packages/page-builder-sdk/package.json | 2 +- yarn.lock | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/page-builder-sdk/package.json b/packages/page-builder-sdk/package.json index b767eff5d..9a1b1b161 100644 --- a/packages/page-builder-sdk/package.json +++ b/packages/page-builder-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@lambdacurry/page-builder-sdk", - "version": "0.0.6-beta.3", + "version": "0.0.1", "description": "SDK for Medusa plugins", "author": "Lambda Curry (https://lambdacurry.dev)", "license": "MIT", diff --git a/yarn.lock b/yarn.lock index 280659a7c..bbf74737a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3582,7 +3582,7 @@ __metadata: languageName: node linkType: hard -"@lambdacurry/page-builder-sdk@workspace:packages/page-builder-sdk": +"@lambdacurry/page-builder-sdk@npm:0.0.1, @lambdacurry/page-builder-sdk@workspace:packages/page-builder-sdk": version: 0.0.0-use.local resolution: "@lambdacurry/page-builder-sdk@workspace:packages/page-builder-sdk" dependencies: @@ -21784,6 +21784,7 @@ __metadata: resolution: "medusa@workspace:apps/medusa" dependencies: "@lambdacurry/medusa-product-reviews": "npm:1.2.0" + "@lambdacurry/page-builder-sdk": "npm:0.0.1" "@medusajs/admin-sdk": "npm:2.8.2" "@medusajs/cli": "npm:2.8.2" "@medusajs/framework": "npm:2.8.2" From 08ca3e21015e7b460d1504f812a5b729d7dfd157 Mon Sep 17 00:00:00 2001 From: Derek Wene Date: Wed, 21 May 2025 12:10:42 -0500 Subject: [PATCH 07/15] fix: broken apis --- .../admin/content/posts/[id]/middlewares.ts | 21 +++++++++++++------ .../posts/[id]/{route.tsx => route.ts} | 17 +++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) rename apps/medusa/src/api/admin/content/posts/[id]/{route.tsx => route.ts} (69%) diff --git a/apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts b/apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts index 0a1b7355b..4a9a8a9f9 100644 --- a/apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts +++ b/apps/medusa/src/api/admin/content/posts/[id]/middlewares.ts @@ -1,8 +1,12 @@ -import { - type MiddlewareRoute, - validateAndTransformBody, -} from '@medusajs/framework' -import { updatePostSchema } from '../../validations' +import { type MiddlewareRoute, validateAndTransformBody, validateAndTransformQuery } from '@medusajs/framework'; +import { updatePostSchema } from '../../validations'; +import { defaultAdminPostFields, defaultPostsQueryConfig } from '../middlewares'; +import { createFindParams } from '@medusajs/medusa/api/utils/validators'; + +export const defaultGetPostQueryConfig = { + defaults: [...defaultAdminPostFields], + isList: false, +}; export const adminPostItemRoutesMiddlewares: MiddlewareRoute[] = [ { @@ -10,9 +14,14 @@ export const adminPostItemRoutesMiddlewares: MiddlewareRoute[] = [ method: 'PUT', middlewares: [validateAndTransformBody(updatePostSchema)], }, + { + matcher: '/admin/content/posts/:id', + method: 'GET', + middlewares: [validateAndTransformQuery(createFindParams({}), defaultGetPostQueryConfig)], + }, { matcher: '/admin/content/posts/:id', method: 'DELETE', middlewares: [], }, -] +]; diff --git a/apps/medusa/src/api/admin/content/posts/[id]/route.tsx b/apps/medusa/src/api/admin/content/posts/[id]/route.ts similarity index 69% rename from apps/medusa/src/api/admin/content/posts/[id]/route.tsx rename to apps/medusa/src/api/admin/content/posts/[id]/route.ts index 1cfee6c4a..f08291be4 100644 --- a/apps/medusa/src/api/admin/content/posts/[id]/route.tsx +++ b/apps/medusa/src/api/admin/content/posts/[id]/route.ts @@ -2,6 +2,7 @@ import type { AuthenticatedMedusaRequest, MedusaResponse } from '@medusajs/frame import { updatePostWorkflow } from '../../../../../workflows/update-post'; import { deletePostWorkflow } from '../../../../../workflows/delete-post'; import type { AdminPageBuilderUpdatePostBody } from '@lambdacurry/page-builder-types'; +import { MedusaError } from '@medusajs/framework/utils'; export const PUT = async (req: AuthenticatedMedusaRequest, res: MedusaResponse) => { const id = req.params.id; @@ -16,6 +17,22 @@ export const PUT = async (req: AuthenticatedMedusaRequest { + const query = req.scope.resolve('query'); + + const { data: posts } = await query.graph({ + entity: 'post', + fields: req.queryConfig?.fields || ['*'], + filters: { id: req.params.id }, + }); + + const post = posts[0]; + + res.status(200).json({ + post: post, + }); +}; + export const DELETE = async (req: AuthenticatedMedusaRequest, res: MedusaResponse) => { const id = req.params.id; From 7c2559232f0f9008c4fbeb7ca39146db61defad4 Mon Sep 17 00:00:00 2001 From: Derek Wene Date: Thu, 22 May 2025 15:09:22 -0500 Subject: [PATCH 08/15] wip: page builder stuff --- apps/medusa/medusa-config.ts | 1 + .../ControlledFields/ControlledCheckbox.tsx | 42 ++++++ .../ControlledCurrencyInput.tsx | 37 +++++ .../ControlledFields/ControlledDatePicker.tsx | 26 ++++ .../ControlledFields/ControlledInput.tsx | 44 ++++++ .../ControlledSearchableSelect.tsx | 36 +++++ .../ControlledFields/ControlledSelect.tsx | 52 +++++++ .../ControlledFields/ControlledTextArea.tsx | 28 ++++ .../components/inputs/Field/ColorInput.tsx | 34 +++++ .../components/inputs/Field/CurrencyInput.tsx | 12 ++ .../components/inputs/Field/DatePicker.tsx | 12 ++ .../admin/components/inputs/Field/Error.tsx | 64 +++++++++ .../components/inputs/Field/FieldCheckbox.tsx | 51 +++++++ .../components/inputs/Field/FieldGroup.tsx | 5 + .../components/inputs/Field/FieldWrapper.tsx | 27 ++++ .../components/inputs/Field/FileUpload.tsx | 115 ++++++++++++++++ .../admin/components/inputs/Field/Input.tsx | 12 ++ .../admin/components/inputs/Field/Label.tsx | 26 ++++ .../inputs/Field/SearchableSelect.tsx | 23 ++++ .../admin/components/inputs/Field/Select.tsx | 24 ++++ .../components/inputs/Field/TextArea.tsx | 12 ++ .../admin/components/inputs/Field/types.d.ts | 129 ++++++++++++++++++ .../organisms/editor/PostDetailsForm.tsx | 111 +++++++++++++++ .../organisms/editor}/breadcrumbs.tsx | 0 .../organisms/editor}/editor-modal.tsx | 0 .../organisms/editor}/editor-sidebar.tsx | 0 .../organisms/editor}/editor-top-bar.tsx | 0 .../organisms/editor/main-content.tsx | 22 +++ .../organisms/editor}/nav-item.tsx | 0 .../organisms/editor/post-editor-layout.tsx | 22 +++ .../editor/post-settings-sidebar.tsx | 24 ++++ .../organisms/editor/sidebar-container.tsx | 57 ++++++++ .../organisms/editor/sidebar-toggle.tsx | 34 +++++ .../admin/hooks/editor/use-editor-sidebar.tsx | 15 ++ .../editor}/use-loading-state.ts | 0 .../medusa/src/admin/hooks/posts-mutations.ts | 7 +- .../components/posts-data-table/index.tsx | 2 +- .../admin/routes/content/editor/[id]/page.tsx | 59 ++++++++ .../editor/components/main-content.tsx | 23 ---- .../editor/components/post-editor-layout.tsx | 20 --- .../components/post-settings-sidebar.tsx | 30 ---- .../editor/components/sidebar-container.tsx | 68 --------- .../editor/components/sidebar-toggle.tsx | 34 ----- .../editor/hooks/use-editor-sidebar.tsx | 12 -- .../providers/editor-sidebar-context.tsx | 24 ++-- .../providers/editor-sidebar-provider.tsx | 32 +++-- .../admin/routes/content/editor/test/page.tsx | 101 +++++++------- .../routes/content/editor/test2/page.tsx | 61 +++++++++ apps/medusa/src/admin/routes/content/page.tsx | 55 ++++---- .../src/api/admin/content/posts/[id]/route.ts | 2 +- .../src/api/admin/content/validations.ts | 32 ++--- apps/medusa/src/api/admin/custom/route.ts | 5 - apps/medusa/src/api/store/custom/route.ts | 12 -- packages/page-builder-types/src/admins.d.ts | 1 - 54 files changed, 1345 insertions(+), 332 deletions(-) create mode 100644 apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCheckbox.tsx create mode 100644 apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCurrencyInput.tsx create mode 100644 apps/medusa/src/admin/components/inputs/ControlledFields/ControlledDatePicker.tsx create mode 100644 apps/medusa/src/admin/components/inputs/ControlledFields/ControlledInput.tsx create mode 100644 apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSearchableSelect.tsx create mode 100644 apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSelect.tsx create mode 100644 apps/medusa/src/admin/components/inputs/ControlledFields/ControlledTextArea.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/ColorInput.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/CurrencyInput.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/DatePicker.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/Error.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/FieldCheckbox.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/FieldGroup.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/FieldWrapper.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/FileUpload.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/Input.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/Label.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/SearchableSelect.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/Select.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/TextArea.tsx create mode 100644 apps/medusa/src/admin/components/inputs/Field/types.d.ts create mode 100644 apps/medusa/src/admin/components/organisms/editor/PostDetailsForm.tsx rename apps/medusa/src/admin/{routes/content/editor/components => components/organisms/editor}/breadcrumbs.tsx (100%) rename apps/medusa/src/admin/{routes/content/editor/components => components/organisms/editor}/editor-modal.tsx (100%) rename apps/medusa/src/admin/{routes/content/editor/components => components/organisms/editor}/editor-sidebar.tsx (100%) rename apps/medusa/src/admin/{routes/content/editor/components => components/organisms/editor}/editor-top-bar.tsx (100%) create mode 100644 apps/medusa/src/admin/components/organisms/editor/main-content.tsx rename apps/medusa/src/admin/{routes/content/editor/components => components/organisms/editor}/nav-item.tsx (100%) create mode 100644 apps/medusa/src/admin/components/organisms/editor/post-editor-layout.tsx create mode 100644 apps/medusa/src/admin/components/organisms/editor/post-settings-sidebar.tsx create mode 100644 apps/medusa/src/admin/components/organisms/editor/sidebar-container.tsx create mode 100644 apps/medusa/src/admin/components/organisms/editor/sidebar-toggle.tsx create mode 100644 apps/medusa/src/admin/hooks/editor/use-editor-sidebar.tsx rename apps/medusa/src/admin/{routes/content/editor/hooks => hooks/editor}/use-loading-state.ts (100%) create mode 100644 apps/medusa/src/admin/routes/content/editor/[id]/page.tsx delete mode 100644 apps/medusa/src/admin/routes/content/editor/components/main-content.tsx delete mode 100644 apps/medusa/src/admin/routes/content/editor/components/post-editor-layout.tsx delete mode 100644 apps/medusa/src/admin/routes/content/editor/components/post-settings-sidebar.tsx delete mode 100644 apps/medusa/src/admin/routes/content/editor/components/sidebar-container.tsx delete mode 100644 apps/medusa/src/admin/routes/content/editor/components/sidebar-toggle.tsx delete mode 100644 apps/medusa/src/admin/routes/content/editor/hooks/use-editor-sidebar.tsx create mode 100644 apps/medusa/src/admin/routes/content/editor/test2/page.tsx delete mode 100644 apps/medusa/src/api/admin/custom/route.ts delete mode 100644 apps/medusa/src/api/store/custom/route.ts diff --git a/apps/medusa/medusa-config.ts b/apps/medusa/medusa-config.ts index 268e89b96..65704108c 100644 --- a/apps/medusa/medusa-config.ts +++ b/apps/medusa/medusa-config.ts @@ -1,4 +1,5 @@ import { defineConfig, loadEnv } from '@medusajs/framework/utils'; +import { sectionConfig } from 'section-config'; loadEnv(process.env.NODE_ENV || 'development', process.cwd()); diff --git a/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCheckbox.tsx b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCheckbox.tsx new file mode 100644 index 000000000..8b17102a7 --- /dev/null +++ b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCheckbox.tsx @@ -0,0 +1,42 @@ +import { + Controller, + type ControllerProps, + type FieldValues, + type Path, + type RegisterOptions, + useFormContext, +} from 'react-hook-form'; +import { FieldCheckbox, type FieldCheckboxProps } from '../Field/FieldCheckbox'; + +type Props = Omit & + Omit & { + name: Path; + rules?: Omit>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>; + }; + +export const ControlledCheckbox = ({ name, rules, onChange, ...props }: Props) => { + const { + control, + formState: { errors }, + } = useFormContext(); + + return ( + >, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + render={({ field }) => ( + { + if (onChange) onChange(checked); + field.onChange(checked); + }} + /> + )} + /> + ); +}; diff --git a/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCurrencyInput.tsx b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCurrencyInput.tsx new file mode 100644 index 000000000..5fb02f7fc --- /dev/null +++ b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledCurrencyInput.tsx @@ -0,0 +1,37 @@ +import { + Controller, + type ControllerProps, + type FieldValues, + type Path, + type RegisterOptions, + useFormContext, +} from 'react-hook-form'; +import { CurrencyInput, type Props as CurrencyInputProps } from '../Field/CurrencyInput'; + +type Props = CurrencyInputProps & + Omit & { + name: Path; + }; + +export const ControlledCurrencyInput = ({ name, rules, ...props }: Props) => { + const { control } = useFormContext(); + + return ( + + control={control} + name={name} + rules={rules as Omit>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + render={({ field }) => { + return ( + ) => { + field.onChange(e.target.value.replace(/[^0-9.-]+/g, '')); + }} + /> + ); + }} + /> + ); +}; diff --git a/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledDatePicker.tsx b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledDatePicker.tsx new file mode 100644 index 000000000..d7f666f0c --- /dev/null +++ b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledDatePicker.tsx @@ -0,0 +1,26 @@ +import { + Controller, + type ControllerProps, + type FieldValues, + type Path, + type RegisterOptions, + useFormContext, +} from 'react-hook-form'; +import { DatePickerInput, type Props as DatePickerProps } from '../Field/DatePicker'; + +type Props = DatePickerProps & + Omit & { + name: Path; + }; + +export const ControlledDatePicker = ({ name, rules, ...props }: Props) => { + const { control } = useFormContext(); + return ( + + control={control} + name={name} + rules={rules as Omit>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + render={({ field }) => } + /> + ); +}; diff --git a/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledInput.tsx b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledInput.tsx new file mode 100644 index 000000000..6a263a1e3 --- /dev/null +++ b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledInput.tsx @@ -0,0 +1,44 @@ +import { + Controller, + type ControllerProps, + type FieldValues, + type Path, + type RegisterOptions, + useFormContext, +} from 'react-hook-form'; +import { Input, type Props as InputProps } from '../Field/Input'; + +type Props = InputProps & + Omit & { + name: Path; + rules?: Omit>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>; + } & React.ComponentProps & + Omit, 'render'>; + +export const ControlledInput = ({ name, rules, onChange, ...props }: Props) => { + const { + control, + formState: { errors }, + } = useFormContext(); + + return ( + >, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + render={({ field }) => ( + { + if (onChange) { + onChange(evt); + } + field.onChange(evt); + }} + /> + )} + /> + ); +}; diff --git a/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSearchableSelect.tsx b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSearchableSelect.tsx new file mode 100644 index 000000000..930b6aeee --- /dev/null +++ b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSearchableSelect.tsx @@ -0,0 +1,36 @@ +import { + Controller, + type ControllerProps, + type FieldValues, + type Path, + type RegisterOptions, + useFormContext, +} from 'react-hook-form'; +import { SearchableSelect, type Props as SearchableSelectProps } from '../Field/SearchableSelect'; + +type Props = SearchableSelectProps & + Omit & { + name: Path; + }; + +export const ControlledSearchableSelect = ({ name, rules, onChange, ...props }: Props) => { + const { control } = useFormContext(); + + return ( + + control={control} + name={name} + rules={rules as Omit>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + render={({ field }) => ( + { + field.onChange(a, b); + onChange?.(a, b); + }} + /> + )} + /> + ); +}; diff --git a/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSelect.tsx b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSelect.tsx new file mode 100644 index 000000000..fc97b3a5f --- /dev/null +++ b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledSelect.tsx @@ -0,0 +1,52 @@ +import { + Controller, + type ControllerProps, + type FieldValues, + type Path, + type RegisterOptions, + useFormContext, +} from 'react-hook-form'; +import { Select, type Props as SelectProps } from '../Field/Select'; + +type Props = SelectProps & + Omit & { + name: Path; + children: React.ReactNode; + onBlur?: () => void; + onChange?: (value: unknown) => void; + }; + +export const ControlledSelect = ({ + name, + rules, + children, + onChange, + onBlur, + ...props +}: Props) => { + const { control } = useFormContext(); + return ( + + control={control} + name={name} + rules={rules as Omit>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'>} + render={({ field }) => { + const handleChange = (value: unknown) => { + if (typeof onChange === 'function') onChange(value); + field.onChange(value); + }; + + const handleBlur = () => { + if (typeof onBlur === 'function') onBlur(); + field.onBlur(); + }; + + return ( + + ); + }} + /> + ); +}; diff --git a/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledTextArea.tsx b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledTextArea.tsx new file mode 100644 index 000000000..692f44594 --- /dev/null +++ b/apps/medusa/src/admin/components/inputs/ControlledFields/ControlledTextArea.tsx @@ -0,0 +1,28 @@ +import { + Controller, + type ControllerProps, + type FieldValues, + type Path, + type RegisterOptions, + useFormContext, +} from 'react-hook-form'; +import { TextArea, type Props as TextAreaProps } from '../Field/TextArea'; + +type Props = TextAreaProps & + Omit & { + name: Path; + rules?: RegisterOptions>; + } & React.ComponentProps & + Omit, 'render'>; + +export const ControlledTextArea = ({ name, rules, ...props }: Props) => { + const { control } = useFormContext(); + return ( + + control={control} + name={name} + rules={rules} + render={({ field }) =>