@nestjs-cms/core 0.0.0-stage → 0.1.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.
- package/.env.example +21 -0
- package/README.md +341 -2
- package/dist/src/api-key.guard.d.ts +4 -0
- package/dist/src/api-key.guard.js +29 -0
- package/dist/src/api-key.guard.js.map +1 -0
- package/dist/src/config.d.ts +43 -0
- package/dist/src/config.js +47 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/database/create-data-source.d.ts +4 -0
- package/dist/src/database/create-data-source.js +23 -0
- package/dist/src/database/create-data-source.js.map +1 -0
- package/dist/src/error.filter.d.ts +6 -0
- package/dist/src/error.filter.js +54 -0
- package/dist/src/error.filter.js.map +1 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.js +23 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/resource/query.d.ts +15 -0
- package/dist/src/resource/query.js +147 -0
- package/dist/src/resource/query.js.map +1 -0
- package/dist/src/resource/resource-record.store.d.ts +7 -0
- package/dist/src/resource/resource-record.store.js +39 -0
- package/dist/src/resource/resource-record.store.js.map +1 -0
- package/dist/src/resource/resource.controller.d.ts +46 -0
- package/dist/src/resource/resource.controller.js +165 -0
- package/dist/src/resource/resource.controller.js.map +1 -0
- package/dist/src/resource/resource.loader.d.ts +2 -0
- package/dist/src/resource/resource.loader.js +43 -0
- package/dist/src/resource/resource.loader.js.map +1 -0
- package/dist/src/resource/resource.module.d.ts +16 -0
- package/dist/src/resource/resource.module.js +70 -0
- package/dist/src/resource/resource.module.js.map +1 -0
- package/dist/src/resource/resource.registry.d.ts +21 -0
- package/dist/src/resource/resource.registry.js +74 -0
- package/dist/src/resource/resource.registry.js.map +1 -0
- package/dist/src/resource/resource.service.d.ts +60 -0
- package/dist/src/resource/resource.service.js +150 -0
- package/dist/src/resource/resource.service.js.map +1 -0
- package/dist/src/resource/resource.types.d.ts +33 -0
- package/dist/src/resource/resource.types.js +7 -0
- package/dist/src/resource/resource.types.js.map +1 -0
- package/dist/src/resource/validation.d.ts +3 -0
- package/dist/src/resource/validation.js +19 -0
- package/dist/src/resource/validation.js.map +1 -0
- package/dist/src/setup.d.ts +3 -0
- package/dist/src/setup.js +16 -0
- package/dist/src/setup.js.map +1 -0
- package/dist/src/storage/attachment.entity.d.ts +23 -0
- package/dist/src/storage/attachment.entity.js +37 -0
- package/dist/src/storage/attachment.entity.js.map +1 -0
- package/dist/src/storage/attachment.service.d.ts +46 -0
- package/dist/src/storage/attachment.service.js +190 -0
- package/dist/src/storage/attachment.service.js.map +1 -0
- package/dist/src/storage/attachment.types.d.ts +5 -0
- package/dist/src/storage/attachment.types.js +3 -0
- package/dist/src/storage/attachment.types.js.map +1 -0
- package/dist/src/storage/s3.service.d.ts +8 -0
- package/dist/src/storage/s3.service.js +65 -0
- package/dist/src/storage/s3.service.js.map +1 -0
- package/docs/api.md +166 -0
- package/docs/operations.md +166 -0
- package/docs/resources.md +151 -0
- package/package.json +82 -4
package/.env.example
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
NODE_ENV=development
|
|
2
|
+
PORT=3000
|
|
3
|
+
HOST=127.0.0.1
|
|
4
|
+
CORS_ORIGINS=
|
|
5
|
+
# Optional shared API key for development/integration; rights/auth module is out of scope.
|
|
6
|
+
ADMIN_API_KEY=
|
|
7
|
+
DB_TYPE=postgres
|
|
8
|
+
DB_HOST=127.0.0.1
|
|
9
|
+
DB_PORT=5432
|
|
10
|
+
DB_USERNAME=cms
|
|
11
|
+
DB_PASSWORD=cms_dev_password
|
|
12
|
+
DB_DATABASE=cms
|
|
13
|
+
# Dev only. Use migrations in production.
|
|
14
|
+
DB_SYNCHRONIZE=true
|
|
15
|
+
S3_REGION=us-east-1
|
|
16
|
+
S3_BUCKET=cms-attachments
|
|
17
|
+
S3_ENDPOINT=http://127.0.0.1:9000
|
|
18
|
+
S3_FORCE_PATH_STYLE=true
|
|
19
|
+
S3_ACCESS_KEY_ID=minioadmin
|
|
20
|
+
S3_SECRET_ACCESS_KEY=minioadmin123
|
|
21
|
+
ATTACHMENT_MAX_BYTES=20971520
|
package/README.md
CHANGED
|
@@ -1,3 +1,342 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @nestjs-cms/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Add a resource-driven CMS backend to a NestJS application. Define each resource in one file; the module discovers it and provides validated CRUD APIs, filters, lifecycle hooks, and S3-backed attachments.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
Requires Node.js 22+, npm, and a PostgreSQL database. The package supports NestJS 11 with the Express adapter.
|
|
8
|
+
|
|
9
|
+
### 1. Create a NestJS project and install the package
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx @nestjs/cli@11 new nestjs-cms-demo --package-manager npm
|
|
13
|
+
cd nestjs-cms-demo
|
|
14
|
+
npm install @nestjs-cms/core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The npm package includes compiled JavaScript and TypeScript declarations. Imports use `"@nestjs-cms/core"`.
|
|
18
|
+
|
|
19
|
+
The package includes Zod, TypeORM, PostgreSQL/MySQL drivers, dotenv, and the S3 client. The NestJS project supplies the NestJS runtime dependencies.
|
|
20
|
+
|
|
21
|
+
### 2. Create a resource
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
mkdir -p src/resources
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Create `src/resources/pages.ts`:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { defineResource, z } from "@nestjs-cms/core";
|
|
31
|
+
|
|
32
|
+
export default defineResource({
|
|
33
|
+
name: "pages",
|
|
34
|
+
schema: z
|
|
35
|
+
.object({
|
|
36
|
+
title: z.string().trim().min(1).max(200),
|
|
37
|
+
status: z.enum(["draft", "published"]).default("draft"),
|
|
38
|
+
})
|
|
39
|
+
.strict(),
|
|
40
|
+
columns: {
|
|
41
|
+
title: { type: String, length: 200 },
|
|
42
|
+
status: { type: String, length: 20 },
|
|
43
|
+
},
|
|
44
|
+
filterable: ["title", "status"],
|
|
45
|
+
sortable: ["title", "createdAt"],
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Keep the folder inside `src` so the standard Nest compiler builds it into `dist/resources`. Each additional resource requires only one new file in this folder. No resource index or per-resource registration is needed.
|
|
50
|
+
|
|
51
|
+
### 3. Import the CMS module once
|
|
52
|
+
|
|
53
|
+
Add `ResourceModule.forRoot(...)` to the `imports` array in `src/app.module.ts`:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { Module } from "@nestjs/common";
|
|
57
|
+
import { join } from "node:path";
|
|
58
|
+
import { ResourceModule } from "@nestjs-cms/core";
|
|
59
|
+
|
|
60
|
+
@Module({
|
|
61
|
+
imports: [
|
|
62
|
+
ResourceModule.forRoot({ resourcesPath: join(__dirname, "resources") }),
|
|
63
|
+
],
|
|
64
|
+
})
|
|
65
|
+
export class AppModule {}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can keep your existing controllers, providers, and other imports. The module's API-key guard and error filter apply only to CMS routes.
|
|
69
|
+
|
|
70
|
+
### 4. Configure `.env`
|
|
71
|
+
|
|
72
|
+
Create `.env` in the new project's root:
|
|
73
|
+
|
|
74
|
+
```dotenv
|
|
75
|
+
NODE_ENV=development
|
|
76
|
+
PORT=3000
|
|
77
|
+
DB_TYPE=postgres
|
|
78
|
+
DB_HOST=127.0.0.1
|
|
79
|
+
DB_PORT=5432
|
|
80
|
+
DB_USERNAME=cms
|
|
81
|
+
DB_PASSWORD=cms_dev_password
|
|
82
|
+
DB_DATABASE=cms
|
|
83
|
+
DB_SYNCHRONIZE=true
|
|
84
|
+
ADMIN_API_KEY=
|
|
85
|
+
CORS_ORIGINS=
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use credentials for an existing PostgreSQL database. The package loads `.env` automatically. With `DB_SYNCHRONIZE=true`, it creates the resource tables in that database during startup. Use migrations instead in production.
|
|
89
|
+
|
|
90
|
+
If you need a local database and port 5432 is available:
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
docker run --name nestjs-cms-demo-postgres -d \
|
|
94
|
+
-e POSTGRES_USER=cms -e POSTGRES_PASSWORD=cms_dev_password -e POSTGRES_DB=cms \
|
|
95
|
+
-p 127.0.0.1:5432:5432 postgres:17-alpine
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Wait for PostgreSQL to be ready before starting the application. The example above supports plain resource CRUD. **Attachments also require working S3/MinIO storage and an attachment field in the resource definition.**
|
|
99
|
+
|
|
100
|
+
### 4a. Configure storage for attachments
|
|
101
|
+
|
|
102
|
+
For local MinIO, add these settings to your application's `.env`:
|
|
103
|
+
|
|
104
|
+
```dotenv
|
|
105
|
+
S3_REGION=us-east-1
|
|
106
|
+
S3_BUCKET=cms-attachments
|
|
107
|
+
S3_ENDPOINT=http://127.0.0.1:9000
|
|
108
|
+
S3_FORCE_PATH_STYLE=true
|
|
109
|
+
S3_ACCESS_KEY_ID=minioadmin
|
|
110
|
+
S3_SECRET_ACCESS_KEY=minioadmin123
|
|
111
|
+
ATTACHMENT_MAX_BYTES=20971520
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
These credentials match this library's development Compose setup. From the `nestjs-cms` repository checkout, start storage with:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
docker compose up -d --build minio minio-init
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Wait for MinIO to become healthy and `minio-init` to finish successfully; it creates the private `cms-attachments` bucket. The npm package does not start storage or include the Compose setup. You can also use an existing MinIO server: supply its endpoint and credentials and create the bucket beforehand. The endpoint above assumes the application runs on your host machine.
|
|
121
|
+
|
|
122
|
+
For AWS S3 instead, use your bucket's region and name, omit `S3_ENDPOINT`, and set `S3_FORCE_PATH_STYLE=false`. Supply both credential variables, or omit both when using an IAM role. See [AWS S3 configuration](docs/operations.md#aws-s3-configuration) for permissions.
|
|
123
|
+
|
|
124
|
+
In `src/resources/pages.ts`, add this property to the existing `defineResource({...})` object:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
attachments: [
|
|
128
|
+
{ field: "cover", mimeTypes: ["image/jpeg", "image/png", "image/webp"] },
|
|
129
|
+
],
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Attachment fields are declared separately from the Zod schema and database columns. After restarting the application and creating a page, upload a file using its record ID:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
curl -X POST http://localhost:3000/api/pages/RECORD_ID/attachments/cover \
|
|
136
|
+
-F 'file=@/absolute/path/to/cover.png'
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Replace `RECORD_ID` and the file path with your values. If `ADMIN_API_KEY` is configured, include the `X-API-Key` header. Uploads and downloads always pass through the backend attachment API; the browser never connects directly to S3/MinIO.
|
|
140
|
+
|
|
141
|
+
Without working object storage, the application can start and plain resource CRUD still works. Storage is contacted when an attachment operation needs it: uploads fail with HTTP 503 (`Object storage upload unavailable`), and downloads of existing attachments fail with HTTP 503 (`Attachment content unavailable`). There is no local-filesystem fallback. Omitting the S3 settings does not disable attachments; the client uses the default region/bucket and AWS credential chain, which only works if that environment already has access to the matching storage.
|
|
142
|
+
|
|
143
|
+
### 5. Start the application
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
npm run start:dev
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
curl http://localhost:3000/api/_resources
|
|
151
|
+
curl -X POST http://localhost:3000/api/pages \
|
|
152
|
+
-H 'Content-Type: application/json' \
|
|
153
|
+
-d '{"title":"About us"}'
|
|
154
|
+
curl http://localhost:3000/api/pages
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
After adding or removing resource files, rebuild/restart the application. The standard Nest CLI TypeScript build emits the resource files separately; bundlers require additional configuration to preserve those files for runtime discovery.
|
|
158
|
+
|
|
159
|
+
For production, run the host project's `npm run build` and `npm run start:prod`, disable schema synchronization, and apply reviewed migrations. The library does not run or install its demo migrations in your application.
|
|
160
|
+
|
|
161
|
+
### Optional: CORS and shutdown hooks
|
|
162
|
+
|
|
163
|
+
Same-origin frontends do not require CORS. To apply `CORS_ORIGINS` for a separate frontend and enable graceful shutdown, call the helper in your application's existing `src/main.ts`:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { configureCmsApp } from "@nestjs-cms/core";
|
|
167
|
+
|
|
168
|
+
// After NestFactory.create(AppModule), before app.listen(...):
|
|
169
|
+
configureCmsApp(app);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Set `CORS_ORIGINS=http://localhost:5173`, for example. Your host application still controls its listening port, bind address, and bootstrap process. If it already manages CORS and shutdown hooks, keep that configuration instead.
|
|
173
|
+
|
|
174
|
+
## Migrating from `nestjs-cms`
|
|
175
|
+
|
|
176
|
+
The backend package is now named `@nestjs-cms/core`. Once the scoped package is
|
|
177
|
+
published, existing applications can switch with:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
npm uninstall nestjs-cms
|
|
181
|
+
npm install @nestjs-cms/core
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Replace imports from `"nestjs-cms"` with `"@nestjs-cms/core"`, including type
|
|
185
|
+
imports. The API is unchanged by this rename. The admin package remains
|
|
186
|
+
`@nestjs-cms/admin`; the GitHub repository remains `kongyim/nestjs-cms`.
|
|
187
|
+
|
|
188
|
+
## Install a local package
|
|
189
|
+
|
|
190
|
+
From this library's checkout:
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
npm ci
|
|
194
|
+
npm pack
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
This builds `nestjs-cms-core-0.1.0.tgz`, including JavaScript and TypeScript declarations. In the new NestJS project, replace the npm installation step with:
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
npm install /absolute/path/to/nestjs-cms-core-0.1.0.tgz
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The package excludes the demo application, demo resources, demo migrations, tests, and local secrets. Packing does not publish anything to a registry.
|
|
204
|
+
|
|
205
|
+
## Install from GitHub (optional)
|
|
206
|
+
|
|
207
|
+
To use an unpublished revision, install from GitHub instead of npm. This requires
|
|
208
|
+
Git and a GitHub SSH key with access to the repository:
|
|
209
|
+
|
|
210
|
+
```sh
|
|
211
|
+
npm install git+ssh://git@github.com/kongyim/nestjs-cms.git
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The package's `prepare` script builds TypeScript during Git installation. Keep
|
|
215
|
+
npm lifecycle scripts enabled. Append `#<tag-or-commit>` to the Git URL to select
|
|
216
|
+
an existing revision. Imports still use `"@nestjs-cms/core"`.
|
|
217
|
+
|
|
218
|
+
### Troubleshooting: Cannot find module `@nestjs-cms/core`
|
|
219
|
+
|
|
220
|
+
Run `npm ls @nestjs-cms/core` in the consuming application and check that
|
|
221
|
+
`node_modules/@nestjs-cms/core/dist/src/index.js` and `index.d.ts` exist. To reinstall
|
|
222
|
+
the published package, stop the development server and run:
|
|
223
|
+
|
|
224
|
+
```sh
|
|
225
|
+
npm uninstall @nestjs-cms/core
|
|
226
|
+
npm install @nestjs-cms/core
|
|
227
|
+
npm run start:dev
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
For Git installations, missing compiled files can indicate an older revision or
|
|
231
|
+
a failed `prepare` script. Reinstall with `--foreground-scripts` to see build
|
|
232
|
+
output, or use a locally packed package as described above.
|
|
233
|
+
|
|
234
|
+
## Publishing updates to npm
|
|
235
|
+
|
|
236
|
+
For the first release under the new name, run `npm run release:check` and
|
|
237
|
+
`npm run release` from the repository root. Version `0.1.0` can be used because
|
|
238
|
+
`@nestjs-cms/core` is a separate npm package from `nestjs-cms` (provided that
|
|
239
|
+
version has not already been published under the new name).
|
|
240
|
+
|
|
241
|
+
After confirming `npm view @nestjs-cms/core version` returns the new release,
|
|
242
|
+
the owner of the old package can mark it deprecated:
|
|
243
|
+
|
|
244
|
+
```sh
|
|
245
|
+
npm deprecate 'nestjs-cms@*' 'Renamed to @nestjs-cms/core. Install @nestjs-cms/core and update your imports.'
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
This keeps existing versions available while directing users to the new package.
|
|
249
|
+
For subsequent releases, follow the steps below.
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
Run the following commands in the package you changed: the repository root for
|
|
253
|
+
`@nestjs-cms/core`, or `packages/admin` for `@nestjs-cms/admin`. The packages have
|
|
254
|
+
independent versions; release only the packages you changed.
|
|
255
|
+
|
|
256
|
+
```sh
|
|
257
|
+
npm ci
|
|
258
|
+
npm run release:check
|
|
259
|
+
npm run version:patch
|
|
260
|
+
npm run release
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
- `release:check` runs tests, builds the package, and previews the files to publish
|
|
264
|
+
without uploading anything. Review that file list before continuing. For backend
|
|
265
|
+
changes involving the database or storage, also run `npm run test:integration`
|
|
266
|
+
with the required services running.
|
|
267
|
+
- `version:patch` updates `package.json` and `package-lock.json` automatically
|
|
268
|
+
(for example, `0.1.0` → `0.1.1`). No manual version editing is needed.
|
|
269
|
+
Use `version:minor` for a feature release (`0.1.0` → `0.2.0`) or
|
|
270
|
+
`version:major` for a major release (`0.1.0` → `1.0.0`). During `0.x`
|
|
271
|
+
development, document breaking changes explicitly and use a minor release;
|
|
272
|
+
from `1.0.0` onward, use a major release for breaking changes.
|
|
273
|
+
- `release` publishes the current version publicly. Tests run again through
|
|
274
|
+
`prepublishOnly`, and the existing packaging hook builds the package before
|
|
275
|
+
upload. If needed, run `npm login --auth-type=web` first and complete npm's
|
|
276
|
+
authentication prompts.
|
|
277
|
+
|
|
278
|
+
Every published update needs a new version, including README-only updates on npm.
|
|
279
|
+
A published name/version cannot be reused. These scripts do not create Git commits
|
|
280
|
+
or tags: review and commit the code, README, and version/lockfile changes, then
|
|
281
|
+
push them to GitHub to keep the release source recorded.
|
|
282
|
+
|
|
283
|
+
If publication fails after the version bump, fix the problem and run
|
|
284
|
+
`npm run release` again without bumping again, provided that version was not
|
|
285
|
+
published. If the outcome is unclear, check `npm view <package-name>@<version> version`
|
|
286
|
+
first. The version scripts only change local files; `release:check` does not bump
|
|
287
|
+
versions, and `release` does not bump automatically.
|
|
288
|
+
|
|
289
|
+
See [npm version](https://docs.npmjs.com/cli/commands/npm-version/) for version
|
|
290
|
+
updates and [npm publish](https://docs.npmjs.com/cli/commands/npm-publish/) for
|
|
291
|
+
publication rules.
|
|
292
|
+
|
|
293
|
+
## Documentation
|
|
294
|
+
|
|
295
|
+
- [Resource definitions, hooks, and service methods](docs/resources.md)
|
|
296
|
+
- [API contract and frontend examples](docs/api.md)
|
|
297
|
+
- [Environment, databases, storage, and deployment](docs/operations.md)
|
|
298
|
+
|
|
299
|
+
`ResourceService` is exported for use in other application services. It provides CRUD and `createAttachment`, `findAttachment`, `downloadAttachment`, and `removeAttachment`. All browser attachment traffic goes through the backend API.
|
|
300
|
+
|
|
301
|
+
User login, roles, and resource rights are not implemented. Setting `ADMIN_API_KEY` requires `X-API-Key` on CMS requests; production currently requires a key of at least 32 characters. This is an integration mechanism, not a full authentication system.
|
|
302
|
+
|
|
303
|
+
## Develop this library
|
|
304
|
+
|
|
305
|
+
The repository also contains a demo application with `categories` and `articles`. These instructions are for library contributors, not package consumers:
|
|
306
|
+
|
|
307
|
+
```sh
|
|
308
|
+
npm ci
|
|
309
|
+
cp .env.example .env
|
|
310
|
+
docker compose up -d --build
|
|
311
|
+
# Wait for postgres/minio to be healthy and minio-init to exit with code 0.
|
|
312
|
+
npm run seed
|
|
313
|
+
npm run dev
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The first MinIO build compiles a pinned source release and takes longer than subsequent starts. The demo API runs at `http://localhost:3000/api`, and the MinIO console at `http://localhost:9001`.
|
|
317
|
+
|
|
318
|
+
```sh
|
|
319
|
+
npm run format
|
|
320
|
+
npm run format:check
|
|
321
|
+
npm run build
|
|
322
|
+
npm test
|
|
323
|
+
npm run test:integration
|
|
324
|
+
# Optional MySQL verification:
|
|
325
|
+
docker compose --profile mysql up -d mysql
|
|
326
|
+
DB_TYPE=mysql DB_PORT=3307 npm run test:integration
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Integration tests use the dedicated `cms_test` database and real MinIO services. The repository's VS Code settings enable formatting on save when the recommended Prettier extension is installed. These editor settings are not installed into consuming applications.
|
|
330
|
+
|
|
331
|
+
## Scope
|
|
332
|
+
|
|
333
|
+
The package implements resource discovery, CRUD, filters, transactional hooks, and backend-managed attachments. Import/export, image resizing, encrypted/hashed fields, automatic relation expansion, and resource permissions are not included. Multilingual and nested fields use JSON. See the [comparison with the original project](docs/resources.md#comparison-with-the-original-project) for differences from `polyu-souvenirs`.
|
|
334
|
+
|
|
335
|
+
## Reusable admin frontend
|
|
336
|
+
|
|
337
|
+
The companion React package lives in [packages/admin](packages/admin/README.md).
|
|
338
|
+
It provides the portal UI, explicitly configured sections in navigation order,
|
|
339
|
+
nested JSON fields, deferred attachments, and inline password actions. It is
|
|
340
|
+
packaged independently as `@nestjs-cms/admin`; the core backend package does not
|
|
341
|
+
install frontend dependencies. See the package README for build/install steps,
|
|
342
|
+
Next.js setup, and authentication/transport adapters.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.ApiKeyGuard = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const node_crypto_1 = require("node:crypto");
|
|
12
|
+
const config_1 = require("./config");
|
|
13
|
+
let ApiKeyGuard = class ApiKeyGuard {
|
|
14
|
+
canActivate(context) {
|
|
15
|
+
if (!config_1.config.ADMIN_API_KEY)
|
|
16
|
+
return true;
|
|
17
|
+
const header = context.switchToHttp().getRequest().headers["x-api-key"];
|
|
18
|
+
const expected = Buffer.from(config_1.config.ADMIN_API_KEY);
|
|
19
|
+
const actual = Buffer.from(typeof header === "string" ? header : "");
|
|
20
|
+
if (actual.length !== expected.length || !(0, node_crypto_1.timingSafeEqual)(actual, expected))
|
|
21
|
+
throw new common_1.UnauthorizedException();
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
exports.ApiKeyGuard = ApiKeyGuard;
|
|
26
|
+
exports.ApiKeyGuard = ApiKeyGuard = __decorate([
|
|
27
|
+
(0, common_1.Injectable)()
|
|
28
|
+
], ApiKeyGuard);
|
|
29
|
+
//# sourceMappingURL=api-key.guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.guard.js","sourceRoot":"","sources":["../../src/api-key.guard.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAKwB;AACxB,6CAA8C;AAC9C,qCAAkC;AAE3B,IAAM,WAAW,GAAjB,MAAM,WAAW;IACtB,WAAW,CAAC,OAAyB;QACnC,IAAI,CAAC,eAAM,CAAC,aAAa;YAAE,OAAO,IAAI,CAAC;QACvC,MAAM,MAAM,GAAY,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC,OAAO,CACjE,WAAW,CACZ,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,eAAM,CAAC,aAAa,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACrE,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAA,6BAAe,EAAC,MAAM,EAAE,QAAQ,CAAC;YACzE,MAAM,IAAI,8BAAqB,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAZY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;GACA,WAAW,CAYvB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
export declare function readConfig(input?: NodeJS.ProcessEnv): {
|
|
3
|
+
NODE_ENV: "development" | "test" | "production";
|
|
4
|
+
PORT: number;
|
|
5
|
+
HOST: string;
|
|
6
|
+
CORS_ORIGINS: string;
|
|
7
|
+
ADMIN_API_KEY: string;
|
|
8
|
+
DB_TYPE: "postgres" | "mysql";
|
|
9
|
+
DB_HOST: string;
|
|
10
|
+
DB_USERNAME: string;
|
|
11
|
+
DB_PASSWORD: string;
|
|
12
|
+
DB_DATABASE: string;
|
|
13
|
+
DB_SYNCHRONIZE: boolean;
|
|
14
|
+
S3_REGION: string;
|
|
15
|
+
S3_BUCKET: string;
|
|
16
|
+
S3_FORCE_PATH_STYLE: boolean;
|
|
17
|
+
ATTACHMENT_MAX_BYTES: number;
|
|
18
|
+
DB_PORT?: number | undefined;
|
|
19
|
+
S3_ENDPOINT?: string | undefined;
|
|
20
|
+
S3_ACCESS_KEY_ID?: string | undefined;
|
|
21
|
+
S3_SECRET_ACCESS_KEY?: string | undefined;
|
|
22
|
+
};
|
|
23
|
+
export declare const config: {
|
|
24
|
+
NODE_ENV: "development" | "test" | "production";
|
|
25
|
+
PORT: number;
|
|
26
|
+
HOST: string;
|
|
27
|
+
CORS_ORIGINS: string;
|
|
28
|
+
ADMIN_API_KEY: string;
|
|
29
|
+
DB_TYPE: "postgres" | "mysql";
|
|
30
|
+
DB_HOST: string;
|
|
31
|
+
DB_USERNAME: string;
|
|
32
|
+
DB_PASSWORD: string;
|
|
33
|
+
DB_DATABASE: string;
|
|
34
|
+
DB_SYNCHRONIZE: boolean;
|
|
35
|
+
S3_REGION: string;
|
|
36
|
+
S3_BUCKET: string;
|
|
37
|
+
S3_FORCE_PATH_STYLE: boolean;
|
|
38
|
+
ATTACHMENT_MAX_BYTES: number;
|
|
39
|
+
DB_PORT?: number | undefined;
|
|
40
|
+
S3_ENDPOINT?: string | undefined;
|
|
41
|
+
S3_ACCESS_KEY_ID?: string | undefined;
|
|
42
|
+
S3_SECRET_ACCESS_KEY?: string | undefined;
|
|
43
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.config = void 0;
|
|
4
|
+
exports.readConfig = readConfig;
|
|
5
|
+
require("dotenv/config");
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const bool = zod_1.z.enum(["true", "false"]).transform((v) => v === "true");
|
|
8
|
+
const env = zod_1.z.object({
|
|
9
|
+
NODE_ENV: zod_1.z
|
|
10
|
+
.enum(["development", "test", "production"])
|
|
11
|
+
.default("development"),
|
|
12
|
+
PORT: zod_1.z.coerce.number().int().min(1).max(65535).default(3000),
|
|
13
|
+
HOST: zod_1.z.string().default("127.0.0.1"),
|
|
14
|
+
CORS_ORIGINS: zod_1.z.string().default("http://localhost:5173"),
|
|
15
|
+
ADMIN_API_KEY: zod_1.z.string().default(""),
|
|
16
|
+
DB_TYPE: zod_1.z.enum(["postgres", "mysql"]).default("postgres"),
|
|
17
|
+
DB_HOST: zod_1.z.string().default("127.0.0.1"),
|
|
18
|
+
DB_PORT: zod_1.z.coerce.number().int().positive().optional(),
|
|
19
|
+
DB_USERNAME: zod_1.z.string().default("cms"),
|
|
20
|
+
DB_PASSWORD: zod_1.z.string().default("cms_dev_password"),
|
|
21
|
+
DB_DATABASE: zod_1.z.string().default("cms"),
|
|
22
|
+
DB_SYNCHRONIZE: bool.default(false),
|
|
23
|
+
S3_REGION: zod_1.z.string().default("us-east-1"),
|
|
24
|
+
S3_BUCKET: zod_1.z.string().min(3).default("cms-attachments"),
|
|
25
|
+
S3_ENDPOINT: zod_1.z.url().optional(),
|
|
26
|
+
S3_FORCE_PATH_STYLE: bool.default(false),
|
|
27
|
+
S3_ACCESS_KEY_ID: zod_1.z.string().optional(),
|
|
28
|
+
S3_SECRET_ACCESS_KEY: zod_1.z.string().optional(),
|
|
29
|
+
ATTACHMENT_MAX_BYTES: zod_1.z.coerce
|
|
30
|
+
.number()
|
|
31
|
+
.int()
|
|
32
|
+
.positive()
|
|
33
|
+
.max(1024 ** 3)
|
|
34
|
+
.default(20 * 1024 ** 2),
|
|
35
|
+
});
|
|
36
|
+
function readConfig(input = process.env) {
|
|
37
|
+
const config = env.parse(input);
|
|
38
|
+
if (!!config.S3_ACCESS_KEY_ID !== !!config.S3_SECRET_ACCESS_KEY)
|
|
39
|
+
throw new Error("Set both S3 credentials or neither (IAM credential chain)");
|
|
40
|
+
if (config.NODE_ENV === "production" && config.DB_SYNCHRONIZE)
|
|
41
|
+
throw new Error("DB_SYNCHRONIZE is forbidden in production");
|
|
42
|
+
if (config.NODE_ENV === "production" && config.ADMIN_API_KEY.length < 32)
|
|
43
|
+
throw new Error("Production requires ADMIN_API_KEY of at least 32 characters until an authentication module is installed");
|
|
44
|
+
return config;
|
|
45
|
+
}
|
|
46
|
+
exports.config = readConfig();
|
|
47
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { DataSource, DataSourceOptions } from "typeorm";
|
|
3
|
+
import { ResourceDefinition } from "../resource/resource.types";
|
|
4
|
+
export declare function createCmsDataSource(resources: ResourceDefinition[], options?: Pick<DataSourceOptions, "migrations">): DataSource;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createCmsDataSource = createCmsDataSource;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const config_1 = require("../config");
|
|
7
|
+
const resource_registry_1 = require("../resource/resource.registry");
|
|
8
|
+
const attachment_entity_1 = require("../storage/attachment.entity");
|
|
9
|
+
function createCmsDataSource(resources, options = {}) {
|
|
10
|
+
return new typeorm_1.DataSource({
|
|
11
|
+
type: config_1.config.DB_TYPE,
|
|
12
|
+
host: config_1.config.DB_HOST,
|
|
13
|
+
port: config_1.config.DB_PORT ?? (config_1.config.DB_TYPE === "mysql" ? 3306 : 5432),
|
|
14
|
+
username: config_1.config.DB_USERNAME,
|
|
15
|
+
password: config_1.config.DB_PASSWORD,
|
|
16
|
+
database: config_1.config.DB_DATABASE,
|
|
17
|
+
synchronize: config_1.config.DB_SYNCHRONIZE,
|
|
18
|
+
entities: [...resources.map(resource_registry_1.createEntity), attachment_entity_1.AttachmentEntity],
|
|
19
|
+
migrations: options.migrations ?? [],
|
|
20
|
+
...(config_1.config.DB_TYPE === "mysql" ? { charset: "utf8mb4" } : {}),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=create-data-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-data-source.js","sourceRoot":"","sources":["../../../src/database/create-data-source.ts"],"names":[],"mappings":";;AAOA,kDAgBC;AAvBD,4BAA0B;AAC1B,qCAAwD;AACxD,sCAAmC;AAEnC,qEAA6D;AAC7D,oEAAgE;AAEhE,SAAgB,mBAAmB,CACjC,SAA+B,EAC/B,UAAiD,EAAE;IAEnD,OAAO,IAAI,oBAAU,CAAC;QACpB,IAAI,EAAE,eAAM,CAAC,OAAO;QACpB,IAAI,EAAE,eAAM,CAAC,OAAO;QACpB,IAAI,EAAE,eAAM,CAAC,OAAO,IAAI,CAAC,eAAM,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAClE,QAAQ,EAAE,eAAM,CAAC,WAAW;QAC5B,QAAQ,EAAE,eAAM,CAAC,WAAW;QAC5B,QAAQ,EAAE,eAAM,CAAC,WAAW;QAC5B,WAAW,EAAE,eAAM,CAAC,cAAc;QAClC,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,gCAAY,CAAC,EAAE,oCAAgB,CAAC;QAC5D,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,GAAG,CAAC,eAAM,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ArgumentsHost, ExceptionFilter } from "@nestjs/common";
|
|
2
|
+
import { Response } from "express";
|
|
3
|
+
export declare class ErrorFilter implements ExceptionFilter {
|
|
4
|
+
private readonly logger;
|
|
5
|
+
catch(error: unknown, host: ArgumentsHost): Response<any, Record<string, any>>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var ErrorFilter_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ErrorFilter = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const typeorm_1 = require("typeorm");
|
|
13
|
+
let ErrorFilter = ErrorFilter_1 = class ErrorFilter {
|
|
14
|
+
logger = new common_1.Logger(ErrorFilter_1.name);
|
|
15
|
+
catch(error, host) {
|
|
16
|
+
const response = host.switchToHttp().getResponse();
|
|
17
|
+
if (error instanceof common_1.HttpException)
|
|
18
|
+
return response.status(error.getStatus()).json(error.getResponse());
|
|
19
|
+
if (error instanceof typeorm_1.QueryFailedError) {
|
|
20
|
+
const code = String(error.driverError.code);
|
|
21
|
+
if ([
|
|
22
|
+
"23505",
|
|
23
|
+
"ER_DUP_ENTRY",
|
|
24
|
+
"23503",
|
|
25
|
+
"ER_ROW_IS_REFERENCED_2",
|
|
26
|
+
"ER_NO_REFERENCED_ROW_2",
|
|
27
|
+
].includes(code))
|
|
28
|
+
return response.status(409).json({
|
|
29
|
+
statusCode: 409,
|
|
30
|
+
message: "Unique or reference constraint conflict",
|
|
31
|
+
});
|
|
32
|
+
if ([
|
|
33
|
+
"22P02",
|
|
34
|
+
"22003",
|
|
35
|
+
"22007",
|
|
36
|
+
"ER_TRUNCATED_WRONG_VALUE",
|
|
37
|
+
"ER_WRONG_VALUE",
|
|
38
|
+
"ER_DATA_OUT_OF_RANGE",
|
|
39
|
+
].includes(code))
|
|
40
|
+
return response
|
|
41
|
+
.status(400)
|
|
42
|
+
.json({ statusCode: 400, message: "Invalid query value" });
|
|
43
|
+
}
|
|
44
|
+
this.logger.error(error instanceof Error ? error.message : "Unexpected error");
|
|
45
|
+
return response
|
|
46
|
+
.status(500)
|
|
47
|
+
.json({ statusCode: 500, message: "Internal server error" });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.ErrorFilter = ErrorFilter;
|
|
51
|
+
exports.ErrorFilter = ErrorFilter = ErrorFilter_1 = __decorate([
|
|
52
|
+
(0, common_1.Catch)()
|
|
53
|
+
], ErrorFilter);
|
|
54
|
+
//# sourceMappingURL=error.filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.filter.js","sourceRoot":"","sources":["../../src/error.filter.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAMwB;AACxB,qCAA2C;AAGpC,IAAM,WAAW,mBAAjB,MAAM,WAAW;IACL,MAAM,GAAG,IAAI,eAAM,CAAC,aAAW,CAAC,IAAI,CAAC,CAAC;IACvD,KAAK,CAAC,KAAc,EAAE,IAAmB;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,WAAW,EAAY,CAAC;QAC7D,IAAI,KAAK,YAAY,sBAAa;YAChC,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QACtE,IAAI,KAAK,YAAY,0BAAgB,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,MAAM,CAAE,KAAK,CAAC,WAAiC,CAAC,IAAI,CAAC,CAAC;YACnE,IACE;gBACE,OAAO;gBACP,cAAc;gBACd,OAAO;gBACP,wBAAwB;gBACxB,wBAAwB;aACzB,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAEhB,OAAO,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBAC/B,UAAU,EAAE,GAAG;oBACf,OAAO,EAAE,yCAAyC;iBACnD,CAAC,CAAC;YACL,IACE;gBACE,OAAO;gBACP,OAAO;gBACP,OAAO;gBACP,0BAA0B;gBAC1B,gBAAgB;gBAChB,sBAAsB;aACvB,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAEhB,OAAO,QAAQ;qBACZ,MAAM,CAAC,GAAG,CAAC;qBACX,IAAI,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAC5D,CAAC;QACF,OAAO,QAAQ;aACZ,MAAM,CAAC,GAAG,CAAC;aACX,IAAI,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;IACjE,CAAC;CACF,CAAA;AA1CY,kCAAW;sBAAX,WAAW;IADvB,IAAA,cAAK,GAAE;GACK,WAAW,CA0CvB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
export { z } from "zod";
|
|
3
|
+
export { ResourceModule } from "./resource/resource.module";
|
|
4
|
+
export type { ResourceModuleOptions } from "./resource/resource.module";
|
|
5
|
+
export { ResourceService } from "./resource/resource.service";
|
|
6
|
+
export { ResourceRegistry } from "./resource/resource.registry";
|
|
7
|
+
export { defineResource } from "./resource/resource.types";
|
|
8
|
+
export type { ResourceDefinition, ResourceHook, HookContext, HookAction, RecordData, AttachmentField, UploadedAttachment, } from "./resource/resource.types";
|
|
9
|
+
export { loadResources } from "./resource/resource.loader";
|
|
10
|
+
export { createCmsDataSource } from "./database/create-data-source";
|
|
11
|
+
export { AttachmentService } from "./storage/attachment.service";
|
|
12
|
+
export { configureCmsApp } from "./setup";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configureCmsApp = exports.AttachmentService = exports.createCmsDataSource = exports.loadResources = exports.defineResource = exports.ResourceRegistry = exports.ResourceService = exports.ResourceModule = exports.z = void 0;
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
var zod_1 = require("zod");
|
|
6
|
+
Object.defineProperty(exports, "z", { enumerable: true, get: function () { return zod_1.z; } });
|
|
7
|
+
var resource_module_1 = require("./resource/resource.module");
|
|
8
|
+
Object.defineProperty(exports, "ResourceModule", { enumerable: true, get: function () { return resource_module_1.ResourceModule; } });
|
|
9
|
+
var resource_service_1 = require("./resource/resource.service");
|
|
10
|
+
Object.defineProperty(exports, "ResourceService", { enumerable: true, get: function () { return resource_service_1.ResourceService; } });
|
|
11
|
+
var resource_registry_1 = require("./resource/resource.registry");
|
|
12
|
+
Object.defineProperty(exports, "ResourceRegistry", { enumerable: true, get: function () { return resource_registry_1.ResourceRegistry; } });
|
|
13
|
+
var resource_types_1 = require("./resource/resource.types");
|
|
14
|
+
Object.defineProperty(exports, "defineResource", { enumerable: true, get: function () { return resource_types_1.defineResource; } });
|
|
15
|
+
var resource_loader_1 = require("./resource/resource.loader");
|
|
16
|
+
Object.defineProperty(exports, "loadResources", { enumerable: true, get: function () { return resource_loader_1.loadResources; } });
|
|
17
|
+
var create_data_source_1 = require("./database/create-data-source");
|
|
18
|
+
Object.defineProperty(exports, "createCmsDataSource", { enumerable: true, get: function () { return create_data_source_1.createCmsDataSource; } });
|
|
19
|
+
var attachment_service_1 = require("./storage/attachment.service");
|
|
20
|
+
Object.defineProperty(exports, "AttachmentService", { enumerable: true, get: function () { return attachment_service_1.AttachmentService; } });
|
|
21
|
+
var setup_1 = require("./setup");
|
|
22
|
+
Object.defineProperty(exports, "configureCmsApp", { enumerable: true, get: function () { return setup_1.configureCmsApp; } });
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,4BAA0B;AAC1B,2BAAwB;AAAf,wFAAA,CAAC,OAAA;AACV,8DAA4D;AAAnD,iHAAA,cAAc,OAAA;AAEvB,gEAA8D;AAArD,mHAAA,eAAe,OAAA;AACxB,kEAAgE;AAAvD,qHAAA,gBAAgB,OAAA;AACzB,4DAA2D;AAAlD,gHAAA,cAAc,OAAA;AAUvB,8DAA2D;AAAlD,gHAAA,aAAa,OAAA;AACtB,oEAAoE;AAA3D,yHAAA,mBAAmB,OAAA;AAC5B,mEAAiE;AAAxD,uHAAA,iBAAiB,OAAA;AAC1B,iCAA0C;AAAjC,wGAAA,eAAe,OAAA"}
|