@appxdigital/appx-core 0.1.121-beta.5 → 0.1.121-beta.7
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.
- package/CHANGELOG.md +104 -0
- package/PRERELEASES.md +83 -0
- package/RELEASING.md +168 -0
- package/dist/common/guards/rbac.guard.d.ts.map +1 -1
- package/dist/common/guards/rbac.guard.js +7 -1
- package/package.json +5 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@appxdigital/appx-core` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
This project follows the `MAJOR.MINOR.PATCH` scheme in `package.json`.
|
|
7
|
+
|
|
8
|
+
## How to read this file
|
|
9
|
+
|
|
10
|
+
- **This file is the collapsed, production changelog** — one section per version published to the `latest` dist-tag. Granular per-build notes for `alpha`/`beta` prereleases live in [`PRERELEASES.md`](./PRERELEASES.md); the release process is documented in [`RELEASING.md`](./RELEASING.md).
|
|
11
|
+
- **Every released version has a section.** Newest first.
|
|
12
|
+
- **Changes that require action in an existing project are listed under `### Migration`** — copy-paste ready, small enough to hand to an AI coding agent. Items outside that block are drop-in.
|
|
13
|
+
- **Scaffold-only changes** (files under `cli/scaffold/`) affect *new* projects created with `appx-core create`. Existing projects own their copies of those files and apply the migration by hand.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## [0.1.121] — 2026-07-14
|
|
18
|
+
|
|
19
|
+
Hardening release: request validation, boot configuration, generated-CRUD DTOs, and data-access create enforcement.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **`setupCoreSecurity(app, options?)`** — one call that applies baseline HTTP hardening: a global `ValidationPipe` (`{ transform: true, whitelist: true, forbidNonWhitelisted: true }`), CORS (`cors` option, default `{ origin: 'http://localhost:3000', credentials: true }`, throws if `origin: '*'` is combined with `credentials: true`), and **Helmet** security headers (on by default; `helmet` option to tune/disable). `helmet` is a new peer dependency.
|
|
24
|
+
- **`buildCoreSessionOptions({ secret, store, cookieName?, ttlSeconds?, secure?, sameSite? })`** — builds hardened `express-session` options. Throws if `secret` is missing or `< 32` chars (no fallback); sets `cookie: { httpOnly, secure (prod), sameSite: 'lax', maxAge }`.
|
|
25
|
+
- **`coreEnvFilePath()`** — returns `['.env.${NODE_ENV}', '.env']` (env-specific file wins, plain `.env` is a fallback) and throws if `NODE_ENV` is unset.
|
|
26
|
+
- **Per-model DTO generation** (`appx generate`). Each model+action gets a `class-validator` DTO so generated controllers type their request body concretely and the whitelist pipe can strip unknown fields. Two files:
|
|
27
|
+
- `src/generated/dto/<model>/<action>-<model>.generated.dto.ts` — base class, **always overwritten**, under the gitignored `src/generated/`. Never hand-edit.
|
|
28
|
+
- `src/modules/<model>/dto/<action>-<model>.dto.ts` — a hand-owned subclass, generated **once**, for custom validation. The controller imports this.
|
|
29
|
+
- **`/// @NoWrite` field annotation** — excludes a field from the generated create/update DTOs (all roles). Fields annotated `/// @Role(none)` are also treated as non-writable.
|
|
30
|
+
- **Create-permission enforcement in the data-access proxy.** `create` / `createMany` validate that the incoming data satisfies the permission's `conditions` before insert (own-scalar fields against the data; relation conditions by looking up the referenced parent), and default-deny when the model/role has no `create` permission. A development-only warning fires when a created row would not satisfy the model's `find` conditions.
|
|
31
|
+
- **`restrictedFields` on `create`** in `CoreController` (previously only `update`, which also read the wrong permission key so it never applied under `updateMany`).
|
|
32
|
+
|
|
33
|
+
### Writable-field policy (generated DTOs)
|
|
34
|
+
|
|
35
|
+
A scalar field is included unless it is: the primary key (`@id`), a server-managed timestamp (`@default(now())` / `@updatedAt`), `/// @NoWrite`, or `/// @Role(none)`. Relation navigation fields are excluded; their scalar foreign keys are kept. Enums map to `@IsEnum`, scalars to the matching `@IsString`/`@IsInt`/`@IsBoolean`/`@IsNumber`/`@IsDateString`; `Json`/`Bytes` use `@Allow()`.
|
|
36
|
+
|
|
37
|
+
### Changed (scaffold — new projects only)
|
|
38
|
+
|
|
39
|
+
- `main.ts` calls `setupCoreSecurity(app, { cors: { origin: corsOrigin, credentials: true } })`, builds session options via `buildCoreSessionOptions`, and reads `CORS_ORIGIN` from config.
|
|
40
|
+
- `app.module.ts` uses `coreEnvFilePath()` for `envFilePath`.
|
|
41
|
+
- Generated `package.json` adds `helmet`; the `start` script sets `NODE_ENV=development`.
|
|
42
|
+
- `AuthController.getAllSessions` / `closeSpecificSession` use `@UseGuards(AuthenticatedGuard)`.
|
|
43
|
+
|
|
44
|
+
### Migration
|
|
45
|
+
|
|
46
|
+
> For existing projects. All edits are to files you own (`main.ts` / `app.module.ts` / `package.json` / your generated controllers). Safe to hand to an AI coding agent.
|
|
47
|
+
|
|
48
|
+
**1. Request validation & HTTP hardening — `src/main.ts`.**
|
|
49
|
+
```ts
|
|
50
|
+
import { setupCoreSecurity } from '@appxdigital/appx-core';
|
|
51
|
+
// remove: app.useGlobalPipes(new ValidationPipe({ transform: true }));
|
|
52
|
+
// remove: app.enableCors({ origin: 'http://localhost:3000', credentials: true });
|
|
53
|
+
const corsOrigin = configService.get<string>('CORS_ORIGIN') ?? 'http://localhost:3000';
|
|
54
|
+
setupCoreSecurity(app, { cors: { origin: corsOrigin, credentials: true } });
|
|
55
|
+
```
|
|
56
|
+
- Install Helmet: `npm install helmet@^8.0.0` (applied automatically by `setupCoreSecurity`; tune with `{ helmet: {...} }`, disable with `{ helmet: false }`).
|
|
57
|
+
- If you register a `ValidationPipe` with custom options, pass them through: `setupCoreSecurity(app, { validationPipe: { /* overrides */ } })`.
|
|
58
|
+
- With `whitelist` + `forbidNonWhitelisted`, body properties not declared on a `class-validator` DTO are rejected (`400`). Confirm every DTO declares every field it legitimately accepts before deploying.
|
|
59
|
+
- Set `CORS_ORIGIN` to your real front-end origin in production. Do not combine `'*'` with credentials — the helper throws at boot. For a public credential-less API pass `{ cors: { origin: '*', credentials: false } }`.
|
|
60
|
+
|
|
61
|
+
**2. Session secret & cookie flags — `src/main.ts`.**
|
|
62
|
+
```ts
|
|
63
|
+
import { buildCoreSessionOptions } from '@appxdigital/appx-core';
|
|
64
|
+
// replace your inline session({ secret: … }) (drop any hardcoded fallback secret) with:
|
|
65
|
+
app.use(session(buildCoreSessionOptions({
|
|
66
|
+
secret: configService.get<string>('SESSION_SECRET'),
|
|
67
|
+
cookieName: configService.get<string>('SESSION_COOKIE_NAME'),
|
|
68
|
+
ttlSeconds: configService.get<number>('SESSION_TTL') || 86400,
|
|
69
|
+
store: new CorePrismaSessionStore(prismaService, { ttl: sessionTTL }),
|
|
70
|
+
})));
|
|
71
|
+
```
|
|
72
|
+
Ensure `SESSION_SECRET` is set (≥ 32 chars) in every environment — the app now refuses to boot without it.
|
|
73
|
+
|
|
74
|
+
**3. Environment file & `NODE_ENV` — `src/app.module.ts`.**
|
|
75
|
+
```ts
|
|
76
|
+
import { coreEnvFilePath } from '@appxdigital/appx-core';
|
|
77
|
+
// ConfigModule.forRoot({ … envFilePath: coreEnvFilePath() })
|
|
78
|
+
```
|
|
79
|
+
Set `NODE_ENV` explicitly (`production` / `development`) in every deploy and start script — boot fails if it is unset. If you use a bare `nest start`, change it to `cross-env NODE_ENV=development nest start`. (`coreEnvFilePath()` loads `.env.<NODE_ENV>` with `.env` as a fallback, so a plain `.env` still works.)
|
|
80
|
+
|
|
81
|
+
**4. Generated-CRUD DTOs.**
|
|
82
|
+
```bash
|
|
83
|
+
npm install @appxdigital/appx-core@^0.1.121
|
|
84
|
+
npx appx generate
|
|
85
|
+
```
|
|
86
|
+
Then **add the DTO-typed overrides to each existing generated controller** (generated once, not overwritten):
|
|
87
|
+
```ts
|
|
88
|
+
import { Body, Param, Post, Put } from '@nestjs/common';
|
|
89
|
+
import { Permission } from '@appxdigital/appx-core';
|
|
90
|
+
import { Create<Model>Dto } from './dto/create-<model-kebab>.dto';
|
|
91
|
+
import { Update<Model>Dto } from './dto/update-<model-kebab>.dto';
|
|
92
|
+
|
|
93
|
+
@Post() @Permission('create')
|
|
94
|
+
async create(@Body() data: Create<Model>Dto) { return super.create(data as any); }
|
|
95
|
+
|
|
96
|
+
@Put(':id') @Permission('updateMany')
|
|
97
|
+
async update(@Param('id') id: string, @Body() data: Update<Model>Dto) { return super.update(id, data as any); }
|
|
98
|
+
```
|
|
99
|
+
(Or delete an un-customized controller and re-run `appx generate` for the new template.) Add custom validation in the hand-owned `dto/*.dto.ts` subclasses — never in the `.generated.dto.ts` base. Lock sensitive columns with `/// @NoWrite` (all roles) or `restrictedFields` on the permission (per role), then regenerate.
|
|
100
|
+
|
|
101
|
+
**5. Create-permission enforcement (behaviour change — review before upgrading).**
|
|
102
|
+
- Ensure every model/role that legitimately creates records has an explicit `create` permission (or `'ALL'`). Without one, create now returns `403` (previously unchecked). Internal framework flows (registration, sessions, tokens) are unaffected.
|
|
103
|
+
- If you supplied arbitrary values for a field a `create` condition constrains (e.g. an owner id), those requests now return `403` unless the value matches — use `setUserIdField` to have the framework set it.
|
|
104
|
+
- **`restrictedFields` under `updateMany` now applies** (it was a no-op before). Fields listed there are stripped on `PUT`. Remove any field that should remain writable.
|
package/PRERELEASES.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Prerelease log
|
|
2
|
+
|
|
3
|
+
Granular notes for **alpha / beta** builds of both packages —
|
|
4
|
+
`@appxdigital/appx-core` (library) and `@appxdigital/appx-core-cli` (CLI) —
|
|
5
|
+
newest first. Entries are labelled by package. These are the builds you install
|
|
6
|
+
to test a change in a real project before it ships:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @appxdigital/appx-core@beta # library, latest beta
|
|
10
|
+
npm install @appxdigital/appx-core@0.1.121-beta.0 # a specific library build
|
|
11
|
+
npx @appxdigital/appx-core-cli@beta create # CLI, latest beta
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Each prerelease gets its own entry here with fine-grained notes. When a version
|
|
15
|
+
is promoted to production it is **collapsed** into a single curated section in
|
|
16
|
+
[`CHANGELOG.md`](./CHANGELOG.md) with aggregated changes and consolidated
|
|
17
|
+
migration steps — that public changelog is the one an upgrading project reads.
|
|
18
|
+
Nothing here is a substitute for it.
|
|
19
|
+
|
|
20
|
+
Prereleases are excluded from normal semver range resolution, so a project on
|
|
21
|
+
`^0.1.x` never pulls one by accident — you always opt in via the `@beta` /
|
|
22
|
+
`@alpha` tag or an exact version.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## [0.1.121-beta.7] — unreleased
|
|
27
|
+
|
|
28
|
+
**Library.** `createMany` now inherits the `create` permission when not declared
|
|
29
|
+
explicitly — in both the data-access proxy and the `RbacGuard`. A
|
|
30
|
+
`permissions.config.ts` can declare a single `create` rule and have it cover
|
|
31
|
+
`createMany` too (mirrors the existing `findMany → count/findFirst` fallback).
|
|
32
|
+
One-directional: declaring only `createMany` does **not** enable `create`.
|
|
33
|
+
|
|
34
|
+
- If you previously duplicated `create` and `createMany`, the `createMany` entry
|
|
35
|
+
is now redundant (harmless to keep). No action required.
|
|
36
|
+
|
|
37
|
+
## [0.1.121-beta.6] — unreleased
|
|
38
|
+
|
|
39
|
+
**Packaging.** The npm tarball now ships `CHANGELOG.md`, `PRERELEASES.md`, and
|
|
40
|
+
`RELEASING.md` (previously only `dist/` + `README.md`). Migration steps are now
|
|
41
|
+
readable from inside an installed `node_modules/@appxdigital/appx-core`, so an
|
|
42
|
+
upgrading project (or an AI agent) can apply them without cloning the repo. No
|
|
43
|
+
code change.
|
|
44
|
+
|
|
45
|
+
## [0.1.121-beta.5] — unreleased
|
|
46
|
+
|
|
47
|
+
**Library.** Field-level access control (`/// @Role(...)`) now applies to
|
|
48
|
+
**nested** relation selections, not just top-level fields. Previously a query
|
|
49
|
+
that selected a restricted field *through* a relation
|
|
50
|
+
(`select: { relation: { select: { restrictedField: true } } }`) received that
|
|
51
|
+
field; the data-access proxy now omits it at every depth, for both `select` and
|
|
52
|
+
`include`, while preserving any `where` / `orderBy` you set on the relation.
|
|
53
|
+
|
|
54
|
+
- Exercise reads that pull fields through relations (nested `select` / `include`,
|
|
55
|
+
including multi-level) and confirm the values you expect still come back — a
|
|
56
|
+
field annotated `@Role(<roles>)` should be absent for roles not listed.
|
|
57
|
+
- No API change; regenerate is not required.
|
|
58
|
+
|
|
59
|
+
## [0.1.121-beta.0] — unreleased
|
|
60
|
+
|
|
61
|
+
First prerelease of the `0.1.121` hardening set. Testing target before this is
|
|
62
|
+
promoted to `latest`. Full aggregated notes and migration live under
|
|
63
|
+
`[0.1.121]` in `CHANGELOG.md`; the highlights to exercise in a project:
|
|
64
|
+
|
|
65
|
+
- **`setupCoreSecurity(app, options?)`** — one call for the global
|
|
66
|
+
`ValidationPipe` (whitelist + `forbidNonWhitelisted`), CORS, and Helmet.
|
|
67
|
+
Verify existing DTOs still accept every field they legitimately take (the
|
|
68
|
+
whitelist rejects undeclared body properties with `400`).
|
|
69
|
+
- **`buildCoreSessionOptions(...)`** — requires a session secret ≥ 32 chars and
|
|
70
|
+
sets hardened cookie flags. Confirm your env provides the secret.
|
|
71
|
+
- **`coreEnvFilePath()`** — `['.env.${NODE_ENV}', '.env']`; throws if
|
|
72
|
+
`NODE_ENV` is unset. Confirm boot scripts set `NODE_ENV`.
|
|
73
|
+
- **Per-model generated DTOs** — regenerate (`appx generate`) and check the
|
|
74
|
+
generated controllers compile and accept your writable fields.
|
|
75
|
+
- **Create-permission enforcement in the data-access proxy** — `create` /
|
|
76
|
+
`createMany` now validate incoming data against the permission conditions and
|
|
77
|
+
default-deny when a model/role has no `create` permission. Exercise every
|
|
78
|
+
create path in the consuming app and confirm intended creates still succeed;
|
|
79
|
+
set explicit `create` permissions (or `ALL`) where needed.
|
|
80
|
+
|
|
81
|
+
> How to try it: bump this package to `0.1.121-beta.0` in the project under
|
|
82
|
+
> test (`npm install @appxdigital/appx-core@beta`), run the app's own suite,
|
|
83
|
+
> and smoke-test create/update flows and boot. Report back before promotion.
|
package/RELEASING.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
This repo publishes **two independent packages**, each versioned on its own:
|
|
4
|
+
|
|
5
|
+
- **`@appxdigital/appx-core`** — the runtime library (root `package.json`),
|
|
6
|
+
released via **`v*`** tags (`release.yml`).
|
|
7
|
+
- **`@appxdigital/appx-core-cli`** — the `appx-core` CLI (`cli/package.json`),
|
|
8
|
+
released via **`cli-v*`** tags (`release-cli.yml`).
|
|
9
|
+
|
|
10
|
+
Both follow the same posture: publishing is deliberate — **it only happens when
|
|
11
|
+
you push a git tag** — and production (`latest`) pauses for a human approval
|
|
12
|
+
before it goes live.
|
|
13
|
+
|
|
14
|
+
## Channels
|
|
15
|
+
|
|
16
|
+
Library (`v*` tags):
|
|
17
|
+
|
|
18
|
+
| You push tag | npm dist-tag | Consumers install with | Gated? |
|
|
19
|
+
| ------------------ | ------------ | --------------------------------- | --------------- |
|
|
20
|
+
| `v1.2.3-alpha.N` | `alpha` | `…/appx-core@alpha` | no |
|
|
21
|
+
| `v1.2.3-beta.N` | `beta` | `…/appx-core@beta` | no |
|
|
22
|
+
| `v1.2.3-rc.N` | `next` | `…/appx-core@next` | no |
|
|
23
|
+
| `v1.2.3` | `latest` | `…/appx-core` (default) | **yes** — approval |
|
|
24
|
+
|
|
25
|
+
CLI (`cli-v*` tags) — identical channels for `@appxdigital/appx-core-cli`:
|
|
26
|
+
|
|
27
|
+
| You push tag | npm dist-tag | Consumers install with | Gated? |
|
|
28
|
+
| -------------------- | ------------ | ------------------------------- | --------------- |
|
|
29
|
+
| `cli-v1.2.3-beta.N` | `beta` | `…/appx-core-cli@beta` | no |
|
|
30
|
+
| `cli-v1.2.3` | `latest` | `…/appx-core-cli` (default) | **yes** — approval |
|
|
31
|
+
|
|
32
|
+
Prereleases are excluded from `^1.2.x` range resolution, so a project on a caret
|
|
33
|
+
range never pulls one by accident — testers opt in via the tag or an exact
|
|
34
|
+
version. Merging to `main` **never** publishes; it only runs CI (library build +
|
|
35
|
+
tests on mysql and postgres, plus a CLI smoke check).
|
|
36
|
+
|
|
37
|
+
## Two files, two audiences
|
|
38
|
+
|
|
39
|
+
- **`PRERELEASES.md`** — granular, one entry per alpha/beta build. What a tester
|
|
40
|
+
reads.
|
|
41
|
+
- **`CHANGELOG.md`** — collapsed, one section per production release with
|
|
42
|
+
aggregated changes and consolidated migration steps. What an upgrading project
|
|
43
|
+
reads. When you promote a version, distil its prerelease entries into a single
|
|
44
|
+
`CHANGELOG.md` section.
|
|
45
|
+
|
|
46
|
+
## One-time setup (before the first publish)
|
|
47
|
+
|
|
48
|
+
1. **npm Trusted Publisher (OIDC) — one per package.** On npmjs.com → the
|
|
49
|
+
package → *Settings* → *Trusted Publisher* → GitHub Actions. Add **two**,
|
|
50
|
+
both owner `appxdigital`, repo `appx-core`:
|
|
51
|
+
- `@appxdigital/appx-core` → workflow `release.yml`
|
|
52
|
+
- `@appxdigital/appx-core-cli` → workflow `release-cli.yml`
|
|
53
|
+
|
|
54
|
+
This lets CI mint a short-lived publish token per run — **no `NPM_TOKEN`
|
|
55
|
+
secret is stored anywhere**, and every publish carries supply-chain
|
|
56
|
+
provenance.
|
|
57
|
+
|
|
58
|
+
2. **GitHub `production` environment (the approval gate).** Repo → *Settings* →
|
|
59
|
+
*Environments* → *New environment* → name it exactly `production` → enable
|
|
60
|
+
*Required reviewers* and add yourself (and/or the team). The
|
|
61
|
+
`publish-production` job targets this environment, so a clean tag will wait
|
|
62
|
+
for a click before publishing to `latest`.
|
|
63
|
+
|
|
64
|
+
## Cutting a release
|
|
65
|
+
|
|
66
|
+
The tag must match `package.json`'s version exactly, or the release job fails
|
|
67
|
+
fast (a guard against mistagging). Convenience scripts keep them in lockstep and
|
|
68
|
+
create the tag for you — they **do not push**, so pushing stays a deliberate
|
|
69
|
+
step:
|
|
70
|
+
|
|
71
|
+
There are two per package — a **test build** and a **production release**:
|
|
72
|
+
|
|
73
|
+
| Script | What it does | Tag | Goes to |
|
|
74
|
+
| ------------------------------- | ------------------------------------- | --------------- | ----------------- |
|
|
75
|
+
| `npm run release:beta` | library test build (`…-beta.N`) | `v…-beta.N` | `beta` channel |
|
|
76
|
+
| `npm run release:production` | promote library to everyone | `vX.Y.Z` | `latest` (gated) |
|
|
77
|
+
| `npm run release:cli:beta` | CLI test build (`…-beta.N`) | `cli-v…-beta.N` | `beta` channel |
|
|
78
|
+
| `npm run release:cli:production`| promote CLI to everyone | `cli-vX.Y.Z` | `latest` (gated) |
|
|
79
|
+
|
|
80
|
+
`release:beta` publishes only to people who opt in with `@beta`; `release:production`
|
|
81
|
+
is what everyone gets by default, and it pauses for your approval before going
|
|
82
|
+
live. Each command bumps the version, commits, and creates the tag, then prints
|
|
83
|
+
the exact `git push origin HEAD --follow-tags` for you to run when ready — they
|
|
84
|
+
never push on their own.
|
|
85
|
+
|
|
86
|
+
Rarer cases go through the underlying script directly:
|
|
87
|
+
`node scripts/release.mjs lib alpha` (alpha channel), `… lib minor` (a feature
|
|
88
|
+
bump), or `… lib X.Y.Z-beta.0` (an explicit version — e.g. the first beta of a
|
|
89
|
+
version already sitting in `package.json`).
|
|
90
|
+
|
|
91
|
+
The manual steps below show what those scripts do under the hood.
|
|
92
|
+
|
|
93
|
+
### Beta (test in projects first)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# set the version + create the matching tag + commit, without auto-pushing
|
|
97
|
+
npm version 0.1.121-beta.0 --message "release: %s"
|
|
98
|
+
git push origin main --follow-tags
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The `Release` workflow builds, tests, and publishes to the `beta` dist-tag.
|
|
102
|
+
Then, in a project you want to test against:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install @appxdigital/appx-core@beta
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Iterate with `npm version prerelease --preid beta` (→ `-beta.1`, `-beta.2`, …),
|
|
109
|
+
each push publishing a new granular `PRERELEASES.md` entry.
|
|
110
|
+
|
|
111
|
+
### Promote to production (`latest`)
|
|
112
|
+
|
|
113
|
+
When the beta is validated in real projects:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# drop the prerelease suffix -> clean version
|
|
117
|
+
npm version 0.1.121 --message "release: %s"
|
|
118
|
+
git push origin main --follow-tags
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The workflow builds and tests, then **pauses** on the `production` environment.
|
|
122
|
+
Approve it in the repo's *Actions* tab → the running release → *Review
|
|
123
|
+
deployments* → *Approve and deploy*. It then publishes to `latest`.
|
|
124
|
+
|
|
125
|
+
> Alternatively, promotion can be a pure retag without republishing:
|
|
126
|
+
> `npm dist-tag add @appxdigital/appx-core@0.1.121-beta.N latest`. The
|
|
127
|
+
> tag-driven workflow above is preferred because it re-runs tests and records
|
|
128
|
+
> provenance for the exact `latest` artifact.
|
|
129
|
+
|
|
130
|
+
### Alpha (rough, one or two projects)
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm version 0.1.122-alpha.0 --message "release: %s"
|
|
134
|
+
git push origin main --follow-tags
|
|
135
|
+
# in the project: npm install @appxdigital/appx-core@alpha
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### CLI (`@appxdigital/appx-core-cli`)
|
|
139
|
+
|
|
140
|
+
Same flow, but bump `cli/package.json` and use the `cli-v` tag prefix. The tag
|
|
141
|
+
must match `cli/package.json`'s version.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# beta:
|
|
145
|
+
npm --prefix cli version 1.0.21-beta.0 --message "release cli: %s"
|
|
146
|
+
git commit -am "release cli: 1.0.21-beta.0" # npm version --prefix does not commit
|
|
147
|
+
git tag cli-v1.0.21-beta.0
|
|
148
|
+
git push origin main --follow-tags
|
|
149
|
+
# test: npx @appxdigital/appx-core-cli@beta create …
|
|
150
|
+
|
|
151
|
+
# production (gated — approve in the Actions tab):
|
|
152
|
+
npm --prefix cli version 1.0.21 --message "release cli: %s"
|
|
153
|
+
git commit -am "release cli: 1.0.21"
|
|
154
|
+
git tag cli-v1.0.21
|
|
155
|
+
git push origin main --follow-tags
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
> `npm version --prefix cli` bumps `cli/package.json` but does not create the
|
|
159
|
+
> git commit/tag (that only happens when run in the repo root). Commit and tag
|
|
160
|
+
> explicitly with the `cli-v` prefix as shown.
|
|
161
|
+
|
|
162
|
+
## Manual fallback
|
|
163
|
+
|
|
164
|
+
If CI is unavailable, you can still publish by hand: `rimraf dist && npm run
|
|
165
|
+
build && npm publish --tag <dist-tag> --access public` for the library, and
|
|
166
|
+
`cd cli && npm publish --tag <dist-tag> --access public` for the CLI. This
|
|
167
|
+
bypasses the tests, the approval gate, and provenance, so prefer the tag-driven
|
|
168
|
+
flow.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac.guard.d.ts","sourceRoot":"","sources":["../../../src/common/guards/rbac.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,gBAAgB,EAInB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAC,qBAAqB,EAAkB,MAAM,kCAAkC,CAAC;AAExF,qBACa,SAAU,YAAW,WAAW;IAErC,OAAO,CAAC,SAAS;IACiB,OAAO,CAAC,iBAAiB;gBADnD,SAAS,EAAE,SAAS,EACc,iBAAiB,EAAE,qBAAqB;IAGhF,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"rbac.guard.d.ts","sourceRoot":"","sources":["../../../src/common/guards/rbac.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,gBAAgB,EAInB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAC,qBAAqB,EAAkB,MAAM,kCAAkC,CAAC;AAExF,qBACa,SAAU,YAAW,WAAW;IAErC,OAAO,CAAC,SAAS;IACiB,OAAO,CAAC,iBAAiB;gBADnD,SAAS,EAAE,SAAS,EACc,iBAAiB,EAAE,qBAAqB;IAGhF,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CA0CjE"}
|
|
@@ -38,7 +38,13 @@ let RbacGuard = exports.RbacGuard = class RbacGuard {
|
|
|
38
38
|
if (!rolePermissions) {
|
|
39
39
|
throw new common_1.ForbiddenException(`No permissions defined for role ${user.role} on model ${model}`);
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
// `createMany` inherits the `create` rule when not defined explicitly —
|
|
42
|
+
// mirrors the data-access proxy, which validates each batched row against
|
|
43
|
+
// the `create` permission. Lets a config declare just `create`.
|
|
44
|
+
let permission = rolePermissions[action];
|
|
45
|
+
if (!permission && action === 'createMany') {
|
|
46
|
+
permission = rolePermissions['create'];
|
|
47
|
+
}
|
|
42
48
|
if (!permission) {
|
|
43
49
|
throw new common_1.ForbiddenException(`Action ${action} not allowed for role ${user.role} on model ${model}`);
|
|
44
50
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appxdigital/appx-core",
|
|
3
|
-
"version": "0.1.121-beta.
|
|
3
|
+
"version": "0.1.121-beta.7",
|
|
4
4
|
"description": "Appx Core is a library that provides a set of tools to help you build your application faster.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -99,7 +99,10 @@
|
|
|
99
99
|
"rxjs": "~7.8.1"
|
|
100
100
|
},
|
|
101
101
|
"files": [
|
|
102
|
-
"dist"
|
|
102
|
+
"dist",
|
|
103
|
+
"CHANGELOG.md",
|
|
104
|
+
"PRERELEASES.md",
|
|
105
|
+
"RELEASING.md"
|
|
103
106
|
],
|
|
104
107
|
"engines": {
|
|
105
108
|
"npm": ">=10.0.0",
|