@medusajs/link-modules 2.22.0-snapshot-20261021091347 → 2.22.0

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 (3) hide show
  1. package/AGENTS.md +65 -0
  2. package/README.md +71 -0
  3. package/package.json +8 -4
package/AGENTS.md ADDED
@@ -0,0 +1,65 @@
1
+ # @medusajs/link-modules
2
+
3
+ Link Modules (`Modules.LINK` = `"link_modules"`): defines Medusa's built-in module links (the pivot tables and read-only relations between commerce modules) and turns every link definition, core or app-level, into a small generated "link module" with its own table and service.
4
+
5
+ ## Using this package
6
+
7
+ - Applications never register it. `MedusaApp` (`packages/core/modules-sdk/src/medusa-app.ts`, `initializeLinks`) dynamically imports `@medusajs/medusa/link-modules` and calls `initialize(config, linkModules, ...)`, where `linkModules` = core definitions plus every `defineLink` from the app and plugins (`MedusaModule.getCustomLinks()`).
8
+ - Work with links through `ContainerRegistrationKeys.LINK` (`link.create/dismiss/delete/restore`) and Query, not through this package. Workflows: `createRemoteLinkStep` / `dismissRemoteLinkStep` in `@medusajs/core-flows`.
9
+ - Link tables are created by `npx medusa db:migrate` (unless `--skip-links`) or `npx medusa db:sync-links` (`--execute-safe`, `--execute-all`), not by MikroORM migrations.
10
+
11
+ Docs: https://docs.medusajs.com/learn/fundamentals/module-links.md, https://docs.medusajs.com/learn/fundamentals/module-links/link.md, https://docs.medusajs.com/learn/fundamentals/module-links/custom-columns.md, https://docs.medusajs.com/learn/fundamentals/module-links/read-only.md
12
+
13
+ ## Built-in links vs app-level `defineLink`
14
+
15
+ Core links live in `src/definitions/*.ts` as raw `ModuleJoinerConfig` objects (`isLink: true`), exported from `src/definitions/index.ts`:
16
+
17
+ ```ts
18
+ export const ProductVariantInventoryItem: ModuleJoinerConfig = {
19
+ serviceName: LINKS.ProductVariantInventoryItem,
20
+ isLink: true,
21
+ databaseConfig: {
22
+ tableName: "product_variant_inventory_item",
23
+ idPrefix: "pvitem",
24
+ extraFields: { required_quantity: { type: "decimal", defaultValue: "1" } },
25
+ },
26
+ primaryKeys: ["id", "variant_id", "inventory_item_id"],
27
+ relationships: [/* exactly 2: { serviceName, entity, primaryKey, foreignKey, alias, args } */],
28
+ extends: [/* adds `inventory_items` to ProductVariant, `variant_link` to InventoryItem */],
29
+ }
30
+ ```
31
+
32
+ - Hand-written: explicit `tableName` (e.g. `product_variant_price_set`), `idPrefix`, `alias`, `fieldAlias` shortcuts (e.g. `variant.inventory` -> `inventory_items.inventory`), `deleteCascade`, `isList`. `serviceName` comes from the `LINKS` map in `packages/core/utils/src/link/links.ts`.
33
+ - `defineLink(a, b, options)` (`packages/core/utils/src/modules-sdk/define-link.ts`) generates the same `ModuleJoinerConfig` from data model references: `serviceName` = `composeLinkName(...)`, table name from `composeTableName(moduleA, keyA, moduleB, keyB)`, entry point `<aliasA>_<aliasB>`, validation of primary keys, plus `database.extraColumns`, `filterable` (Index Module) and `readOnly`. Both feed into the same `initialize()`.
34
+ - Read-only links (`src/definitions/readonly/`, `isReadOnlyLink: true`) have no table: they only `extends` an entity with a relation resolved through an existing foreign key column (e.g. `OrderLineItem.product_id` -> `Product`, `Cart.region_id` -> `Region`, `Store.currency_code` -> `Currency`).
35
+
36
+ Pivot tables defined here: `cart_payment_collection`, `cart_promotion`, `customer_account_holder`, `location_fulfillment_provider`, `location_fulfillment_set`, `invite_rbac_role`, `user_rbac_role`, `order_cart`, `order_fulfillment`, `order_payment_collection`, `order_promotion`, `return_fulfillment`, `product_sales_channel`, `product_shipping_profile`, `product_variant_inventory_item`, `product_variant_price_set`, `publishable_api_key_sales_channel`, `region_payment_provider`, `sales_channel_stock_location`, `shipping_option_price_set`.
37
+
38
+ ## Architecture
39
+
40
+ - `src/initialize/index.ts` `initialize()`: for each definition, validates exactly 2 relationships (non-read-only), non-composite foreign key, `extraDataFields` present in `databaseConfig.extraFields`; skips the link if either module is not loaded (read-only links keep only extensions whose modules are loaded); builds a GraphQL schema (`src/utils/generate-schema.ts`) and boots it via `MedusaModule.bootstrapLink` with an EVENT_BUS dependency. Read-only links are keyed by a hash of `extends`.
41
+ - `src/utils/generate-entity.ts`: MikroORM `EntitySchema` per link: composite PK on the two foreign keys, `id`, extra fields, `created_at`/`updated_at`/`deleted_at`, partial indexes `WHERE deleted_at IS NULL`.
42
+ - `src/services/link-module-service.ts` (`getModuleService`): `list/listAndCount/retrieve/create/dismiss/delete/softDelete/restore`; emits `<entityName>.attached` on create/restore and `<entityName>.detached` on dismiss/delete/softDelete.
43
+ - `src/migration/index.ts` `MigrationsExecutionPlanner`: tracks tables in `link_module_migrations`, plans `create` / `update` / `delete` / `noop` / `notify` per link, renames tables whose name changed for the same from/to models, and runs under Postgres advisory locks.
44
+
45
+ ## Development
46
+
47
+ ```bash
48
+ cd packages/modules/link-modules
49
+ yarn build
50
+ yarn test # src/migration/__tests__
51
+ yarn test:integration # needs Postgres
52
+ ../../../node_modules/.bin/jest integration-tests/__tests__/migrations.spec.ts
53
+ ```
54
+
55
+ - No `migration:create` script and no models: schema changes come from editing a definition, applied by `db:sync-links`.
56
+ - Integration tests: `integration-tests/__tests__/migrations.spec.ts`, `rename-migration.spec.ts`.
57
+ - New core link: add the file in `src/definitions/`, add a `LINKS` entry in `packages/core/utils/src/link/links.ts`, and export it from `src/definitions/index.ts`.
58
+
59
+ ## Gotchas
60
+
61
+ - A definition that is not exported from `src/definitions/index.ts` is never loaded. `order-claim-payment-collection.ts` and `order-exchange-payment-collection.ts` currently exist but are not exported.
62
+ - Any SQL diff containing `alter column` or `drop column` becomes a `notify` action and is never applied automatically; `executePlan` skips `noop` and `notify` unless the action is changed to `update` (`db:sync-links --execute-all` does that).
63
+ - Removing a link definition plans a `delete` (DROP TABLE) for its tracked table: `db:sync-links` prompts for it, `--execute-all` drops it, `--execute-safe` skips it.
64
+ - `initialize()` errors are caught in `MedusaApp` and only logged as "Error initializing link modules."; `remoteLink` is then undefined.
65
+ - Duplicate service keys throw "Link module ... already defined."
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ <p align="center">
2
+ <a href="https://www.medusajs.com">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/59018053/229103275-b5e482bb-4601-46e6-8142-244f531cebdb.svg">
5
+ <source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
6
+ <img alt="Medusa logo" src="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
7
+ </picture>
8
+ </a>
9
+ </p>
10
+ <h1 align="center">
11
+ @medusajs/link-modules
12
+ </h1>
13
+
14
+ <h4 align="center">
15
+ <a href="https://docs.medusajs.com">Documentation</a> |
16
+ <a href="https://www.medusajs.com">Website</a>
17
+ </h4>
18
+
19
+ <p align="center">
20
+ Building blocks for digital commerce
21
+ </p>
22
+ <p align="center">
23
+ <a href="https://github.com/medusajs/medusa/blob/develop/LICENSE">
24
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Medusa is released under the MIT license." />
25
+ </a>
26
+ <a href="https://github.com/medusajs/medusa/blob/develop/CONTRIBUTING.md">
27
+ <img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="PRs welcome!" />
28
+ </a>
29
+ <a href="https://discord.gg/xpCwq3Kfn8">
30
+ <img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
31
+ </a>
32
+ <a href="https://twitter.com/intent/follow?screen_name=medusajs">
33
+ <img src="https://img.shields.io/twitter/follow/medusajs.svg?label=Follow%20@medusajs" alt="Follow @medusajs" />
34
+ </a>
35
+ </p>
36
+
37
+ Link Modules for Medusa: creates and manages the tables that store module links, the relationships between data models of different modules (for example, a product and its sales channels). It contains Medusa's built-in link definitions and also loads the links you define with `defineLink`. Medusa loads it automatically; apps don't install, register, or call this package directly, and instead manage links with the `Link` tool (`ContainerRegistrationKeys.LINK`) and retrieve linked data with Query.
38
+
39
+ ## At a glance
40
+
41
+ | | |
42
+ | --- | --- |
43
+ | Package | `@medusajs/link-modules` |
44
+ | Type | Infrastructure Module |
45
+ | Module key | `Modules.LINK` (`"link_modules"`) |
46
+ | Registered by default | Yes (always loaded by the Medusa application) |
47
+
48
+ ## Installation
49
+
50
+ No installation needed. The package ships with `@medusajs/medusa`.
51
+
52
+ ## Usage
53
+
54
+ Define a link in your application, then run `npx medusa db:migrate` to create its table:
55
+
56
+ ```ts
57
+ import BrandModule from "../modules/brand"
58
+ import ProductModule from "@medusajs/medusa/product"
59
+ import { defineLink } from "@medusajs/framework/utils"
60
+
61
+ export default defineLink(
62
+ ProductModule.linkable.product,
63
+ BrandModule.linkable.brand
64
+ )
65
+ ```
66
+
67
+ ## Resources
68
+
69
+ - [Module Links](https://docs.medusajs.com/learn/fundamentals/module-links)
70
+ - [Link](https://docs.medusajs.com/learn/fundamentals/module-links/link)
71
+ - [Query](https://docs.medusajs.com/learn/fundamentals/query)
package/package.json CHANGED
@@ -1,15 +1,19 @@
1
1
  {
2
2
  "name": "@medusajs/link-modules",
3
- "version": "2.22.0-snapshot-20261021091347",
3
+ "version": "2.22.0",
4
4
  "description": "Medusa Default Link Modules Package and Definitions",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
8
8
  "dist",
9
+ "AGENTS.md",
9
10
  "!dist/**/__tests__",
10
11
  "!dist/**/__mocks__",
11
12
  "!dist/**/__fixtures__"
12
13
  ],
14
+ "llms": "https://docs.medusajs.com/llms.txt",
15
+ "llmsFull": "https://docs.medusajs.com/llms-full.txt",
16
+ "mcpServer": "https://docs.medusajs.com/mcp",
13
17
  "repository": {
14
18
  "type": "git",
15
19
  "url": "git+https://github.com/medusajs/medusa.git",
@@ -36,10 +40,10 @@
36
40
  "test:integration": "../../../node_modules/.bin/jest --passWithNoTests --forceExit --testPathPattern=\"integration-tests/__tests__/.*\\.ts\""
37
41
  },
38
42
  "devDependencies": {
39
- "@medusajs/framework": "2.22.0-snapshot-20261021091347",
40
- "@medusajs/test-utils": "2.22.0-snapshot-20261021091347"
43
+ "@medusajs/framework": "2.22.0",
44
+ "@medusajs/test-utils": "2.22.0"
41
45
  },
42
46
  "peerDependencies": {
43
- "@medusajs/framework": "2.22.0-snapshot-20261021091347"
47
+ "@medusajs/framework": "2.22.0"
44
48
  }
45
49
  }