@lenne.tech/nest-server 11.29.0 → 11.29.1

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.
@@ -4,7 +4,7 @@ This document defines the rules for managing dependencies in package.json.
4
4
 
5
5
  ## Package Manager: pnpm
6
6
 
7
- This project uses **pnpm** for development. The `packageManager` field in `package.json` ensures the correct version is used (via Corepack).
7
+ This project uses **pnpm** for development. The `packageManager` field in `package.json` pins the exact version and is the single source of truth — pnpm itself follows it (`managePackageManagerVersions`, on by default since pnpm 10), so no Corepack is involved. See [The pnpm pin contract](#the-pnpm-pin-contract-packagemanager-as-single-source-of-truth).
8
8
 
9
9
  ```bash
10
10
  # Install dependencies
@@ -99,7 +99,7 @@ The `pnpm-lock.yaml` file must always be committed. It provides additional repro
99
99
 
100
100
  ## Package Manager: pnpm 11
101
101
 
102
- This repo is pinned to **pnpm 11** via the `packageManager` field (corepack/`pnpm/action-setup` follow it, so CI and Docker use it automatically — no version is hardcoded anywhere else).
102
+ This repo is pinned to **pnpm 11** via the `packageManager` field — see [The pnpm pin contract](#the-pnpm-pin-contract-packagemanager-as-single-source-of-truth) for how CI and Docker consume it without corepack.
103
103
 
104
104
  pnpm 11 **no longer reads the `pnpm` field in `package.json`**, and `.npmrc` is auth/registry only. All pnpm-specific settings live in **`pnpm-workspace.yaml`**:
105
105
 
@@ -109,6 +109,61 @@ pnpm 11 **no longer reads the `pnpm` field in `package.json`**, and `.npmrc` is
109
109
 
110
110
  `pnpm audit`: pnpm 10.x is broken (npm retired the legacy audit endpoint → HTTP 410); pnpm 11 uses the working bulk-advisory endpoint. `scripts/check.mjs` degrades the retired-endpoint failure to a non-blocking warning as a safety net, so `check` stays green + honest even if a future endpoint change lands.
111
111
 
112
+ ## The pnpm pin contract: `packageManager` as single source of truth
113
+
114
+ **Rule: the pnpm version is pinned in exactly one place — `package.json#packageManager`. Nothing may hardcode it, and nothing may rely on corepack.**
115
+
116
+ ```jsonc
117
+ {
118
+ "packageManager": "pnpm@11.13.1+sha512.b2fc7683…", // THE pin: exact, with integrity hash
119
+ "engines": { "node": ">= 22", "pnpm": "^11.0.0" } // soft major gate — NOT a pin
120
+ }
121
+ ```
122
+
123
+ **Corepack is not part of this contract.** It used to be the thing that read `packageManager`, but **Node >= 25 no longer ships it** — a build stage running `corepack enable` on such an image dies with `corepack: not found`. Nothing here needs it: pnpm follows the field itself (`managePackageManagerVersions`, on by default since pnpm 10), and `pnpm/action-setup` reads it directly.
124
+
125
+ ### How each consumer gets the pinned pnpm
126
+
127
+ | Consumer | Mechanism |
128
+ |----------|-----------|
129
+ | Local dev | pnpm self-switches to the pinned version (`managePackageManagerVersions`) |
130
+ | GitHub Actions | `pnpm/action-setup@v6` with **no** `version:` input — it reads `packageManager` |
131
+ | Docker / other CI | the derive-line (below), once per pnpm-running stage |
132
+
133
+ ### The derive-line
134
+
135
+ ```dockerfile
136
+ # Provision the exact pnpm declared in package.json (single source of truth).
137
+ # No corepack: Node >= 25 no longer ships it. The +sha512 suffix is stripped;
138
+ # npm enforces registry integrity for the tarball itself.
139
+ RUN npm install -g "$(node -p "require('./package.json').packageManager.split('+')[0]")"
140
+ ```
141
+
142
+ `.split('+')[0]` reduces `pnpm@11.13.1+sha512.…` to the plain spec `npm install -g` accepts. Dropping the hash does not weaken integrity — npm verifies the tarball against the registry's own metadata.
143
+
144
+ Two ordering rules, both enforced by the contract test:
145
+
146
+ 1. It must run **after** the `COPY` that puts `package.json` in the WORKDIR — it reads that file.
147
+ 2. It must be repeated in **every** stage that runs `pnpm`. A global install in `deps` does not survive into `builder`; stages inherit only what is explicitly `COPY --from=`'d.
148
+
149
+ ### Rules
150
+
151
+ | Rule | Why |
152
+ |------|-----|
153
+ | `packageManager` is exact (`x.y.z+sha512.<hash>`), never a range | Same fixed-version rule as dependencies; corepack rejects ranges outright |
154
+ | `engines.pnpm` tracks the pin's major (`^<major>.0.0`) | A soft gate that warns pnpm 10 users. It is not a pin and cannot tell CI what to install |
155
+ | Never declare `devEngines.packageManager` | npm/npx abort with `EBADDEVENGINES`; corepack rejects ranges inside it |
156
+ | Never pass `version:` to `pnpm/action-setup` | Two sources drift; the action hard-errors on a mismatch |
157
+ | Never `RUN corepack …` | Absent on Node >= 25 |
158
+ | Never `npm install -g pnpm@<literal>` | That is a second pin — derive it instead |
159
+ | Monorepo: pin at the **workspace root** | The derive-line reads `/app/package.json`, which in monorepo mode (`API_DIR=projects/api`) is the root manifest. Missing there → `TypeError: Cannot read properties of undefined (reading 'split')` |
160
+
161
+ ### Enforcement
162
+
163
+ `tests/unit/pnpm-pin-contract.spec.ts` asserts every rule above structurally (unit suite, no network), so a re-introduced `with: version: 11` or a stray `corepack enable` fails the build rather than drifting silently. A twelfth test proves the chain functionally — derive the spec, `npm install -g` it into a throwaway prefix, assert the binary reports the pinned version. It needs network + ~10 MB and is gated to `CI` / `PIN_PROVISION_TEST=1`.
164
+
165
+ **When bumping pnpm:** run `pnpm self-update` (writes the field with a fresh hash), align `engines.pnpm` if the major moved, and commit `package.json` + `pnpm-lock.yaml` together. Nothing else needs touching — that is the point.
166
+
112
167
  ## Overrides
113
168
 
114
169
  Package overrides live in the `overrides:` section of **`pnpm-workspace.yaml`** (they moved out of `package.json`'s `pnpm.overrides` in the pnpm 11 upgrade). They force transitive dependencies to a security-patched version.
package/FRAMEWORK-API.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @lenne.tech/nest-server — Framework API Reference
2
2
 
3
- > Auto-generated from source code on 2026-07-16 (v11.29.0)
3
+ > Auto-generated from source code on 2026-07-17 (v11.29.1)
4
4
  > File: `FRAMEWORK-API.md` — compact, machine-readable API surface for Claude Code
5
5
 
6
6
  ## CoreModule.forRoot()
@@ -0,0 +1,311 @@
1
+ # Migration Guide: 11.29.0 → 11.29.1
2
+
3
+ ## Overview
4
+
5
+ | Category | Details |
6
+ |----------|---------|
7
+ | **Breaking Changes** | None |
8
+ | **Bugfixes** | None — no runtime code changed. `src/core/` is byte-identical to 11.29.0. |
9
+ | **New Features** | None |
10
+ | **Maintenance** | **Toolchain only.** `package.json#packageManager` is restored as the *single* place the pnpm version is pinned. `corepack` is gone from the `Dockerfile` (Node >= 25 no longer ships it); every pnpm-running build stage now provisions the pinned pnpm itself. `pnpm/action-setup` reads the pin instead of carrying its own `version` input. A contract test (`tests/unit/pnpm-pin-contract.spec.ts`) guards the whole chain. |
11
+ | **Migration Effort** | **0 minutes for npm-mode and vendor-mode consumers** — nothing in your project changes. **~10 minutes if you adopt the pattern**, which you should do *before* moving any build to Node >= 25. |
12
+
13
+ This release changes **how the framework repo builds itself**. It ships no API change, no
14
+ configuration change, and no behavioral change. Update with `pnpm add @lenne.tech/nest-server@11.29.1`
15
+ and you are done.
16
+
17
+ The reason to read further: **the `Dockerfile` is not part of the npm package** (it is not in
18
+ `package.json#files`). Your project's own `Dockerfile` and CI came from the starter template, so you
19
+ do **not** inherit this fix automatically. If they still run `corepack enable`, they will break the
20
+ day you move to Node >= 25 — see [Adopting the pattern](#adopting-the-pattern-in-your-project-recommended).
21
+
22
+ ---
23
+
24
+ ## Quick Migration (npm mode)
25
+
26
+ No code changes required.
27
+
28
+ ```bash
29
+ # Update the package
30
+ pnpm add @lenne.tech/nest-server@11.29.1
31
+
32
+ # Verify
33
+ pnpm run build
34
+ pnpm test
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Why this release exists: corepack is going away
40
+
41
+ `corepack` was the mechanism that read `package.json#packageManager` and materialized the right
42
+ package-manager binary. It shipped with Node for years, which is why the framework's `Dockerfile`
43
+ could simply say `corepack enable` and trust that pnpm appeared.
44
+
45
+ **Node >= 25 no longer ships corepack.** A build stage that runs `corepack enable` on such an image
46
+ fails outright:
47
+
48
+ ```
49
+ /bin/sh: corepack: not found
50
+ ```
51
+
52
+ So the framework needed a way to provision an exact pnpm version that does not depend on corepack
53
+ existing — without giving up the single-source-of-truth pin.
54
+
55
+ ### What 11.29.0 did, and why it is reverted here
56
+
57
+ 11.29.0 removed the `packageManager` field and introduced `engines.pnpm: "^11.0.0"`. That left the
58
+ repo with **no exact pin at all**, so the version had to be restated wherever pnpm was needed — the
59
+ workflows grew a hardcoded `with: version: 11`, and Docker's `corepack enable` (with no
60
+ `packageManager` field to follow) would resolve to whatever it considered current.
61
+
62
+ Two sources of truth, neither exact. 11.29.1 collapses them back into one:
63
+
64
+ | | 11.29.0 | 11.29.1 |
65
+ |---|---|---|
66
+ | `package.json#packageManager` | *(removed)* | `pnpm@11.13.1+sha512.…` — **the** pin |
67
+ | `package.json#engines.pnpm` | `^11.0.0` | `^11.0.0` — unchanged, a soft major gate |
68
+ | `.github/workflows/*` | `with: version: 11` | *(no `version` input — reads the pin)* |
69
+ | `Dockerfile` | `corepack enable` | derive-line (below) |
70
+
71
+ `engines.pnpm` stays, but understand what it is: a **soft major-range guard**, not a pin. It warns a
72
+ pnpm 10 user; it does not tell CI which version to install. Only `packageManager` does that.
73
+
74
+ ---
75
+
76
+ ## What Changed
77
+
78
+ ### 1. `packageManager` is back — exact, with an integrity hash
79
+
80
+ ```jsonc
81
+ // package.json
82
+ {
83
+ "packageManager": "pnpm@11.13.1+sha512.b2fc7683b8a6525414e7d13e1ba28caaddde96bf66ec540bfaeb7e702b81f3e0be4d1f295edf7f9fe0396740a8dce4509c582ddf79891f4543fea32d37645f25",
84
+ "engines": {
85
+ "node": ">= 22",
86
+ "pnpm": "^11.0.0"
87
+ }
88
+ }
89
+ ```
90
+
91
+ **This field has no effect on your project.** `packageManager` is only ever read from the *root*
92
+ `package.json` of the project being built — never from a dependency's. You inherit nothing from the
93
+ framework's pin.
94
+
95
+ Note that pnpm itself honours the field, with no corepack involved: run any `pnpm` command in a
96
+ directory whose `package.json` pins a different pnpm, and pnpm switches to it
97
+ (`managePackageManagerVersions`, on by default since pnpm 10). Corepack was never the only thing
98
+ reading this field — which is exactly why dropping it costs nothing.
99
+
100
+ ### 2. The Dockerfile provisions pnpm without corepack
101
+
102
+ Every stage that runs `pnpm` now provisions the pinned version itself, from the pin:
103
+
104
+ ```dockerfile
105
+ # Provision the exact pnpm declared in package.json (single source of truth).
106
+ # No corepack: Node >= 25 no longer ships it. The +sha512 suffix is stripped;
107
+ # npm enforces registry integrity for the tarball itself.
108
+ RUN npm install -g "$(node -p "require('./package.json').packageManager.split('+')[0]")"
109
+ ```
110
+
111
+ The `.split('+')[0]` turns `pnpm@11.13.1+sha512.b2fc…` into `pnpm@11.13.1`, because `npm install -g`
112
+ takes a plain spec. The dropped hash is not a loss of integrity: npm verifies the tarball against the
113
+ registry's own integrity metadata on install.
114
+
115
+ The line appears **once per pnpm-running stage** (`deps` and `builder`) — Docker stages do not inherit
116
+ each other's globally installed binaries, only what is explicitly `COPY --from=`'d.
117
+
118
+ ### 3. `pnpm/action-setup` no longer carries a `version` input
119
+
120
+ ```yaml
121
+ - name: Install pnpm
122
+ # No version input: the exact version is read from package.json's packageManager field.
123
+ uses: pnpm/action-setup@v6
124
+ ```
125
+
126
+ The action reads `packageManager` on its own. Specifying **both** is not redundant-but-harmless — the
127
+ action treats a mismatch as a hard error, so the two sources cannot silently drift.
128
+
129
+ ### 4. A contract test guards the chain
130
+
131
+ `tests/unit/pnpm-pin-contract.spec.ts` (11 assertions, unit suite, no MongoDB) fails the build if
132
+ anyone re-introduces the drift this release removes:
133
+
134
+ - the pin is exact (`x.y.z` + `sha512` hash — never a range),
135
+ - `engines.pnpm` tracks the pin's major,
136
+ - `devEngines.packageManager` never (re)appears — npm/npx abort with `EBADDEVENGINES` on it,
137
+ - the `Dockerfile` contains no `corepack` in any `RUN`,
138
+ - **every** pnpm-running stage runs the derive-line *before* its first `pnpm` command, and only after
139
+ a `COPY` has put `package.json` in place,
140
+ - no workflow passes a `version:` to `pnpm/action-setup` or hardcodes `npm install -g pnpm@…`.
141
+
142
+ A twelfth test proves the chain end-to-end — it derives the spec exactly as the Dockerfile does,
143
+ installs it into a throwaway prefix, and asserts the provisioned binary reports the pinned version.
144
+ It needs network and ~10 MB, so it is gated to `CI` / `PIN_PROVISION_TEST=1` and stays out of your way
145
+ locally.
146
+
147
+ ---
148
+
149
+ ## Breaking Changes
150
+
151
+ **None.** No public API, config key, decorator, or exported symbol changed.
152
+
153
+ ---
154
+
155
+ ## Adopting the pattern in your project (recommended)
156
+
157
+ Do this **before** you move any build to Node >= 25 — not after it breaks. If your project was
158
+ generated from a recent `nest-server-starter` / `lt fullstack init`, check whether it is already done.
159
+
160
+ ### Step 1: Pin pnpm in your root `package.json`
161
+
162
+ ```bash
163
+ # Writes packageManager with the integrity hash for the version you actually use
164
+ pnpm self-update
165
+ ```
166
+
167
+ Or set it by hand — the exact form matters (`pnpm@x.y.z+sha512.<hash>`):
168
+
169
+ ```jsonc
170
+ {
171
+ "packageManager": "pnpm@11.13.1+sha512.b2fc7683…",
172
+ "engines": { "node": ">= 22", "pnpm": "^11.0.0" }
173
+ }
174
+ ```
175
+
176
+ > **Monorepo:** this belongs in the **workspace root** `package.json`, not only in `projects/api/`.
177
+ > The Dockerfile's derive-line reads `/app/package.json`, which in monorepo mode
178
+ > (`--build-arg API_DIR=projects/api`) is the root manifest. See
179
+ > [Troubleshooting](#docker-build-fails-with-typeerror-cannot-read-properties-of-undefined-reading-split).
180
+
181
+ ### Step 2: Replace corepack in your Dockerfile
182
+
183
+ **Before:**
184
+ ```dockerfile
185
+ RUN apk add --no-cache python3 make g++ && corepack enable
186
+ ```
187
+
188
+ **After:**
189
+ ```dockerfile
190
+ RUN apk add --no-cache python3 make g++
191
+
192
+ # … COPY the manifests first — the derive-line reads package.json …
193
+
194
+ # Provision the exact pnpm declared in package.json (single source of truth).
195
+ # No corepack: Node >= 25 no longer ships it. The +sha512 suffix is stripped;
196
+ # npm enforces registry integrity for the tarball itself.
197
+ RUN npm install -g "$(node -p "require('./package.json').packageManager.split('+')[0]")"
198
+ ```
199
+
200
+ Two ordering rules, both easy to get wrong:
201
+
202
+ 1. The derive-line must come **after** the `COPY` that puts `package.json` into the WORKDIR — it
203
+ reads that file.
204
+ 2. It must be repeated in **each** stage that runs `pnpm`. A global install in `deps` does not reach
205
+ `builder`.
206
+
207
+ ### Step 3: Drop the hardcoded version in CI
208
+
209
+ **GitHub Actions** — remove the `version` input:
210
+
211
+ ```yaml
212
+ - name: Install pnpm
213
+ uses: pnpm/action-setup@v6 # reads packageManager; no `with: version:`
214
+ ```
215
+
216
+ **GitLab CI** (or any runner without the action) — use the same derive-line:
217
+
218
+ ```yaml
219
+ before_script:
220
+ # Provision the exact pnpm pinned in package.json (single source of truth).
221
+ - npm install -g "$(node -p "require('./package.json').packageManager.split('+')[0]")"
222
+ - pnpm install --frozen-lockfile
223
+ ```
224
+
225
+ ### Step 4 (optional): Guard it with a test
226
+
227
+ Copy `tests/unit/pnpm-pin-contract.spec.ts` from this repo and trim it to the files your project has.
228
+ The value is not the assertions — it is that the next person who "helpfully" re-adds
229
+ `with: version: 11` or a second `npm install -g pnpm@…` gets a red build instead of a silent drift
230
+ that surfaces months later as an unreproducible container.
231
+
232
+ ---
233
+
234
+ ## Compatibility Notes
235
+
236
+ | Pattern | Status |
237
+ |---------|--------|
238
+ | Any application code, decorator, service, or config using the framework | ✅ Unaffected — no runtime code changed |
239
+ | **npm-mode** consumers (`@lenne.tech/nest-server` as a dependency) | ✅ Unaffected — `pnpm add …@11.29.1` and done |
240
+ | **Vendor-mode** consumers (`src/core/` copied in) | ✅ Unaffected — `src/core/` is byte-identical to 11.29.0; a sync produces no delta |
241
+ | The framework's `packageManager` pin leaking into your project | ✅ Impossible — the field is read only from the root manifest, never from a dependency |
242
+ | Your project's `Dockerfile` still using `corepack enable` | ⚠️ Works on Node <= 24, **breaks on Node >= 25** — apply Step 2 |
243
+ | Your CI passing both `with: version:` **and** having a `packageManager` field | ⚠️ Hard error on version mismatch — apply Step 3 |
244
+ | Node version | ✅ Unchanged (`engines.node: ">= 22"`); the framework's own images stay on Node 24 LTS |
245
+ | pnpm 10 or older as your project's package manager | ⚠️ `engines.pnpm: "^11.0.0"` warns (`EBADENGINE`); a hard failure only with `engine-strict=true` |
246
+
247
+ ---
248
+
249
+ ## Troubleshooting
250
+
251
+ ### `corepack: not found` in a Docker build or CI job
252
+
253
+ You moved to a Node >= 25 image while your build still calls `corepack enable`. This is exactly the
254
+ failure this release prevents — apply [Step 2](#step-2-replace-corepack-in-your-dockerfile). Do not
255
+ "fix" it with `npm install -g corepack`: that reintroduces the indirection the derive-line removes.
256
+
257
+ ### Docker build fails with `TypeError: Cannot read properties of undefined (reading 'split')`
258
+
259
+ The derive-line found a `package.json` **without** a `packageManager` field. Almost always a
260
+ monorepo: in monorepo mode the build context is the workspace root, so `/app/package.json` is the
261
+ **root** manifest — and the pin was only added to `projects/api/package.json`.
262
+
263
+ Fix: add `packageManager` to the workspace **root** manifest (Step 1). Keeping the root and the API
264
+ package on the same pin is the point — one pnpm builds the whole workspace.
265
+
266
+ ### `ERR_PNPM_BAD_PM_VERSION`, or the action reports multiple pnpm versions
267
+
268
+ Two sources disagree about the version. Either your workflow still passes `with: version:` alongside
269
+ a `packageManager` field (remove the input — [Step 3](#step-3-drop-the-hardcoded-version-in-ci)), or a
270
+ stray `npm install -g pnpm@<other>` runs before the derive-line.
271
+
272
+ ### `EBADENGINE` / `ERR_PNPM_UNSUPPORTED_ENGINE` warning mentioning pnpm
273
+
274
+ Unchanged from 11.29.0 — `engines.pnpm: "^11.0.0"` warns when installing with pnpm 10 or older.
275
+ Upgrade with `npm i -g pnpm@11`, or pin your project via `packageManager` and let pnpm switch itself.
276
+ The framework's *runtime* does not depend on pnpm; this concerns the install step only.
277
+
278
+ ### `EBADDEVENGINES` from npm or npx
279
+
280
+ Something added a `devEngines.packageManager` block. npm and npx abort on it, and corepack rejects
281
+ ranges inside it. Use `packageManager` (exact pin) plus `engines.pnpm` (soft range) instead — the
282
+ contract test asserts `devEngines.packageManager` stays absent.
283
+
284
+ ---
285
+
286
+ ## Affected Files
287
+
288
+ No core module changed in this release, so there is no module documentation to revisit. For
289
+ completeness, the full change surface:
290
+
291
+ | File | Change |
292
+ |------|--------|
293
+ | `package.json` | `packageManager` restored (exact pin + `sha512`); version → 11.29.1 |
294
+ | `Dockerfile` | `corepack enable` removed; derive-line added to the `deps` and `builder` stages |
295
+ | `.github/workflows/build.yml`, `publish.yml` | `with: version: 11` removed from `pnpm/action-setup` |
296
+ | `tests/unit/pnpm-pin-contract.spec.ts` | **New** — 11 structural assertions + 1 CI-gated provisioning proof |
297
+ | `spectaql.yml`, `FRAMEWORK-API.md` | Version bump only (kept in sync per the release process) |
298
+ | `.claude/rules/package-management.md` | Documents the corepack-free pin contract |
299
+
300
+ ---
301
+
302
+ ## References
303
+
304
+ - [Package Management Rules — fixed versions, overrides, the pnpm pin contract](../.claude/rules/package-management.md)
305
+ - [Versioning Strategy — release process, `package.json` / `spectaql.yml` version sync](../.claude/rules/versioning.md)
306
+ - Contract test: `tests/unit/pnpm-pin-contract.spec.ts`
307
+ - [Migration Guide 11.28.1 → 11.29.0](./11.28.1-to-11.29.0.md) — previous release (introduced the `engines.pnpm` gate this guide keeps)
308
+ - [Migration Guide 11.27.6 → 11.27.7](./11.27.6-to-11.27.7.md) — the pnpm 11 move, when corepack was still the mechanism
309
+ - [nest-server-starter](https://github.com/lenneTech/nest-server-starter) (reference implementation)
310
+ </content>
311
+ </invoke>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/nest-server",
3
- "version": "11.29.0",
3
+ "version": "11.29.1",
4
4
  "description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
5
5
  "keywords": [
6
6
  "node",
@@ -79,6 +79,7 @@
79
79
  "node": ">= 22",
80
80
  "pnpm": "^11.0.0"
81
81
  },
82
+ "packageManager": "pnpm@11.13.1+sha512.b2fc7683b8a6525414e7d13e1ba28caaddde96bf66ec540bfaeb7e702b81f3e0be4d1f295edf7f9fe0396740a8dce4509c582ddf79891f4543fea32d37645f25",
82
83
  "dependencies": {
83
84
  "@apollo/server": "5.5.1",
84
85
  "@as-integrations/express5": "1.1.2",