@spinajs/configuration-http 2.0.480 → 2.0.482

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +30 -7
  2. package/lib/cjs/bootstrap.d.ts +20 -0
  3. package/lib/cjs/bootstrap.d.ts.map +1 -0
  4. package/lib/cjs/bootstrap.js +40 -0
  5. package/lib/cjs/bootstrap.js.map +1 -0
  6. package/lib/cjs/config/configuration-http.d.ts +34 -0
  7. package/lib/cjs/config/configuration-http.d.ts.map +1 -0
  8. package/lib/cjs/config/configuration-http.js +41 -0
  9. package/lib/cjs/config/configuration-http.js.map +1 -0
  10. package/lib/cjs/controllers/Configuration.d.ts +66 -0
  11. package/lib/cjs/controllers/Configuration.d.ts.map +1 -0
  12. package/lib/cjs/controllers/Configuration.js +170 -0
  13. package/lib/cjs/controllers/Configuration.js.map +1 -0
  14. package/lib/cjs/dto/update-config-dto.d.ts +14 -0
  15. package/lib/cjs/dto/update-config-dto.d.ts.map +1 -0
  16. package/lib/cjs/dto/update-config-dto.js +42 -0
  17. package/lib/cjs/dto/update-config-dto.js.map +1 -0
  18. package/lib/cjs/index.d.ts +5 -0
  19. package/lib/cjs/index.d.ts.map +1 -0
  20. package/lib/cjs/index.js +21 -0
  21. package/lib/cjs/index.js.map +1 -0
  22. package/lib/cjs/package.json +1 -0
  23. package/lib/cjs/validation.d.ts +29 -0
  24. package/lib/cjs/validation.d.ts.map +1 -0
  25. package/lib/cjs/validation.js +72 -0
  26. package/lib/cjs/validation.js.map +1 -0
  27. package/lib/mjs/bootstrap.d.ts +20 -0
  28. package/lib/mjs/bootstrap.d.ts.map +1 -0
  29. package/lib/mjs/bootstrap.js +37 -0
  30. package/lib/mjs/bootstrap.js.map +1 -0
  31. package/lib/mjs/config/configuration-http.d.ts +34 -0
  32. package/lib/mjs/config/configuration-http.d.ts.map +1 -0
  33. package/lib/mjs/config/configuration-http.js +39 -0
  34. package/lib/mjs/config/configuration-http.js.map +1 -0
  35. package/lib/mjs/controllers/Configuration.d.ts +66 -0
  36. package/lib/mjs/controllers/Configuration.d.ts.map +1 -0
  37. package/lib/mjs/controllers/Configuration.js +167 -0
  38. package/lib/mjs/controllers/Configuration.js.map +1 -0
  39. package/lib/mjs/dto/update-config-dto.d.ts +14 -0
  40. package/lib/mjs/dto/update-config-dto.d.ts.map +1 -0
  41. package/lib/mjs/dto/update-config-dto.js +39 -0
  42. package/lib/mjs/dto/update-config-dto.js.map +1 -0
  43. package/lib/mjs/index.d.ts +5 -0
  44. package/lib/mjs/index.d.ts.map +1 -0
  45. package/lib/mjs/index.js +5 -0
  46. package/lib/mjs/index.js.map +1 -0
  47. package/lib/mjs/package.json +1 -0
  48. package/lib/mjs/validation.d.ts +29 -0
  49. package/lib/mjs/validation.d.ts.map +1 -0
  50. package/lib/mjs/validation.js +68 -0
  51. package/lib/mjs/validation.js.map +1 -0
  52. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  53. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  54. package/package.json +30 -7
package/README.md CHANGED
@@ -1,11 +1,34 @@
1
- # `@spinajs/configuration-common`
1
+ # `@spinajs/configuration-http`
2
2
 
3
- > TODO: description
3
+ HTTP API for reading and updating database-stored configuration values managed by
4
+ [`@spinajs/configuration-db-source`](../configuration-db-source).
4
5
 
5
- ## Usage
6
+ It exposes a read + update CRUD surface over the `configuration` table. Entries
7
+ themselves are created by code that exposes config options (`expose: true`), so
8
+ this API intentionally does **not** create or delete arbitrary entries — it only
9
+ lets operators tune existing values.
6
10
 
7
- ```
8
- const configurationCommon = require('@spinajs/configuration-common');
11
+ ## Endpoints
9
12
 
10
- // TODO: DEMONSTRATE API
11
- ```
13
+ | Method | Path | Permission | Description |
14
+ | ------ | ------------------------ | ----------- | -------------------------------------------- |
15
+ | GET | `/configuration` | `readAny` | List all entries (optional `?group=` filter) |
16
+ | GET | `/configuration/:slug` | `readAny` | Get a single entry by slug |
17
+ | PATCH | `/configuration/:slug` | `updateAny` | Update an entry's `Value` (+ `Default`/`Watch`) |
18
+
19
+ All routes require a valid session (`AuthorizedPolicy`) and are guarded by
20
+ `RbacPolicy` on the `configuration` resource.
21
+
22
+ Incoming values are validated against the entry `Type` and `Meta` constraints
23
+ (min/max, oneOf/manyOf, date bounds) and stored in their canonical string form.
24
+
25
+ ## RBAC
26
+
27
+ The package ships a dedicated `configuration` role granting `read:any` /
28
+ `update:any` on the `configuration` resource, and extends `admin` with it. Grant
29
+ the `configuration` role (or `admin`) to give an account access to the API.
30
+
31
+ ## Notes
32
+
33
+ Writes are persisted to the database only. The running application picks up the
34
+ change through the db-source watch poll, and only for entries with `Watch = true`.
@@ -0,0 +1,20 @@
1
+ import { Bootstrapper } from '@spinajs/di';
2
+ /**
3
+ * Ties the `DbConfig` model to the `configuration` RBAC resource.
4
+ *
5
+ * `DbConfig` lives in the persistence-only `@spinajs/configuration-db-source`
6
+ * package, which intentionally does not depend on rbac. Its `@Model('configuration')`
7
+ * only names the database table - that is NOT the RBAC resource. Set the model's
8
+ * `RbacResource` here ( this http package already depends on rbac ) so the
9
+ * `RbacModelPermissionMiddleware` enforces `configuration` grants on every
10
+ * DbConfig query, matching the route-level `@Resource('configuration')` on the
11
+ * controller.
12
+ *
13
+ * Without this the model descriptor has no `RbacResource`, so model-level
14
+ * permission checks are silently skipped ( the middleware's table-name fallback
15
+ * is disabled ) and only the route-level policy would guard the data.
16
+ */
17
+ export declare class ConfigurationHttpBootstrapper extends Bootstrapper {
18
+ bootstrap(): void;
19
+ }
20
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAKvD;;;;;;;;;;;;;;GAcG;AACH,qBACa,6BAA8B,SAAQ,YAAY;IACtD,SAAS,IAAI,IAAI;CAMzB"}
@@ -0,0 +1,40 @@
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.ConfigurationHttpBootstrapper = void 0;
10
+ const di_1 = require("@spinajs/di");
11
+ const orm_1 = require("@spinajs/orm");
12
+ const configuration_db_source_1 = require("@spinajs/configuration-db-source");
13
+ /**
14
+ * Ties the `DbConfig` model to the `configuration` RBAC resource.
15
+ *
16
+ * `DbConfig` lives in the persistence-only `@spinajs/configuration-db-source`
17
+ * package, which intentionally does not depend on rbac. Its `@Model('configuration')`
18
+ * only names the database table - that is NOT the RBAC resource. Set the model's
19
+ * `RbacResource` here ( this http package already depends on rbac ) so the
20
+ * `RbacModelPermissionMiddleware` enforces `configuration` grants on every
21
+ * DbConfig query, matching the route-level `@Resource('configuration')` on the
22
+ * controller.
23
+ *
24
+ * Without this the model descriptor has no `RbacResource`, so model-level
25
+ * permission checks are silently skipped ( the middleware's table-name fallback
26
+ * is disabled ) and only the route-level policy would guard the data.
27
+ */
28
+ let ConfigurationHttpBootstrapper = class ConfigurationHttpBootstrapper extends di_1.Bootstrapper {
29
+ bootstrap() {
30
+ const descriptor = (0, orm_1.extractModelDescriptor)(configuration_db_source_1.DbConfig);
31
+ if (descriptor) {
32
+ descriptor.RbacResource = 'configuration';
33
+ }
34
+ }
35
+ };
36
+ exports.ConfigurationHttpBootstrapper = ConfigurationHttpBootstrapper;
37
+ exports.ConfigurationHttpBootstrapper = ConfigurationHttpBootstrapper = __decorate([
38
+ (0, di_1.Injectable)(di_1.Bootstrapper)
39
+ ], ConfigurationHttpBootstrapper);
40
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oCAAuD;AACvD,sCAAsD;AACtD,8EAA4D;AAG5D;;;;;;;;;;;;;;GAcG;AAEI,IAAM,6BAA6B,GAAnC,MAAM,6BAA8B,SAAQ,iBAAY;IACtD,SAAS;QACd,MAAM,UAAU,GAAG,IAAA,4BAAsB,EAAC,kCAAQ,CAAyB,CAAC;QAC5E,IAAI,UAAU,EAAE,CAAC;YACf,UAAU,CAAC,YAAY,GAAG,eAAe,CAAC;QAC5C,CAAC;IACH,CAAC;CACF,CAAA;AAPY,sEAA6B;wCAA7B,6BAA6B;IADzC,IAAA,eAAU,EAAC,iBAAY,CAAC;GACZ,6BAA6B,CAOzC"}
@@ -0,0 +1,34 @@
1
+ declare const configurationHttp: {
2
+ system: {
3
+ dirs: {
4
+ controllers: string[];
5
+ };
6
+ };
7
+ rbac: {
8
+ grants: {
9
+ /**
10
+ * Dedicated admin sub-role granting full management over configuration
11
+ * entries. Mirrors the `admin.users` sub-role in @spinajs/rbac: only the
12
+ * `admin` role ( and `system`, which extends admin ) inherits it below, so
13
+ * the configuration HTTP api is an admin-only capability. The resource
14
+ * itself is named `configuration` ( see @Resource in the controller ).
15
+ */
16
+ 'admin.configuration': {
17
+ configuration: {
18
+ 'read:any': string[];
19
+ 'update:any': string[];
20
+ };
21
+ };
22
+ /**
23
+ * Admin inherits configuration management. The config merge concatenates
24
+ * `$extend` arrays, so this is additive - it does not overwrite the base
25
+ * admin grants ( eg. `admin.users` ).
26
+ */
27
+ admin: {
28
+ $extend: string[];
29
+ };
30
+ };
31
+ };
32
+ };
33
+ export default configurationHttp;
34
+ //# sourceMappingURL=configuration-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration-http.d.ts","sourceRoot":"","sources":["../../../src/config/configuration-http.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,iBAAiB;;;;;;;;YAQjB;;;;;;eAMG;;;;;;;YAQH;;;;eAIG;;;;;;CAMR,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path_1 = require("path");
4
+ function dir(path) {
5
+ const inCommonJs = typeof module !== 'undefined';
6
+ return (0, path_1.resolve)((0, path_1.normalize)((0, path_1.join)(process.env.WORKSPACE_ROOT_PATH ?? process.cwd(), 'node_modules', '@spinajs', 'configuration-http', 'lib', inCommonJs ? 'cjs' : 'mjs', path)));
7
+ }
8
+ const configurationHttp = {
9
+ system: {
10
+ dirs: {
11
+ controllers: [dir('controllers')],
12
+ },
13
+ },
14
+ rbac: {
15
+ grants: {
16
+ /**
17
+ * Dedicated admin sub-role granting full management over configuration
18
+ * entries. Mirrors the `admin.users` sub-role in @spinajs/rbac: only the
19
+ * `admin` role ( and `system`, which extends admin ) inherits it below, so
20
+ * the configuration HTTP api is an admin-only capability. The resource
21
+ * itself is named `configuration` ( see @Resource in the controller ).
22
+ */
23
+ 'admin.configuration': {
24
+ configuration: {
25
+ 'read:any': ['*'],
26
+ 'update:any': ['*'],
27
+ },
28
+ },
29
+ /**
30
+ * Admin inherits configuration management. The config merge concatenates
31
+ * `$extend` arrays, so this is additive - it does not overwrite the base
32
+ * admin grants ( eg. `admin.users` ).
33
+ */
34
+ admin: {
35
+ $extend: ['admin.configuration'],
36
+ },
37
+ },
38
+ },
39
+ };
40
+ exports.default = configurationHttp;
41
+ //# sourceMappingURL=configuration-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration-http.js","sourceRoot":"","sources":["../../../src/config/configuration-http.ts"],"names":[],"mappings":";;AAAA,+BAAgD;AAEhD,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;IACjD,OAAO,IAAA,cAAO,EAAC,IAAA,gBAAS,EAAC,IAAA,WAAI,EAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,oBAAoB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/K,CAAC;AAED,MAAM,iBAAiB,GAAG;IACxB,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,WAAW,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;SAClC;KACF;IACD,IAAI,EAAE;QACJ,MAAM,EAAE;YACN;;;;;;eAMG;YACH,qBAAqB,EAAE;gBACrB,aAAa,EAAE;oBACb,UAAU,EAAE,CAAC,GAAG,CAAC;oBACjB,YAAY,EAAE,CAAC,GAAG,CAAC;iBACpB;aACF;YAED;;;;eAIG;YACH,KAAK,EAAE;gBACL,OAAO,EAAE,CAAC,qBAAqB,CAAC;aACjC;SACF;KACF;CACF,CAAC;AAEF,kBAAe,iBAAiB,CAAC"}
@@ -0,0 +1,66 @@
1
+ import { BadRequestResponse, BaseController, Ok } from '@spinajs/http';
2
+ import { DataValidator } from '@spinajs/validation';
3
+ import { DbConfig } from '@spinajs/configuration-db-source';
4
+ import { UpdateConfigDto } from '../dto/update-config-dto.js';
5
+ /**
6
+ * HTTP api for database stored configuration values.
7
+ *
8
+ * Exposes read and update operations over the `configuration` table managed by
9
+ * `@spinajs/configuration-db-source`. Entries themselves are created by code
10
+ * that exposes config options ( `expose: true` ), so this api intentionally does
11
+ * NOT allow creating or deleting arbitrary entries - only tuning their values.
12
+ *
13
+ * Writes are persisted to the database only. The running application picks up
14
+ * the change through the db-source watch poll, and only for entries with
15
+ * `Watch = true`.
16
+ *
17
+ * @tags Configuration
18
+ */
19
+ export declare class ConfigurationController extends BaseController {
20
+ protected Validator: DataValidator;
21
+ /**
22
+ * List configuration entries
23
+ * Returns all database stored configuration entries, optionally filtered by group.
24
+ * @security cookieAuth
25
+ * @param group Optional group name to filter entries by
26
+ * @response 200 List of configuration entries
27
+ * @response 401 Unauthorized — valid session required
28
+ * @response 403 Forbidden — readAny permission required on configuration resource
29
+ */
30
+ list(group?: string): Promise<Ok<Record<string, unknown>[]>>;
31
+ /**
32
+ * Get configuration entry
33
+ * Returns a single configuration entry identified by its slug.
34
+ * @security cookieAuth
35
+ * @param slug Unique configuration entry slug
36
+ * @response 200 Configuration entry
37
+ * @response 401 Unauthorized — valid session required
38
+ * @response 403 Forbidden — readAny permission required on configuration resource
39
+ * @response 404 Configuration entry not found
40
+ */
41
+ get(entry: DbConfig): Promise<Ok<Record<string, unknown>>>;
42
+ /**
43
+ * Update configuration entry value
44
+ * Updates the value ( and optionally default/watch flag ) of an existing entry.
45
+ * The incoming value is validated against the entry `Type` and `Meta` constraints.
46
+ * Structural fields ( slug, group, type ) cannot be changed through this api.
47
+ * @security cookieAuth
48
+ * @param slug Unique configuration entry slug
49
+ * @response 200 Updated configuration entry
50
+ * @response 400 Invalid value for the entry type or constraints
51
+ * @response 401 Unauthorized — valid session required
52
+ * @response 403 Forbidden — updateAny permission required on configuration resource
53
+ * @response 404 Configuration entry not found
54
+ */
55
+ update(entry: DbConfig, data: UpdateConfigDto): Promise<Ok<Record<string, unknown>> | BadRequestResponse<any>>;
56
+ /**
57
+ * Validates a single value against the entry value schema, returning a 400
58
+ * response on failure or `null` when it passes.
59
+ *
60
+ * The value is wrapped in an object ( `{ [field]: value }` ) so it is always a
61
+ * non-null object for the validator - a bare `null` / scalar would otherwise
62
+ * confuse `tryValidate`'s schema-vs-data overload resolution.
63
+ */
64
+ private validateValue;
65
+ }
66
+ //# sourceMappingURL=Configuration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Configuration.d.ts","sourceRoot":"","sources":["../../../src/controllers/Configuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAuB,EAAE,EAAwB,MAAM,eAAe,CAAC;AAGlH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAgB9D;;;;;;;;;;;;;GAaG;AACH,qBAGa,uBAAwB,SAAQ,cAAc;IAEzD,SAAS,CAAC,SAAS,EAAG,aAAa,CAAC;IAEpC;;;;;;;;OAQG;IAGU,IAAI,CAAU,KAAK,CAAC,EAAE,MAAM;IAKzC;;;;;;;;;OASG;IAGU,GAAG,CAAwD,KAAK,EAAE,QAAQ;IAIvF;;;;;;;;;;;;OAYG;IAGU,MAAM,CAAwD,KAAK,EAAE,QAAQ,EAAU,IAAI,EAAE,eAAe;IAmCzH;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;CActB"}
@@ -0,0 +1,170 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ConfigurationController = void 0;
16
+ const http_1 = require("@spinajs/http");
17
+ const rbac_http_1 = require("@spinajs/rbac-http");
18
+ const di_1 = require("@spinajs/di");
19
+ const validation_1 = require("@spinajs/validation");
20
+ const orm_http_1 = require("@spinajs/orm-http");
21
+ const configuration_db_source_1 = require("@spinajs/configuration-db-source");
22
+ const update_config_dto_js_1 = require("../dto/update-config-dto.js");
23
+ const validation_js_1 = require("../validation.js");
24
+ /**
25
+ * Serializes an entry for the api. `DbConfig.dehydrate()` emits only the declared
26
+ * columns with Value / Default in their canonical stored form ( numbers as "10",
27
+ * booleans as "true"/"false", dates / times as ISO 8601 etc. ) produced by the
28
+ * DbConfigValueConverter, and Meta already parsed into an object by its @Json
29
+ * converter - the same representation they round-trip through on update.
30
+ */
31
+ function present(entry) {
32
+ const out = entry.dehydrate();
33
+ out.Meta = entry.Meta ?? null;
34
+ return out;
35
+ }
36
+ /**
37
+ * HTTP api for database stored configuration values.
38
+ *
39
+ * Exposes read and update operations over the `configuration` table managed by
40
+ * `@spinajs/configuration-db-source`. Entries themselves are created by code
41
+ * that exposes config options ( `expose: true` ), so this api intentionally does
42
+ * NOT allow creating or deleting arbitrary entries - only tuning their values.
43
+ *
44
+ * Writes are persisted to the database only. The running application picks up
45
+ * the change through the db-source watch poll, and only for entries with
46
+ * `Watch = true`.
47
+ *
48
+ * @tags Configuration
49
+ */
50
+ let ConfigurationController = class ConfigurationController extends http_1.BaseController {
51
+ /**
52
+ * List configuration entries
53
+ * Returns all database stored configuration entries, optionally filtered by group.
54
+ * @security cookieAuth
55
+ * @param group Optional group name to filter entries by
56
+ * @response 200 List of configuration entries
57
+ * @response 401 Unauthorized — valid session required
58
+ * @response 403 Forbidden — readAny permission required on configuration resource
59
+ */
60
+ async list(group) {
61
+ const entries = await (group ? configuration_db_source_1.DbConfig.where('Group', group) : configuration_db_source_1.DbConfig.all());
62
+ return new http_1.Ok(entries.map((e) => present(e)));
63
+ }
64
+ /**
65
+ * Get configuration entry
66
+ * Returns a single configuration entry identified by its slug.
67
+ * @security cookieAuth
68
+ * @param slug Unique configuration entry slug
69
+ * @response 200 Configuration entry
70
+ * @response 401 Unauthorized — valid session required
71
+ * @response 403 Forbidden — readAny permission required on configuration resource
72
+ * @response 404 Configuration entry not found
73
+ */
74
+ async get(entry) {
75
+ return new http_1.Ok(present(entry));
76
+ }
77
+ /**
78
+ * Update configuration entry value
79
+ * Updates the value ( and optionally default/watch flag ) of an existing entry.
80
+ * The incoming value is validated against the entry `Type` and `Meta` constraints.
81
+ * Structural fields ( slug, group, type ) cannot be changed through this api.
82
+ * @security cookieAuth
83
+ * @param slug Unique configuration entry slug
84
+ * @response 200 Updated configuration entry
85
+ * @response 400 Invalid value for the entry type or constraints
86
+ * @response 401 Unauthorized — valid session required
87
+ * @response 403 Forbidden — updateAny permission required on configuration resource
88
+ * @response 404 Configuration entry not found
89
+ */
90
+ async update(entry, data) {
91
+ // Build the value schema from the entry Type + Meta ( entry.Meta is already an
92
+ // object here, parsed by its @Json converter on load ) and validate the
93
+ // incoming value(s) against it. Validation can only happen here - not on the
94
+ // request DTO - because the entry Type isn't known until after this lookup.
95
+ const schema = (0, validation_js_1.valueSchema)(entry.Type, entry.Meta);
96
+ const valueError = this.validateValue(schema, 'Value', data.Value);
97
+ if (valueError) {
98
+ return valueError;
99
+ }
100
+ if (data.Default !== undefined) {
101
+ const defaultError = this.validateValue(schema, 'Default', data.Default);
102
+ if (defaultError) {
103
+ return defaultError;
104
+ }
105
+ }
106
+ // Assign the raw, validated value(s). The DbConfigValueConverter does all the
107
+ // type-based coercion into the canonical stored form on update().
108
+ entry.Value = data.Value;
109
+ if (data.Default !== undefined) {
110
+ entry.Default = data.Default;
111
+ }
112
+ if (data.Watch !== undefined) {
113
+ entry.Watch = data.Watch;
114
+ }
115
+ await entry.update();
116
+ return new http_1.Ok(present(entry));
117
+ }
118
+ /**
119
+ * Validates a single value against the entry value schema, returning a 400
120
+ * response on failure or `null` when it passes.
121
+ *
122
+ * The value is wrapped in an object ( `{ [field]: value }` ) so it is always a
123
+ * non-null object for the validator - a bare `null` / scalar would otherwise
124
+ * confuse `tryValidate`'s schema-vs-data overload resolution.
125
+ */
126
+ validateValue(valueSchema, field, value) {
127
+ const [isValid, errors] = this.Validator.tryValidate({ type: 'object', properties: { [field]: valueSchema }, required: [field] }, { [field]: value });
128
+ if (isValid) {
129
+ return null;
130
+ }
131
+ const message = (errors ?? []).map((e) => `${field}${e.instancePath ? e.instancePath.replace(`/${field}`, '') : ''} ${e.message ?? 'is invalid'}`.trim()).join('; ') || `invalid value for ${field}`;
132
+ return new http_1.BadRequestResponse({ error: { message } });
133
+ }
134
+ };
135
+ exports.ConfigurationController = ConfigurationController;
136
+ __decorate([
137
+ (0, di_1.Autoinject)(),
138
+ __metadata("design:type", validation_1.DataValidator)
139
+ ], ConfigurationController.prototype, "Validator", void 0);
140
+ __decorate([
141
+ (0, http_1.Get)('/'),
142
+ (0, rbac_http_1.Permission)(['readAny']),
143
+ __param(0, (0, http_1.Query)()),
144
+ __metadata("design:type", Function),
145
+ __metadata("design:paramtypes", [String]),
146
+ __metadata("design:returntype", Promise)
147
+ ], ConfigurationController.prototype, "list", null);
148
+ __decorate([
149
+ (0, http_1.Get)(':slug'),
150
+ (0, rbac_http_1.Permission)(['readAny']),
151
+ __param(0, (0, orm_http_1.FromModel)({ paramField: 'slug', queryField: 'Slug' })),
152
+ __metadata("design:type", Function),
153
+ __metadata("design:paramtypes", [configuration_db_source_1.DbConfig]),
154
+ __metadata("design:returntype", Promise)
155
+ ], ConfigurationController.prototype, "get", null);
156
+ __decorate([
157
+ (0, http_1.Patch)(':slug'),
158
+ (0, rbac_http_1.Permission)(['updateAny']),
159
+ __param(0, (0, orm_http_1.FromModel)({ paramField: 'slug', queryField: 'Slug' })),
160
+ __param(1, (0, http_1.Body)()),
161
+ __metadata("design:type", Function),
162
+ __metadata("design:paramtypes", [configuration_db_source_1.DbConfig, update_config_dto_js_1.UpdateConfigDto]),
163
+ __metadata("design:returntype", Promise)
164
+ ], ConfigurationController.prototype, "update", null);
165
+ exports.ConfigurationController = ConfigurationController = __decorate([
166
+ (0, http_1.BasePath)('configuration'),
167
+ (0, http_1.Policy)(rbac_http_1.AuthorizedPolicy),
168
+ (0, rbac_http_1.Resource)('configuration')
169
+ ], ConfigurationController);
170
+ //# sourceMappingURL=Configuration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Configuration.js","sourceRoot":"","sources":["../../../src/controllers/Configuration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Body payload for updating a configuration entry value.
3
+ *
4
+ * Only the operationally meaningful fields are editable. Structural fields
5
+ * ( `Slug`, `Group`, `Type` ) are owned by code that exposes the option and
6
+ * cannot be changed through this api.
7
+ */
8
+ export declare class UpdateConfigDto {
9
+ Value: any;
10
+ Default?: any;
11
+ Watch?: boolean;
12
+ constructor(data: Partial<UpdateConfigDto>);
13
+ }
14
+ //# sourceMappingURL=update-config-dto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-config-dto.d.ts","sourceRoot":"","sources":["../../../src/dto/update-config-dto.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,qBAYa,eAAe;IAEnB,KAAK,EAAE,GAAG,CAAC;IAGX,OAAO,CAAC,EAAE,GAAG,CAAC;IAEd,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEX,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC;CAG3C"}
@@ -0,0 +1,42 @@
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 __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.UpdateConfigDto = void 0;
13
+ const validation_1 = require("@spinajs/validation");
14
+ /**
15
+ * Body payload for updating a configuration entry value.
16
+ *
17
+ * Only the operationally meaningful fields are editable. Structural fields
18
+ * ( `Slug`, `Group`, `Type` ) are owned by code that exposes the option and
19
+ * cannot be changed through this api.
20
+ */
21
+ let UpdateConfigDto = class UpdateConfigDto {
22
+ constructor(data) {
23
+ Object.assign(this, data);
24
+ }
25
+ };
26
+ exports.UpdateConfigDto = UpdateConfigDto;
27
+ exports.UpdateConfigDto = UpdateConfigDto = __decorate([
28
+ (0, validation_1.Schema)({
29
+ type: 'object',
30
+ $id: 'configuration.http.updateConfigDTO',
31
+ properties: {
32
+ // value type varies with the entry `Type`, real validation happens against
33
+ // Type/Meta in the controller, so the schema only requires its presence
34
+ Value: {},
35
+ Default: {},
36
+ Watch: { type: 'boolean' },
37
+ },
38
+ required: ['Value'],
39
+ }),
40
+ __metadata("design:paramtypes", [Object])
41
+ ], UpdateConfigDto);
42
+ //# sourceMappingURL=update-config-dto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-config-dto.js","sourceRoot":"","sources":["../../../src/dto/update-config-dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAA6C;AAE7C;;;;;;GAMG;AAaI,IAAM,eAAe,GAArB,MAAM,eAAe;IAS1B,YAAY,IAA8B;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF,CAAA;AAZY,0CAAe;0BAAf,eAAe;IAZ3B,IAAA,mBAAM,EAAC;QACN,IAAI,EAAE,QAAQ;QACd,GAAG,EAAE,oCAAoC;QACzC,UAAU,EAAE;YACV,2EAA2E;YAC3E,wEAAwE;YACxE,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAC3B;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB,CAAC;;GACW,eAAe,CAY3B"}
@@ -0,0 +1,5 @@
1
+ export * from './controllers/Configuration.js';
2
+ export * from './dto/update-config-dto.js';
3
+ export * from './validation.js';
4
+ export * from './bootstrap.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./controllers/Configuration.js"), exports);
18
+ __exportStar(require("./dto/update-config-dto.js"), exports);
19
+ __exportStar(require("./validation.js"), exports);
20
+ __exportStar(require("./bootstrap.js"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iEAA+C;AAC/C,6DAA2C;AAC3C,kDAAgC;AAChC,iDAA+B"}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,29 @@
1
+ import { ConfigurationEntryType, IConfigurationEntryMeta } from '@spinajs/configuration-db-source';
2
+ /** A plain JSON Schema fragment. */
3
+ type JsonSchema = Record<string, unknown>;
4
+ /**
5
+ * Base JSON Schema per configuration `Type`. These shapes are constant - the
6
+ * per-entry `Meta` ( bounds / allowed values ) is folded on top at request time
7
+ * by {@link valueSchema}.
8
+ *
9
+ * Validation only - it asserts the incoming value is acceptable. Coercion into
10
+ * the typed / canonical stored form is the converter's job ( see
11
+ * DbConfigValueConverter ), so eg. a `date` is just a `format: date` string
12
+ * here, not a luxon DateTime.
13
+ */
14
+ export declare const VALUE_SCHEMAS: Record<ConfigurationEntryType, JsonSchema>;
15
+ /**
16
+ * Resolves the value schema for an entry: the constant base schema for its
17
+ * `Type` with the entry `Meta` constraints applied.
18
+ *
19
+ * The constraints target the schema "leaf" - the `items` schema for array types
20
+ * ( manyOf / *-range ), otherwise the schema itself - so allowed values and
21
+ * bounds land on the element being validated regardless of arity.
22
+ *
23
+ * Fed to `DataValidator` ( ajv ) in the controller, after the entry - and so its
24
+ * Type / Meta - has been loaded from the db. It can't live on the request DTO
25
+ * schema, which is validated before that lookup when the type is still unknown.
26
+ */
27
+ export declare function valueSchema(type: ConfigurationEntryType, meta?: IConfigurationEntryMeta): JsonSchema;
28
+ export {};
29
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEnG,oCAAoC;AACpC,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,sBAAsB,EAAE,UAAU,CAiBpE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,sBAAsB,EAAE,IAAI,CAAC,EAAE,uBAAuB,GAAG,UAAU,CA8BpG"}