medusa-strapi-plugin 0.0.13 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.medusa/server/src/modules/strapi/service.js +34 -1
  2. package/CHANGELOG.md +79 -0
  3. package/package.json +1 -1
  4. package/src/admin/README.md +34 -0
  5. package/src/admin/lib/sdk.ts +9 -0
  6. package/src/admin/routes/strapi/page.tsx +44 -0
  7. package/src/admin/tsconfig.json +24 -0
  8. package/src/admin/vite-env.d.ts +1 -0
  9. package/src/api/README.md +123 -0
  10. package/src/api/admin/strapi/sync/route.ts +38 -0
  11. package/src/jobs/README.md +36 -0
  12. package/src/links/README.md +26 -0
  13. package/src/links/strapi-categories.ts +23 -0
  14. package/src/links/strapi-collections.ts +23 -0
  15. package/src/links/strapi-product-variants.ts +23 -0
  16. package/src/links/strapi-products.ts +23 -0
  17. package/src/modules/README.md +113 -0
  18. package/src/modules/strapi/index.ts +10 -0
  19. package/src/modules/strapi/loader/create-content-models.ts +144 -0
  20. package/src/modules/strapi/service.ts +576 -0
  21. package/src/providers/README.md +30 -0
  22. package/src/subscribers/README.md +54 -0
  23. package/src/subscribers/create-category.ts +25 -0
  24. package/src/subscribers/create-collection.ts +25 -0
  25. package/src/subscribers/create-product.ts +25 -0
  26. package/src/subscribers/create-variant.ts +25 -0
  27. package/src/subscribers/delete-category.ts +25 -0
  28. package/src/subscribers/delete-collection.ts +25 -0
  29. package/src/subscribers/delete-product.ts +25 -0
  30. package/src/subscribers/delete-variant.ts +25 -0
  31. package/src/subscribers/sync-categories.ts +44 -0
  32. package/src/subscribers/sync-collections.ts +44 -0
  33. package/src/subscribers/sync-products.ts +44 -0
  34. package/src/subscribers/update-category.ts +25 -0
  35. package/src/subscribers/update-collection.ts +25 -0
  36. package/src/subscribers/update-product.ts +25 -0
  37. package/src/subscribers/update-variant.ts +25 -0
  38. package/src/workflows/README.md +69 -0
  39. package/src/workflows/delete-categories-strapi.ts +20 -0
  40. package/src/workflows/delete-collections-strapi.ts +20 -0
  41. package/src/workflows/delete-product-variants-strapi.ts +20 -0
  42. package/src/workflows/delete-products-strapi.ts +20 -0
  43. package/src/workflows/steps/delete-categories-strapi.ts +29 -0
  44. package/src/workflows/steps/delete-collections-strapi.ts +31 -0
  45. package/src/workflows/steps/delete-product-variants-strapi.ts +31 -0
  46. package/src/workflows/steps/delete-products-strapi.ts +29 -0
  47. package/src/workflows/steps/upsert-categories-strapi.ts +84 -0
  48. package/src/workflows/steps/upsert-collections-strapi.ts +84 -0
  49. package/src/workflows/steps/upsert-product-variants-strapi.ts +83 -0
  50. package/src/workflows/steps/upsert-products-strapi.ts +81 -0
  51. package/src/workflows/upsert-categories-strapi.ts +30 -0
  52. package/src/workflows/upsert-collections-strapi.ts +30 -0
  53. package/src/workflows/upsert-product-variants-strapi.ts +30 -0
  54. package/src/workflows/upsert-products-strapi.ts +36 -0
@@ -0,0 +1,84 @@
1
+ import { ProductCategoryDTO } from "@medusajs/framework/types";
2
+ import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk";
3
+ import { STRAPI_MODULE } from "../../modules/strapi";
4
+ import StrapiModuleService from "../../modules/strapi/service";
5
+ import { Modules } from "@medusajs/framework/utils";
6
+
7
+ type EntryProps = {
8
+ documentId: string;
9
+ categoryId: string;
10
+ };
11
+
12
+ type StepInput = {
13
+ categories: ProductCategoryDTO[];
14
+ };
15
+
16
+ export const upsertCategoriesStrapiStep = createStep(
17
+ "upsert-categories-strapi-step",
18
+ async (input: StepInput, { container }) => {
19
+ const strapiModuleService: StrapiModuleService =
20
+ container.resolve(STRAPI_MODULE);
21
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
22
+
23
+ const categories: EntryProps[] = [];
24
+ const originalMetadata: Record<string, any> = {};
25
+
26
+ try {
27
+ for (const category of input.categories) {
28
+ // Store original metadata for compensation
29
+ originalMetadata[category.id] = category.metadata;
30
+
31
+ const entry = await strapiModuleService.upsertCategory(category);
32
+ await productModuleService.updateProductCategories(category.id, {
33
+ metadata: {
34
+ ...category.metadata,
35
+ strapiId: entry.documentId,
36
+ strapiSyncedAt: new Date().valueOf(),
37
+ },
38
+ });
39
+ categories.push({
40
+ documentId: entry.documentId,
41
+ categoryId: category.id,
42
+ });
43
+ }
44
+ } catch (e) {
45
+ return StepResponse.permanentFailure(
46
+ `Error creating categories in Strapi: ${e.message}`,
47
+ { categories, originalMetadata },
48
+ );
49
+ }
50
+
51
+ return new StepResponse(categories, { categories, originalMetadata });
52
+ },
53
+ async (compensateInput, { container }) => {
54
+ if (!compensateInput) return;
55
+
56
+ const { categories, originalMetadata } = compensateInput;
57
+ const strapiModuleService: StrapiModuleService =
58
+ container.resolve(STRAPI_MODULE);
59
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
60
+
61
+ // Revert metadata changes and delete created entries
62
+ for (const category of categories) {
63
+ try {
64
+ // Revert metadata to original state
65
+ if (originalMetadata[category.categoryId]) {
66
+ await productModuleService.updateProductCategories(
67
+ category.categoryId,
68
+ {
69
+ metadata: originalMetadata[category.categoryId],
70
+ },
71
+ );
72
+ }
73
+
74
+ // Delete the Strapi entry if it was created
75
+ await strapiModuleService.deleteCategory(category.categoryId);
76
+ } catch (error) {
77
+ console.error(
78
+ `Failed to compensate category ${category.categoryId}:`,
79
+ error,
80
+ );
81
+ }
82
+ }
83
+ },
84
+ );
@@ -0,0 +1,84 @@
1
+ import { ProductCollectionDTO } from "@medusajs/framework/types";
2
+ import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk";
3
+ import { STRAPI_MODULE } from "../../modules/strapi";
4
+ import StrapiModuleService from "../../modules/strapi/service";
5
+ import { Modules } from "@medusajs/framework/utils";
6
+
7
+ type EntryProps = {
8
+ documentId: string;
9
+ collectionId: string;
10
+ };
11
+
12
+ type StepInput = {
13
+ collections: ProductCollectionDTO[];
14
+ };
15
+
16
+ export const upsertCollectionStrapiStep = createStep(
17
+ "upsert-collections-strapi-step",
18
+ async (input: StepInput, { container }) => {
19
+ const strapiModuleService: StrapiModuleService =
20
+ container.resolve(STRAPI_MODULE);
21
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
22
+
23
+ const collections: EntryProps[] = [];
24
+ const originalMetadata: Record<string, any> = {};
25
+
26
+ try {
27
+ for (const collection of input.collections) {
28
+ // Store original metadata for compensation
29
+ originalMetadata[collection.id] = collection.metadata;
30
+
31
+ const entry = await strapiModuleService.upsertCollection(collection);
32
+ await productModuleService.updateProductCollections(collection.id, {
33
+ metadata: {
34
+ ...collection.metadata,
35
+ strapiId: entry.documentId,
36
+ strapiSyncedAt: new Date().valueOf(),
37
+ },
38
+ });
39
+ collections.push({
40
+ documentId: entry.documentId,
41
+ collectionId: collection.id,
42
+ });
43
+ }
44
+ } catch (e) {
45
+ return StepResponse.permanentFailure(
46
+ `Error creating collections in Strapi: ${e.message}`,
47
+ { collections, originalMetadata },
48
+ );
49
+ }
50
+
51
+ return new StepResponse(collections, { collections, originalMetadata });
52
+ },
53
+ async (compensateInput, { container }) => {
54
+ if (!compensateInput) return;
55
+
56
+ const { collections, originalMetadata } = compensateInput;
57
+ const strapiModuleService: StrapiModuleService =
58
+ container.resolve(STRAPI_MODULE);
59
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
60
+
61
+ // Revert metadata changes and delete created entries
62
+ for (const collection of collections) {
63
+ try {
64
+ // Revert metadata to original state
65
+ if (originalMetadata[collection.collectionId]) {
66
+ await productModuleService.updateProductCollections(
67
+ collection.collectionId,
68
+ {
69
+ metadata: originalMetadata[collection.collectionId],
70
+ },
71
+ );
72
+ }
73
+
74
+ // Delete the Strapi entry if it was created
75
+ await strapiModuleService.deleteCollection(collection.collectionId);
76
+ } catch (error) {
77
+ console.error(
78
+ `Failed to compensate collection ${collection.collectionId}:`,
79
+ error,
80
+ );
81
+ }
82
+ }
83
+ },
84
+ );
@@ -0,0 +1,83 @@
1
+ import { ProductVariantDTO } from "@medusajs/framework/types";
2
+ import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk";
3
+ import { STRAPI_MODULE } from "../../modules/strapi";
4
+ import StrapiModuleService from "../../modules/strapi/service";
5
+ import { Modules } from "@medusajs/framework/utils";
6
+
7
+ type EntryProps = {
8
+ documentId: string;
9
+ variantId: string;
10
+ };
11
+
12
+ type StepInput = {
13
+ variants: ProductVariantDTO[];
14
+ };
15
+
16
+ export const upsertProductVariantsStrapiStep = createStep(
17
+ "upsert-product-variants-strapi-step",
18
+ async (input: StepInput, { container }) => {
19
+ const strapiModuleService: StrapiModuleService =
20
+ container.resolve(STRAPI_MODULE);
21
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
22
+
23
+ const variants: EntryProps[] = [];
24
+ const originalMetadata: Record<string, any> = {};
25
+
26
+ try {
27
+ for (const variant of input.variants) {
28
+ // Store original metadata for compensation
29
+ originalMetadata[variant.id] = variant.metadata;
30
+
31
+ const entry = await strapiModuleService.upsertProductVariant(variant);
32
+ if (entry) {
33
+ await productModuleService.updateProductVariants(variant.id, {
34
+ metadata: {
35
+ ...variant.metadata,
36
+ strapiId: entry.documentId,
37
+ strapiSyncedAt: new Date().valueOf(),
38
+ },
39
+ });
40
+ variants.push({
41
+ documentId: entry.documentId,
42
+ variantId: variant.id,
43
+ });
44
+ }
45
+ }
46
+ } catch (e) {
47
+ return StepResponse.permanentFailure(
48
+ `Error creating variants in Strapi: ${e.message}`,
49
+ { variants, originalMetadata },
50
+ );
51
+ }
52
+
53
+ return new StepResponse(variants, { variants, originalMetadata });
54
+ },
55
+ async (compensateInput, { container }) => {
56
+ if (!compensateInput) return;
57
+
58
+ const { variants, originalMetadata } = compensateInput;
59
+ const strapiModuleService: StrapiModuleService =
60
+ container.resolve(STRAPI_MODULE);
61
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
62
+
63
+ // Revert metadata changes and delete created entries
64
+ for (const variant of variants) {
65
+ try {
66
+ // Revert metadata to original state
67
+ if (originalMetadata[variant.variantId]) {
68
+ await productModuleService.updateProductVariants(variant.variantId, {
69
+ metadata: originalMetadata[variant.variantId],
70
+ });
71
+ }
72
+
73
+ // Delete the Strapi entry if it was created
74
+ await strapiModuleService.deleteProductVariant(variant.variantId);
75
+ } catch (error) {
76
+ console.error(
77
+ `Failed to compensate variant ${variant.variantId}:`,
78
+ error,
79
+ );
80
+ }
81
+ }
82
+ },
83
+ );
@@ -0,0 +1,81 @@
1
+ import { ProductDTO } from "@medusajs/framework/types";
2
+ import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk";
3
+ import { STRAPI_MODULE } from "../../modules/strapi";
4
+ import StrapiModuleService from "../../modules/strapi/service";
5
+ import { Modules } from "@medusajs/framework/utils";
6
+
7
+ type EntryProps = {
8
+ documentId: string;
9
+ productId: string;
10
+ };
11
+
12
+ type StepInput = {
13
+ products: ProductDTO[];
14
+ };
15
+
16
+ export const upsertProductsStrapiStep = createStep(
17
+ "upsert-products-strapi-step",
18
+ async (input: StepInput, { container }) => {
19
+ const strapiModuleService: StrapiModuleService =
20
+ container.resolve(STRAPI_MODULE);
21
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
22
+
23
+ const products: EntryProps[] = [];
24
+ const originalMetadata: Record<string, any> = {};
25
+
26
+ try {
27
+ for (const product of input.products) {
28
+ // Store original metadata for compensation
29
+ originalMetadata[product.id] = product.metadata;
30
+
31
+ const entry = await strapiModuleService.upsertProduct(product);
32
+ await productModuleService.updateProducts(product.id, {
33
+ metadata: {
34
+ ...product.metadata,
35
+ strapiId: entry.documentId,
36
+ strapiSyncedAt: new Date().valueOf(),
37
+ },
38
+ });
39
+ products.push({
40
+ documentId: entry.documentId,
41
+ productId: product.id,
42
+ });
43
+ }
44
+ } catch (e) {
45
+ return StepResponse.permanentFailure(
46
+ `Error creating products in Strapi: ${e.message}`,
47
+ { products, originalMetadata },
48
+ );
49
+ }
50
+
51
+ return new StepResponse(products, { products, originalMetadata });
52
+ },
53
+ async (compensateInput, { container }) => {
54
+ if (!compensateInput) return;
55
+
56
+ const { products, originalMetadata } = compensateInput;
57
+ const strapiModuleService: StrapiModuleService =
58
+ container.resolve(STRAPI_MODULE);
59
+ const productModuleService = container.resolve(Modules.PRODUCT) as any;
60
+
61
+ // Revert metadata changes and delete created entries
62
+ for (const product of products) {
63
+ try {
64
+ // Revert metadata to original state
65
+ if (originalMetadata[product.productId]) {
66
+ await productModuleService.updateProducts(product.productId, {
67
+ metadata: originalMetadata[product.productId],
68
+ });
69
+ }
70
+
71
+ // Delete the Strapi entry if it was created
72
+ await strapiModuleService.deleteProduct(product.productId);
73
+ } catch (error) {
74
+ console.error(
75
+ `Failed to compensate product ${product.productId}:`,
76
+ error,
77
+ );
78
+ }
79
+ }
80
+ },
81
+ );
@@ -0,0 +1,30 @@
1
+ import { ProductCategoryDTO } from "@medusajs/framework/types";
2
+ import {
3
+ createWorkflow,
4
+ WorkflowResponse,
5
+ } from "@medusajs/framework/workflows-sdk";
6
+ import { useQueryGraphStep } from "@medusajs/core-flows";
7
+ import { upsertCategoriesStrapiStep } from "./steps/upsert-categories-strapi";
8
+
9
+ type WorkflowInput = {
10
+ category_ids: string[];
11
+ };
12
+
13
+ export const upsertCategoriesStrapiWorkflow = createWorkflow(
14
+ { name: "upsert-categories-strapi-workflow" },
15
+ (input: WorkflowInput) => {
16
+ const { data } = useQueryGraphStep({
17
+ entity: "product_category",
18
+ fields: ["id", "name", "handle", "metadata"],
19
+ filters: {
20
+ id: input.category_ids,
21
+ },
22
+ });
23
+
24
+ const strapiCategories = upsertCategoriesStrapiStep({
25
+ categories: data as ProductCategoryDTO[],
26
+ });
27
+
28
+ return new WorkflowResponse(strapiCategories);
29
+ },
30
+ );
@@ -0,0 +1,30 @@
1
+ import { ProductCollectionDTO } from "@medusajs/framework/types";
2
+ import {
3
+ createWorkflow,
4
+ WorkflowResponse,
5
+ } from "@medusajs/framework/workflows-sdk";
6
+ import { useQueryGraphStep } from "@medusajs/core-flows";
7
+ import { upsertCollectionStrapiStep } from "./steps/upsert-collections-strapi";
8
+
9
+ type WorkflowInput = {
10
+ collection_ids: string[];
11
+ };
12
+
13
+ export const upsertCollectionsStrapiWorkflow = createWorkflow(
14
+ { name: "upsert-collection-strapi-workflow" },
15
+ (input: WorkflowInput) => {
16
+ const { data } = useQueryGraphStep({
17
+ entity: "product_collection",
18
+ fields: ["id", "title", "handle", "metadata"],
19
+ filters: {
20
+ id: input.collection_ids,
21
+ },
22
+ });
23
+
24
+ const strapiCollections = upsertCollectionStrapiStep({
25
+ collections: data as ProductCollectionDTO[],
26
+ });
27
+
28
+ return new WorkflowResponse(strapiCollections);
29
+ },
30
+ );
@@ -0,0 +1,30 @@
1
+ import { ProductVariantDTO } from "@medusajs/framework/types";
2
+ import {
3
+ createWorkflow,
4
+ WorkflowResponse,
5
+ } from "@medusajs/framework/workflows-sdk";
6
+ import { useQueryGraphStep } from "@medusajs/core-flows";
7
+ import { upsertProductVariantsStrapiStep } from "./steps/upsert-product-variants-strapi";
8
+
9
+ type WorkflowInput = {
10
+ variant_ids: string[];
11
+ };
12
+
13
+ export const upsertProductVariantsStrapiWorkflow = createWorkflow(
14
+ { name: "upsert-product-variants-strapi-workflow" },
15
+ (input: WorkflowInput) => {
16
+ const { data } = useQueryGraphStep({
17
+ entity: "product_variant",
18
+ fields: ["id", "title", "sku", "product_id", "metadata"],
19
+ filters: {
20
+ id: input.variant_ids,
21
+ },
22
+ });
23
+
24
+ const strapiVariants = upsertProductVariantsStrapiStep({
25
+ variants: data as ProductVariantDTO[],
26
+ });
27
+
28
+ return new WorkflowResponse(strapiVariants);
29
+ },
30
+ );
@@ -0,0 +1,36 @@
1
+ import { ProductDTO } from "@medusajs/framework/types";
2
+ import {
3
+ createWorkflow,
4
+ WorkflowResponse,
5
+ } from "@medusajs/framework/workflows-sdk";
6
+ import { useQueryGraphStep } from "@medusajs/core-flows";
7
+ import { upsertProductsStrapiStep } from "./steps/upsert-products-strapi";
8
+
9
+ type WorkflowInput = {
10
+ product_ids: string[];
11
+ };
12
+
13
+ export const upsertProductsStrapiWorkflow = createWorkflow(
14
+ { name: "upsert-products-strapi-workflow" },
15
+ (input: WorkflowInput) => {
16
+ const { data } = useQueryGraphStep({
17
+ entity: "product",
18
+ fields: [
19
+ "id",
20
+ "title",
21
+ "type.value",
22
+ "status",
23
+ "handle",
24
+ "variants.*",
25
+ "metadata",
26
+ ],
27
+ filters: { id: input.product_ids },
28
+ });
29
+
30
+ const strapiProducts = upsertProductsStrapiStep({
31
+ products: data as ProductDTO[],
32
+ });
33
+
34
+ return new WorkflowResponse(strapiProducts);
35
+ },
36
+ );