@veap/settings 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/LICENSE +21 -0
- package/README.md +113 -2
- package/dist/composition.d.ts +15 -0
- package/dist/composition.js +5 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/settings.repository.d.ts +30 -0
- package/dist/contracts/settings.repository.js +8 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/migrations/0001_create_settings_table.d.ts +4 -0
- package/dist/migrations/0001_create_settings_table.js +12 -0
- package/dist/migrations/index.d.ts +4 -0
- package/dist/migrations/index.js +7 -0
- package/dist/models/Setting.d.ts +22 -0
- package/dist/models/Setting.js +32 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models.d.ts +1 -0
- package/dist/models.js +1 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/settings.provider.d.ts +14 -0
- package/dist/providers/settings.provider.js +52 -0
- package/dist/repositories/index.d.ts +1 -0
- package/dist/repositories/index.js +1 -0
- package/dist/repositories/setting.repository.d.ts +11 -0
- package/dist/repositories/setting.repository.js +29 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/settings.service.d.ts +44 -0
- package/dist/services/settings.service.js +93 -0
- package/package.json +52 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Damian Miller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,114 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://github.com/veapjs/veap-settings/actions/workflows/CI.yml)
|
|
2
|
+
[](https://github.com/veapjs/veap-settings/actions/workflows/RELEASE.yml)
|
|
3
|
+
[](https://www.npmjs.com/package/@veap/settings)
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
# @veap/settings
|
|
6
|
+
|
|
7
|
+
Key-value application settings management, caching, and persistence engine
|
|
8
|
+
for Veap applications.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
`@veap/settings` provides a dynamic configuration and settings system for
|
|
13
|
+
applications needing runtime-tunable options (site title, maintenance mode,
|
|
14
|
+
features flags, integrations). It bridges database persistence powered by
|
|
15
|
+
`@veap/database` with in-memory caching to minimize database query overhead.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **Typed key-value storage**: Store strings, numbers, booleans, and complex
|
|
20
|
+
JSON structures under unique keys.
|
|
21
|
+
- **In-memory cache layer**: Fast cached reads with automated cache
|
|
22
|
+
invalidation on update or delete operations.
|
|
23
|
+
- **Active Record persistence**: Backed by the `Setting` model with automatic
|
|
24
|
+
schema migrations.
|
|
25
|
+
- **Clean Architecture & IoC**: Follows repository pattern with
|
|
26
|
+
`SETTINGS_REPOSITORY` and integrates cleanly via `SettingsServiceProvider`.
|
|
27
|
+
- **Default values & fallback**: Specify fallback values when keys have not yet
|
|
28
|
+
been configured in the database.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Using bun
|
|
34
|
+
bun add @veap/settings @veap/kernel @veap/database
|
|
35
|
+
|
|
36
|
+
# Using pnpm
|
|
37
|
+
pnpm add @veap/settings @veap/kernel @veap/database
|
|
38
|
+
|
|
39
|
+
# Using npm
|
|
40
|
+
npm install @veap/settings @veap/kernel @veap/database
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Register in Application Builder
|
|
46
|
+
|
|
47
|
+
Include `SettingsServiceProvider` in your application composition root:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { Application } from "@veap/kernel";
|
|
51
|
+
import { DatabaseServiceProvider } from "@veap/database";
|
|
52
|
+
import { SettingsServiceProvider } from "@veap/settings";
|
|
53
|
+
|
|
54
|
+
export const app = Application.configure()
|
|
55
|
+
.use(DatabaseServiceProvider)
|
|
56
|
+
.use(
|
|
57
|
+
new SettingsServiceProvider(undefined, {
|
|
58
|
+
autoMigrate: true, // Automatically applies settings table migrations
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
.create();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Accessing Settings via IoC
|
|
65
|
+
|
|
66
|
+
Resolve `SettingsService` from the container in your services or server actions:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { app } from "@veap/kernel";
|
|
70
|
+
import { SettingsService } from "@veap/settings";
|
|
71
|
+
|
|
72
|
+
// Read a setting with a typed fallback
|
|
73
|
+
const settings = await app(SettingsService);
|
|
74
|
+
const siteName = await settings.get("site.name", "Default Site Name");
|
|
75
|
+
const maintenance = await settings.get<boolean>("system.maintenance", false);
|
|
76
|
+
|
|
77
|
+
// Save or update a setting
|
|
78
|
+
await settings.set("site.name", "My Enterprise Portal");
|
|
79
|
+
await settings.set("features.comments_enabled", true);
|
|
80
|
+
|
|
81
|
+
// Delete a setting
|
|
82
|
+
await settings.delete("obsolete_key");
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Direct Model Access
|
|
86
|
+
|
|
87
|
+
Interact directly with the Active Record model from `@veap/settings/models`:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { Setting } from "@veap/settings/models";
|
|
91
|
+
|
|
92
|
+
// Query all public settings
|
|
93
|
+
const allSettings = await Setting.query().orderBy("key", "asc").get();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Subpath Exports
|
|
97
|
+
|
|
98
|
+
| Export Path | Content |
|
|
99
|
+
| --------------------------- | ----------------------------------------------------------------------- |
|
|
100
|
+
| `@veap/settings` | `SettingsService`, `SettingsServiceProvider`, and repository interfaces |
|
|
101
|
+
| `@veap/settings/models` | Active Record `Setting` model |
|
|
102
|
+
| `@veap/settings/migrations` | Knex migrations for the settings schema |
|
|
103
|
+
|
|
104
|
+
## Documentation
|
|
105
|
+
|
|
106
|
+
For full guides and settings caching options, visit:
|
|
107
|
+
|
|
108
|
+
- **Official Website**: [https://veap.pl](https://veap.pl)
|
|
109
|
+
- **Documentation**: [https://veap.pl/docs](https://veap.pl/docs)
|
|
110
|
+
- **GitHub Repository**: [https://github.com/veapjs/veap-settings](https://github.com/veapjs/veap-settings)
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type SettingsConfig } from "./providers/settings.provider.js";
|
|
2
|
+
declare module "@veap/kernel" {
|
|
3
|
+
interface ApplicationBuilder {
|
|
4
|
+
/**
|
|
5
|
+
* Registers the SettingsServiceProvider into the application.
|
|
6
|
+
*/
|
|
7
|
+
withSettings(config?: SettingsConfig): this;
|
|
8
|
+
}
|
|
9
|
+
interface VeapConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Configuration options for @veap/settings.
|
|
12
|
+
*/
|
|
13
|
+
settings?: SettingsConfig;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type ISettingsRepository, type ISettingsService, SETTINGS_REPOSITORY, SETTINGS_SERVICE, } from "./settings.repository.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SETTINGS_REPOSITORY, SETTINGS_SERVICE, } from "./settings.repository.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Token } from "@veap/kernel";
|
|
2
|
+
/**
|
|
3
|
+
* Settings persistence port.
|
|
4
|
+
*/
|
|
5
|
+
export interface ISettingsRepository {
|
|
6
|
+
get<T>(key: string): Promise<T | null>;
|
|
7
|
+
set(key: string, value: unknown): Promise<void>;
|
|
8
|
+
delete(key: string): Promise<void>;
|
|
9
|
+
clear(): Promise<void>;
|
|
10
|
+
all?(): Promise<Record<string, unknown>>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Injection token for the settings repository port.
|
|
14
|
+
*/
|
|
15
|
+
export declare const SETTINGS_REPOSITORY: Token<ISettingsRepository>;
|
|
16
|
+
/**
|
|
17
|
+
* Forward type reference for SettingsService in IoC tokens.
|
|
18
|
+
*/
|
|
19
|
+
export interface ISettingsService {
|
|
20
|
+
get<T>(key: string, defaultValue?: T | null): Promise<T | null>;
|
|
21
|
+
set(key: string, value: unknown): Promise<void>;
|
|
22
|
+
remove(key: string): Promise<void>;
|
|
23
|
+
clear(): Promise<void>;
|
|
24
|
+
has(key: string): Promise<boolean>;
|
|
25
|
+
all(): Promise<Record<string, unknown>>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Injection token for the settings application service.
|
|
29
|
+
*/
|
|
30
|
+
export declare const SETTINGS_SERVICE: Token<ISettingsService>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injection token for the settings repository port.
|
|
3
|
+
*/
|
|
4
|
+
export const SETTINGS_REPOSITORY = Symbol.for("veap:settings:repository");
|
|
5
|
+
/**
|
|
6
|
+
* Injection token for the settings application service.
|
|
7
|
+
*/
|
|
8
|
+
export const SETTINGS_SERVICE = Symbol.for("veap:settings:service");
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./composition.js";
|
|
2
|
+
export * from "./contracts/index.js";
|
|
3
|
+
export * from "./migrations/index.js";
|
|
4
|
+
export * from "./models/index.js";
|
|
5
|
+
export * from "./providers/index.js";
|
|
6
|
+
export * from "./repositories/index.js";
|
|
7
|
+
export * from "./services/index.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./composition.js";
|
|
2
|
+
export * from "./contracts/index.js";
|
|
3
|
+
export * from "./migrations/index.js";
|
|
4
|
+
export * from "./models/index.js";
|
|
5
|
+
export * from "./providers/index.js";
|
|
6
|
+
export * from "./repositories/index.js";
|
|
7
|
+
export * from "./services/index.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const name = "0001_create_settings_table";
|
|
2
|
+
export async function up(_db, schema) {
|
|
3
|
+
await schema.createTable("settings", (table) => {
|
|
4
|
+
table.text("id").primaryKey();
|
|
5
|
+
table.text("key").notNull().unique();
|
|
6
|
+
table.json("value").notNull();
|
|
7
|
+
table.timestamp("updated_at").defaultNow();
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export async function down(_db, schema) {
|
|
11
|
+
await schema.dropTableIfExists("settings");
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { runMigrations } from "@veap/database";
|
|
2
|
+
import * as m0001 from "./0001_create_settings_table.js";
|
|
3
|
+
export const settingsMigrations = [m0001];
|
|
4
|
+
export async function runSettingsMigrations() {
|
|
5
|
+
await runMigrations("settings", settingsMigrations);
|
|
6
|
+
}
|
|
7
|
+
export default settingsMigrations;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CastType, Model } from "@veap/database";
|
|
2
|
+
export interface SettingAttributes {
|
|
3
|
+
id?: string;
|
|
4
|
+
key: string;
|
|
5
|
+
value: any;
|
|
6
|
+
updatedAt?: Date | null;
|
|
7
|
+
updated_at?: Date | null;
|
|
8
|
+
}
|
|
9
|
+
export declare class Setting extends Model<SettingAttributes> {
|
|
10
|
+
static table: string;
|
|
11
|
+
static autoUuid: boolean;
|
|
12
|
+
static timestamps: boolean | string[];
|
|
13
|
+
static casts: Record<string, CastType>;
|
|
14
|
+
/**
|
|
15
|
+
* Helper to quickly get a setting by key.
|
|
16
|
+
*/
|
|
17
|
+
static getValue<T = any>(key: string, defaultValue?: T | null): Promise<T | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Helper to quickly set/update a setting by key.
|
|
20
|
+
*/
|
|
21
|
+
static setValue(key: string, value: any): Promise<Setting>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Model } from "@veap/database";
|
|
2
|
+
export class Setting extends Model {
|
|
3
|
+
static table = "settings";
|
|
4
|
+
static autoUuid = true;
|
|
5
|
+
static timestamps = ["updated_at"];
|
|
6
|
+
static casts = {
|
|
7
|
+
value: "json",
|
|
8
|
+
updatedAt: "datetime",
|
|
9
|
+
updated_at: "datetime",
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Helper to quickly get a setting by key.
|
|
13
|
+
*/
|
|
14
|
+
static async getValue(key, defaultValue = null) {
|
|
15
|
+
const setting = await this.where("key", key).first();
|
|
16
|
+
return setting ? setting.getAttribute("value") : defaultValue;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Helper to quickly set/update a setting by key.
|
|
20
|
+
*/
|
|
21
|
+
static async setValue(key, value) {
|
|
22
|
+
let setting = await this.where("key", key).first();
|
|
23
|
+
if (setting) {
|
|
24
|
+
setting.setAttribute("value", value);
|
|
25
|
+
await setting.save();
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
setting = await this.create({ key, value });
|
|
29
|
+
}
|
|
30
|
+
return setting;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Setting, type SettingAttributes, } from "./Setting.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Setting, } from "./Setting.js";
|
package/dist/models.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./models/index.js";
|
package/dist/models.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./models/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type SettingsConfig, SettingsServiceProvider, } from "./settings.provider.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SettingsServiceProvider, } from "./settings.provider.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Container, ServiceProvider } from "@veap/kernel";
|
|
2
|
+
export interface SettingsConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Whether to automatically run settings database migrations during SettingsServiceProvider.boot().
|
|
5
|
+
* Defaults to `true` when database connection is initialized.
|
|
6
|
+
*/
|
|
7
|
+
autoMigrate?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class SettingsServiceProvider extends ServiceProvider {
|
|
10
|
+
private config?;
|
|
11
|
+
constructor(container: Container, config?: SettingsConfig);
|
|
12
|
+
register(): void;
|
|
13
|
+
boot(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { isDatabaseInitialized } from "@veap/database";
|
|
2
|
+
import { ConfigService, logger, ServiceProvider, } from "@veap/kernel";
|
|
3
|
+
import { SETTINGS_REPOSITORY, SETTINGS_SERVICE, } from "../contracts/settings.repository.js";
|
|
4
|
+
import { runSettingsMigrations } from "../migrations/index.js";
|
|
5
|
+
import { ActiveRecordSettingsRepository } from "../repositories/setting.repository.js";
|
|
6
|
+
import { SettingsService } from "../services/settings.service.js";
|
|
7
|
+
export class SettingsServiceProvider extends ServiceProvider {
|
|
8
|
+
config;
|
|
9
|
+
constructor(container, config) {
|
|
10
|
+
super(container);
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
register() {
|
|
14
|
+
this.container.register({
|
|
15
|
+
token: SETTINGS_REPOSITORY,
|
|
16
|
+
useClass: ActiveRecordSettingsRepository,
|
|
17
|
+
singleton: true,
|
|
18
|
+
});
|
|
19
|
+
this.container.register({
|
|
20
|
+
token: SettingsService,
|
|
21
|
+
useClass: SettingsService,
|
|
22
|
+
singleton: true,
|
|
23
|
+
});
|
|
24
|
+
this.container.register({
|
|
25
|
+
token: SETTINGS_SERVICE,
|
|
26
|
+
useFactory: (service) => service,
|
|
27
|
+
inject: [SettingsService],
|
|
28
|
+
singleton: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async boot() {
|
|
32
|
+
const configService = this.container.has(ConfigService)
|
|
33
|
+
? await this.container.resolve(ConfigService)
|
|
34
|
+
: undefined;
|
|
35
|
+
const envAutoMigrate = configService?.get("SETTINGS_AUTO_MIGRATE") ??
|
|
36
|
+
(typeof process !== "undefined"
|
|
37
|
+
? process.env.SETTINGS_AUTO_MIGRATE
|
|
38
|
+
: undefined);
|
|
39
|
+
const shouldAutoMigrate = this.config?.autoMigrate ??
|
|
40
|
+
(envAutoMigrate !== undefined
|
|
41
|
+
? envAutoMigrate === "true" || envAutoMigrate === "1"
|
|
42
|
+
: true);
|
|
43
|
+
if (shouldAutoMigrate !== false && isDatabaseInitialized()) {
|
|
44
|
+
try {
|
|
45
|
+
await runSettingsMigrations();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
logger.warn("veap:settings", "Automatic settings migration failed or deferred:", error?.message || error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ActiveRecordSettingsRepository } from "./setting.repository.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ActiveRecordSettingsRepository } from "./setting.repository.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ISettingsRepository } from "../contracts/settings.repository.js";
|
|
2
|
+
/**
|
|
3
|
+
* `ISettingsRepository` adapter backed by the `Setting` ActiveRecord model.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ActiveRecordSettingsRepository implements ISettingsRepository {
|
|
6
|
+
get<T>(key: string): Promise<T | null>;
|
|
7
|
+
set(key: string, value: unknown): Promise<void>;
|
|
8
|
+
delete(key: string): Promise<void>;
|
|
9
|
+
clear(): Promise<void>;
|
|
10
|
+
all(): Promise<Record<string, unknown>>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Setting } from "../models/Setting.js";
|
|
2
|
+
/**
|
|
3
|
+
* `ISettingsRepository` adapter backed by the `Setting` ActiveRecord model.
|
|
4
|
+
*/
|
|
5
|
+
export class ActiveRecordSettingsRepository {
|
|
6
|
+
async get(key) {
|
|
7
|
+
return Setting.getValue(key, null);
|
|
8
|
+
}
|
|
9
|
+
async set(key, value) {
|
|
10
|
+
await Setting.setValue(key, value);
|
|
11
|
+
}
|
|
12
|
+
async delete(key) {
|
|
13
|
+
await Setting.where("key", key).delete();
|
|
14
|
+
}
|
|
15
|
+
async clear() {
|
|
16
|
+
await Setting.query().delete();
|
|
17
|
+
}
|
|
18
|
+
async all() {
|
|
19
|
+
const settings = await Setting.all();
|
|
20
|
+
const result = {};
|
|
21
|
+
for (const s of settings) {
|
|
22
|
+
const k = s.getAttribute("key");
|
|
23
|
+
if (k) {
|
|
24
|
+
result[k] = s.getAttribute("value");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./index.js";
|
package/dist/server.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SettingsService } from "./settings.service.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SettingsService } from "./settings.service.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type ICacheProvider } from "@veap/kernel";
|
|
2
|
+
import { type ISettingsRepository, type ISettingsService } from "../contracts/settings.repository.js";
|
|
3
|
+
/**
|
|
4
|
+
* Application service for reading and writing settings.
|
|
5
|
+
*
|
|
6
|
+
* It depends exclusively on ports (ICacheProvider, ISettingsRepository)
|
|
7
|
+
* that are injected through the constructor.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SettingsService implements ISettingsService {
|
|
10
|
+
private cache;
|
|
11
|
+
private repository;
|
|
12
|
+
constructor(cache: ICacheProvider, repository: ISettingsRepository);
|
|
13
|
+
/**
|
|
14
|
+
* Get a setting value by key.
|
|
15
|
+
* @param key Setting key (e.g., "system:page")
|
|
16
|
+
* @param defaultValue Optional fallback value if the key does not exist
|
|
17
|
+
* @returns Value as T or defaultValue / null
|
|
18
|
+
*/
|
|
19
|
+
get<T>(key: string, defaultValue?: T | null): Promise<T | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a setting exists.
|
|
22
|
+
* @param key Setting key
|
|
23
|
+
*/
|
|
24
|
+
has(key: string): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Set a setting value.
|
|
27
|
+
* @param key Setting key
|
|
28
|
+
* @param value JSON value
|
|
29
|
+
*/
|
|
30
|
+
set(key: string, value: unknown): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Remove a setting by key.
|
|
33
|
+
* @param key Setting key
|
|
34
|
+
*/
|
|
35
|
+
remove(key: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Clear all settings.
|
|
38
|
+
*/
|
|
39
|
+
clear(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Retrieve all settings as a key-value map.
|
|
42
|
+
*/
|
|
43
|
+
all(): Promise<Record<string, unknown>>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { CACHE_PROVIDER, Inject, Injectable, } from "@veap/kernel";
|
|
14
|
+
import { SETTINGS_REPOSITORY, } from "../contracts/settings.repository.js";
|
|
15
|
+
/**
|
|
16
|
+
* Application service for reading and writing settings.
|
|
17
|
+
*
|
|
18
|
+
* It depends exclusively on ports (ICacheProvider, ISettingsRepository)
|
|
19
|
+
* that are injected through the constructor.
|
|
20
|
+
*/
|
|
21
|
+
let SettingsService = class SettingsService {
|
|
22
|
+
cache;
|
|
23
|
+
repository;
|
|
24
|
+
constructor(cache, repository) {
|
|
25
|
+
this.cache = cache;
|
|
26
|
+
this.repository = repository;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get a setting value by key.
|
|
30
|
+
* @param key Setting key (e.g., "system:page")
|
|
31
|
+
* @param defaultValue Optional fallback value if the key does not exist
|
|
32
|
+
* @returns Value as T or defaultValue / null
|
|
33
|
+
*/
|
|
34
|
+
async get(key, defaultValue = null) {
|
|
35
|
+
const cacheKey = `settings:${key}`;
|
|
36
|
+
const cached = await this.cache.get(cacheKey);
|
|
37
|
+
if (cached !== null)
|
|
38
|
+
return cached;
|
|
39
|
+
const value = await this.repository.get(key);
|
|
40
|
+
if (value !== null) {
|
|
41
|
+
await this.cache.set(cacheKey, value);
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
return defaultValue;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if a setting exists.
|
|
48
|
+
* @param key Setting key
|
|
49
|
+
*/
|
|
50
|
+
async has(key) {
|
|
51
|
+
return (await this.get(key)) !== null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set a setting value.
|
|
55
|
+
* @param key Setting key
|
|
56
|
+
* @param value JSON value
|
|
57
|
+
*/
|
|
58
|
+
async set(key, value) {
|
|
59
|
+
await this.repository.set(key, value);
|
|
60
|
+
await this.cache.set(`settings:${key}`, value);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Remove a setting by key.
|
|
64
|
+
* @param key Setting key
|
|
65
|
+
*/
|
|
66
|
+
async remove(key) {
|
|
67
|
+
await this.repository.delete(key);
|
|
68
|
+
await this.cache.delete(`settings:${key}`);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Clear all settings.
|
|
72
|
+
*/
|
|
73
|
+
async clear() {
|
|
74
|
+
await this.repository.clear();
|
|
75
|
+
await this.cache.clear();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Retrieve all settings as a key-value map.
|
|
79
|
+
*/
|
|
80
|
+
async all() {
|
|
81
|
+
if (this.repository.all) {
|
|
82
|
+
return this.repository.all();
|
|
83
|
+
}
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
SettingsService = __decorate([
|
|
88
|
+
Injectable(),
|
|
89
|
+
__param(0, Inject(CACHE_PROVIDER)),
|
|
90
|
+
__param(1, Inject(SETTINGS_REPOSITORY)),
|
|
91
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
92
|
+
], SettingsService);
|
|
93
|
+
export { SettingsService };
|
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veap/settings",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Application settings management, caching, and persistence for Veap",
|
|
5
|
+
"bugs": "https://github.com/veapjs/veap-settings/issues",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/veapjs/veap-settings.git"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./models": {
|
|
20
|
+
"types": "./dist/models.d.ts",
|
|
21
|
+
"default": "./dist/models.js"
|
|
22
|
+
},
|
|
23
|
+
"./server": {
|
|
24
|
+
"types": "./dist/server.d.ts",
|
|
25
|
+
"default": "./dist/server.js"
|
|
26
|
+
},
|
|
27
|
+
"./migrations": {
|
|
28
|
+
"types": "./dist/migrations/index.d.ts",
|
|
29
|
+
"default": "./dist/migrations/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"clean": "rimraf dist",
|
|
38
|
+
"build": "rimraf dist && tsc",
|
|
39
|
+
"dev": "tsc --watch",
|
|
40
|
+
"test": "vitest run"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@veap/database": "0.1.1",
|
|
44
|
+
"@veap/kernel": "0.1.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.20.2",
|
|
48
|
+
"better-sqlite3": "^13.0.3",
|
|
49
|
+
"knex": "^3.1.0",
|
|
50
|
+
"rimraf": "^6.1.3",
|
|
51
|
+
"typescript": "6.0.3",
|
|
52
|
+
"vitest": "^5.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|