@rytass/wms-module-graphql 0.1.3 → 0.1.5

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.
@@ -68,6 +68,24 @@ The reference consumer ([`wms-standalone`](#13-reference-implementation-wms-stan
68
68
 
69
69
  The frontend package (`wms-module-react`) is **ESM-only** (`"type": "module"`). Bundlers that target Next.js / Vite / webpack 5 handle this transparently; classic CJS-only Node tools do not.
70
70
 
71
+ ### 2.1 pnpm build-script approval
72
+
73
+ If you are on **pnpm 9 or newer**, the first `pnpm install` will refuse to run native build scripts for several transitive dependencies and surface `ERR_PNPM_IGNORED_BUILDS`. This is pnpm's supply-chain protection, not a WMS issue, but it is the very first error a fresh integrator hits.
74
+
75
+ Resolve it once by approving the packages WMS transitively needs to build:
76
+
77
+ ```bash
78
+ pnpm approve-builds
79
+ # Or, in pnpm-workspace.yaml:
80
+ # allowBuilds:
81
+ # '@apollo/protobufjs': true
82
+ # '@nestjs/core': true
83
+ # '@parcel/watcher': true
84
+ # sharp: true
85
+ ```
86
+
87
+ After approval, `pnpm install` completes cleanly. The exact list pnpm asks you to approve depends on your other dependencies; the four above are the ones triggered by WMS's NestJS + Apollo + native-image stack.
88
+
71
89
  ---
72
90
 
73
91
  ## 3. Quick start (60 seconds)
@@ -78,7 +96,7 @@ mkdir my-wms && cd my-wms
78
96
  pnpm init
79
97
  pnpm add @rytass/wms-module-core @rytass/wms-module-graphql @rytass/wms-module-react
80
98
  pnpm add @nestjs/common @nestjs/core @nestjs/graphql @nestjs/typeorm \
81
- @nestjs/apollo @nestjs/config @nestjs/platform-express @apollo/server@^4 \
99
+ @nestjs/apollo@~13.1.0 @nestjs/config @nestjs/platform-express @apollo/server@^4 \
82
100
  typeorm pg reflect-metadata graphql rxjs \
83
101
  class-transformer class-validator \
84
102
  @as-integrations/express5
@@ -191,8 +209,52 @@ What you get from this single `forRootAsync`:
191
209
  - DataLoader N+1 prevention across every resolveField
192
210
  - Default seed rows (DEFAULT location, DEFAULT loaderType, DEFAULT loader) on first boot
193
211
 
212
+ **`forRootAsync` TypeScript signature**:
213
+
214
+ ```ts
215
+ WmsModuleGraphqlModule.forRootAsync(
216
+ options: WmsModuleCoreModuleAsyncOptions,
217
+ gqlOptions: GqlModuleAsyncOptions<ApolloDriverConfig>,
218
+ ): DynamicModule
219
+ ```
220
+
221
+ > Note the **two positional arguments**. A common mistake is to pass a single options object
222
+ > (matching NestJS's typical convention) which produces a misleading
223
+ > `TypeError: Cannot read properties of undefined (reading 'imports')` from inside the lib.
224
+ > The first arg configures the WMS core module (seed defaults, async factory, etc.); the
225
+ > second arg configures the underlying NestJS GraphQL module (driver, autoSchemaFile, plugins).
226
+
194
227
  See [API Reference - wms-module-graphql](./api-reference.md) for the full `forRootAsync` signature.
195
228
 
229
+ ### Adding your own resolvers alongside WMS
230
+
231
+ `WmsModuleGraphqlModule` calls `GraphQLModule.forRootAsync(...)` internally — that registration is workspace-global, so you cannot register a second `GraphQLModule` (see §13.1). What you **can** do is put your own resolvers in **sibling NestJS modules** imported in `AppModule`:
232
+
233
+ ```ts
234
+ // apps/api/src/modules/posts/posts.module.ts
235
+ import { Module } from '@nestjs/common';
236
+ import { TypeOrmModule } from '@nestjs/typeorm';
237
+ import { Post } from './post.entity';
238
+ import { PostResolver } from './post.resolver';
239
+
240
+ @Module({
241
+ imports: [TypeOrmModule.forFeature([Post])],
242
+ providers: [PostResolver],
243
+ })
244
+ export class PostsModule {}
245
+
246
+ // apps/api/src/app/app.module.ts
247
+ @Module({
248
+ imports: [
249
+ /* ... TypeOrm, Config, WmsModuleGraphqlModule ... */
250
+ PostsModule, // your sibling module
251
+ ],
252
+ })
253
+ export class AppModule {}
254
+ ```
255
+
256
+ NestJS's GraphQL module discovers every `@Resolver()` class from every imported module via DI and merges them into the **same** schema. So your `Post`/`User` resolvers coexist in one schema with the WMS resolvers automatically — no extra wiring needed. The §13.1 "one GraphQLModule" constraint only forbids a second `GraphQLModule.forRoot(...)` registration, not additional resolvers.
257
+
196
258
  ### 4.3 `.env`
197
259
 
198
260
  Keep DB credentials in `.env` (and add it to `.gitignore`).
@@ -284,7 +346,7 @@ Tested combinations as of 0.1.2:
284
346
  |----------------------------------|-------------------------|--------------------------------------------------------------------|
285
347
  | NestJS (`@nestjs/*`) | 11.x | 10.x untested; some Express-5-related APIs differ |
286
348
  | `@nestjs/graphql` | 13.x | Required for `@nestjs/apollo@13` |
287
- | `@nestjs/apollo` | 13.x | Pairs with Apollo Server 4 + Express 5 |
349
+ | `@nestjs/apollo` | 13.0.x – 13.1.x | 13.2+ requires @apollo/server@^5 which breaks lib's v4 plugin usage |
288
350
  | `@apollo/server` | 4.x | v5 is breaking; not supported |
289
351
  | `@as-integrations/express5` | 1.x | Required runtime peer |
290
352
  | TypeORM | 0.3.x | 0.2.x not supported (different DataSource API) |
@@ -1072,11 +1134,17 @@ logic. Any field set on `req` by a NestJS guard or Passport strategy (e.g. `req.
1072
1134
  therefore accessible from resolvers as `ctx.req.user`.
1073
1135
 
1074
1136
  > **Why returning `context` from `gqlOptions.useFactory` does not work**: the lib's
1075
- > `forRootAsync` calls `gqlOptions.useFactory(…)` to collect your Apollo options, then
1076
- > unconditionally replaces the `context` key with its own factory that injects DataLoaders
1077
- > (`{ loaders, ...contextArg }`). Any `context` you return from `useFactory` is silently
1078
- > dropped. The resulting GraphQL context is always `{ req, res, loaders }` — there is no
1079
- > `user` key.
1137
+ > internal context factory replaces any `context` key you return from `gqlOptions.useFactory`,
1138
+ > but it spreads the raw `contextArg` (the `{ req, res }` provided by Apollo Server). So:
1139
+ >
1140
+ > | Approach | Works? |
1141
+ > |----------------------------------------------------|--------|
1142
+ > | Return `context: () => ({ user })` from useFactory | ❌ overridden |
1143
+ > | Populate `req.user` via NestJS guard / Passport | ✅ access via `context.req.user` |
1144
+ >
1145
+ > Always populate identity onto `req` (via a guard) and read it as `context.req.user` in
1146
+ > your resolvers. The resulting GraphQL context is `{ req, res, loaders }` — `req.user` IS
1147
+ > accessible as long as a guard or middleware has set it on the request object.
1080
1148
 
1081
1149
  To access the authenticated user in a **custom** resolver, populate `req.user` in a guard
1082
1150
  or middleware and read it from `ctx.req.user`:
@@ -1267,6 +1335,13 @@ function WmsLayout({ children }: { children: ReactNode }): ReactNode {
1267
1335
  }
1268
1336
  ```
1269
1337
 
1338
+ > **Critical constraint**: WMS page components use the `NextPath` enum for all internal
1339
+ > navigation (`router.push(NextPath.MATERIALSMANAGEMENT)` etc.). Enum values are hardcoded
1340
+ > root-level paths (`/materials-management`, `/inventory-list`, etc.). **WMS pages cannot be
1341
+ > mounted under a custom path prefix like `/wms/*`** — internal links will break even though
1342
+ > the pages initially render. If your existing project requires path prefixing, you must mount
1343
+ > WMS at the root of a separate domain or subdomain.
1344
+
1270
1345
  The lib's page components do not require the WMS navigation shell to be present — they only
1271
1346
  require the three providers (§13.7) and an Apollo client (§13.6). You can completely replace
1272
1347
  the navigation chrome with your own.
@@ -1495,6 +1570,40 @@ creating a new monorepo. Key points:
1495
1570
  `@rytass/wms-module-*` package names, ensure they point to `node_modules` (the installed
1496
1571
  package), not local source, to avoid confusion.
1497
1572
 
1573
+ ### 13.13.1 pnpm peer-dep multi-instantiation hazard
1574
+
1575
+ When a pnpm workspace contains apps that resolve `@nestjs/core` (or other peers
1576
+ of `@rytass/wms-module-core`) to different major versions, pnpm creates one
1577
+ **instance** of `@rytass/wms-module-core` per unique peer resolution. Both
1578
+ instances register their TypeORM entity decorators against the same global
1579
+ `getMetadataArgsStorage()`, producing:
1580
+
1581
+ ```
1582
+ TypeError: Cannot read properties of undefined (reading 'ownColumns')
1583
+ at EntityMetadataBuilder.ts:548
1584
+ ```
1585
+
1586
+ **Required workaround**: every workspace app that imports `@rytass/wms-module-core`
1587
+ (directly or transitively via `@rytass/wms-module-graphql`) must resolve to the
1588
+ same `@nestjs/*` major version. Options:
1589
+
1590
+ 1. Upgrade the entire workspace to a single NestJS major (preferred)
1591
+ 2. Force pnpm to deduplicate the WMS module instance:
1592
+
1593
+ ```yaml
1594
+ # pnpm-workspace.yaml
1595
+ overrides:
1596
+ '@rytass/wms-module-core': '0.1.4'
1597
+ ```
1598
+
1599
+ 3. Apply `public-hoist-pattern[]` for `@rytass/wms-module-*` in `.npmrc`
1600
+
1601
+ This is a structural limitation of the pnpm peer-resolution model combined
1602
+ with TypeORM's global metadata storage; the WMS lib cannot deduplicate
1603
+ itself without rewriting TypeORM's entity registry. Yarn 4 and npm 10 do not
1604
+ hit this because their hoisting strategies differ — pnpm with strict mode is
1605
+ the only affected case.
1606
+
1498
1607
  ---
1499
1608
 
1500
1609
  ### 13.14 GraphQL Type Name Conflicts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rytass/wms-module-graphql",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Rytass WMS Module — GraphQL schema, resolvers and DTOs for warehouse management",
5
5
  "keywords": [
6
6
  "rytass",
@@ -46,10 +46,10 @@
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@as-integrations/express5": "^1.0.0",
49
- "@nestjs/apollo": "^13.0.0",
49
+ "@nestjs/apollo": ">=13.0.0 <13.2.0",
50
50
  "@nestjs/common": "^11.0.0",
51
51
  "@nestjs/graphql": "^13.0.0",
52
- "@rytass/wms-module-core": "^0.1.3",
52
+ "@rytass/wms-module-core": "^0.1.5",
53
53
  "graphql": "^16.0.0",
54
54
  "reflect-metadata": "^0.1.13 || ^0.2.0",
55
55
  "rxjs": "^7.8.0"