statcon 0.1.0

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 (37) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +36 -0
  5. package/dist/serializeCasing.d.ts +10 -0
  6. package/dist/serializeCasing.js +17 -0
  7. package/dist/structures/Alerting.d.ts +26 -0
  8. package/dist/structures/Alerting.js +47 -0
  9. package/dist/structures/Announcement.d.ts +15 -0
  10. package/dist/structures/Announcement.js +23 -0
  11. package/dist/structures/Base.d.ts +6 -0
  12. package/dist/structures/Base.js +5 -0
  13. package/dist/structures/Client.d.ts +57 -0
  14. package/dist/structures/Client.js +126 -0
  15. package/dist/structures/Configuration.d.ts +54 -0
  16. package/dist/structures/Configuration.js +215 -0
  17. package/dist/structures/Endpoint.d.ts +84 -0
  18. package/dist/structures/Endpoint.js +163 -0
  19. package/dist/structures/ExternalEndpoint.d.ts +22 -0
  20. package/dist/structures/ExternalEndpoint.js +44 -0
  21. package/dist/structures/Maintenance.d.ts +18 -0
  22. package/dist/structures/Maintenance.js +31 -0
  23. package/dist/structures/Security.d.ts +44 -0
  24. package/dist/structures/Security.js +91 -0
  25. package/dist/structures/Storage.d.ts +18 -0
  26. package/dist/structures/Storage.js +31 -0
  27. package/dist/structures/Tunnel.d.ts +20 -0
  28. package/dist/structures/Tunnel.js +35 -0
  29. package/dist/structures/UI.d.ts +34 -0
  30. package/dist/structures/UI.js +55 -0
  31. package/dist/structures/Web.d.ts +18 -0
  32. package/dist/structures/Web.js +31 -0
  33. package/dist/structures/index.d.ts +13 -0
  34. package/dist/structures/index.js +13 -0
  35. package/dist/types.d.ts +24 -0
  36. package/dist/types.js +1 -0
  37. package/package.json +34 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Logan Devine
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 ADDED
@@ -0,0 +1,45 @@
1
+ # statcon
2
+
3
+ The Status Configurator - a declarative configuration generator for Gatus config.yaml
4
+
5
+ ## Usage
6
+
7
+ Statcon is packaged as a module on npm, and can be used in your own projects to generate Gatus configuration files.
8
+
9
+ Configure a JS or TS project, install statcon, and then create a file like `statcon.conf.ts` with your desired configuration.
10
+
11
+ See the [`statcon.conf.ts`](https://github.com/thetayloredman/statcon/blob/main/statcon.conf.ts) file for an example of Statcon's declarative, functional configuration style.
12
+
13
+ ## Output
14
+
15
+ The `sc.generate()` function will return a JS object which you can then JSON.stringify and write to a file.
16
+
17
+ Valid JSON is valid YAML, so you can write the output to the `config.yaml` file and it will be usable by Gatus.
18
+
19
+ ## Code Splitting
20
+
21
+ If your configuration gets quite long and you want to split it into multiple files, you can export them as plugins and import them into your main configuration file, then `.use`ing them in the main configuration.
22
+
23
+ For example, you could have a `plugins/` directory with files like `plugins/database.ts` and `plugins/api.ts`, each exporting a function that takes a Statcon instance and returns a plugin object.
24
+
25
+ Then in your main `statcon.conf.ts`, you can import those plugins and use them:
26
+
27
+ ```ts
28
+ import { Statcon } from "statcon";
29
+ import databasePlugin from "./plugins/database";
30
+ import apiPlugin from "./plugins/api";
31
+
32
+ const config = sc.generate((config) =>
33
+ config.use(databasePlugin).use(apiPlugin)
34
+ );
35
+ ```
36
+
37
+ This allows you to keep your configuration organized and modular, especially as it grows in size and complexity.
38
+
39
+ ## Contributing
40
+
41
+ Contributions to Statcon are welcome! If you have an idea for a new feature, or want to help improve the codebase, please open an issue or submit a pull request.
42
+
43
+ ## License
44
+
45
+ Statcon is licensed under the MIT License. See the [LICENSE](./LICENSE) file for more information.
@@ -0,0 +1,3 @@
1
+ import * as structures from "./structures/index.js";
2
+ export * from "./structures/index.js";
3
+ export declare function generate(cb: (config: structures.Configuration) => structures.Configuration): Record<string, unknown>;
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ import * as structures from "./structures/index.js";
2
+ export * from "./structures/index.js";
3
+ /**
4
+ * Converts a camelCase string to kebab-case
5
+ */
6
+ function toKebabCase(str) {
7
+ return str.replace(/[A-Z]/g, (letter, offset) => {
8
+ return offset === 0 ? letter.toLowerCase() : `-${letter.toLowerCase()}`;
9
+ });
10
+ }
11
+ /**
12
+ * Recursively converts all object property names from camelCase to kebab-case
13
+ */
14
+ function convertKeysToKebabCase(obj) {
15
+ if (obj === null || obj === undefined) {
16
+ return obj;
17
+ }
18
+ if (Array.isArray(obj)) {
19
+ return obj.map((item) => convertKeysToKebabCase(item));
20
+ }
21
+ if (typeof obj === "object" && obj.constructor === Object) {
22
+ const newObj = {};
23
+ for (const key in obj) {
24
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
25
+ const kebabKey = toKebabCase(key);
26
+ newObj[kebabKey] = convertKeysToKebabCase(obj[key]);
27
+ }
28
+ }
29
+ return newObj;
30
+ }
31
+ return obj;
32
+ }
33
+ export function generate(cb) {
34
+ const serialized = cb(new structures.Configuration({})).serialize();
35
+ return convertKeysToKebabCase(serialized);
36
+ }
@@ -0,0 +1,10 @@
1
+ type camelToKebabCase<S extends string> = S extends `${infer First}${infer Rest}` ? `${Lowercase<First>}${camelToKebabCaseHelper<Rest>}` : S;
2
+ declare function camelToKebabCase<S extends string>(str: S): S;
3
+ type camelToKebabCaseHelper<S extends string> = S extends `${infer First}${infer Rest}` ? First extends Uppercase<First> ? `-${Lowercase<First>}${camelToKebabCaseHelper<Rest>}` : `${First}${camelToKebabCaseHelper<Rest>}` : S;
4
+ export type serializeCasing<T> = {
5
+ [K in keyof T as camelToKebabCase<string & K>]: T[K] extends object ? serializeCasing<T[K]> : T[K];
6
+ } & unknown;
7
+ export declare function serializeCasing<T extends {
8
+ [key: string]: any;
9
+ }>(obj: T): serializeCasing<T>;
10
+ export {};
@@ -0,0 +1,17 @@
1
+ function camelToKebabCase(str) {
2
+ return str.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
3
+ }
4
+ export function serializeCasing(obj) {
5
+ const result = {};
6
+ for (const key in obj) {
7
+ if (obj.hasOwnProperty(key)) {
8
+ const kebabKey = camelToKebabCase(key);
9
+ const value = obj[key];
10
+ result[kebabKey] =
11
+ typeof value === "object" && value !== null
12
+ ? serializeCasing(value)
13
+ : value;
14
+ }
15
+ }
16
+ return result;
17
+ }
@@ -0,0 +1,26 @@
1
+ import { Base, Serialize } from "./Base.js";
2
+ export type AlertingConfiguration = {
3
+ type?: string;
4
+ enabled?: boolean;
5
+ failureThreshold?: number;
6
+ successThreshold?: number;
7
+ minimumReminderInterval?: number;
8
+ sendOnResolved?: boolean;
9
+ description?: string;
10
+ [additional: string]: any;
11
+ providerOverride?: Partial<AlertingConfiguration>;
12
+ };
13
+ export declare class Alerting extends Base implements Serialize {
14
+ data: AlertingConfiguration;
15
+ constructor(data: AlertingConfiguration);
16
+ type(type: string): this;
17
+ enabled(enabled: boolean): this;
18
+ failureThreshold(threshold: number): this;
19
+ successThreshold(threshold: number): this;
20
+ minimumReminderInterval(interval: number): this;
21
+ sendOnResolved(send: boolean): this;
22
+ description(description: string): this;
23
+ set(key: string, value: any): this;
24
+ providerOverride(override: Partial<AlertingConfiguration>): this;
25
+ serialize(): Record<string, any>;
26
+ }
@@ -0,0 +1,47 @@
1
+ import { Base } from "./Base.js";
2
+ export class Alerting extends Base {
3
+ data;
4
+ constructor(data) {
5
+ super();
6
+ this.data = data;
7
+ }
8
+ type(type) {
9
+ this.data.type = type;
10
+ return this;
11
+ }
12
+ enabled(enabled) {
13
+ this.data.enabled = enabled;
14
+ return this;
15
+ }
16
+ failureThreshold(threshold) {
17
+ this.data.failureThreshold = threshold;
18
+ return this;
19
+ }
20
+ successThreshold(threshold) {
21
+ this.data.successThreshold = threshold;
22
+ return this;
23
+ }
24
+ minimumReminderInterval(interval) {
25
+ this.data.minimumReminderInterval = interval;
26
+ return this;
27
+ }
28
+ sendOnResolved(send) {
29
+ this.data.sendOnResolved = send;
30
+ return this;
31
+ }
32
+ description(description) {
33
+ this.data.description = description;
34
+ return this;
35
+ }
36
+ set(key, value) {
37
+ this.data[key] = value;
38
+ return this;
39
+ }
40
+ providerOverride(override) {
41
+ this.data.providerOverride = override;
42
+ return this;
43
+ }
44
+ serialize() {
45
+ return this.data;
46
+ }
47
+ }
@@ -0,0 +1,15 @@
1
+ import { Base, Serialize } from "./Base.js";
2
+ export type AnnouncementConfiguration = {
3
+ timestamp?: number;
4
+ type?: "outage" | "warning" | "information" | "operational" | "none";
5
+ message?: string;
6
+ archived?: boolean;
7
+ };
8
+ export declare class Announcement extends Base implements Serialize {
9
+ data: AnnouncementConfiguration;
10
+ constructor(data: AnnouncementConfiguration);
11
+ message(message: string): this;
12
+ type(type: AnnouncementConfiguration["type"]): this;
13
+ archived(archived: boolean): this;
14
+ serialize(): Record<string, any>;
15
+ }
@@ -0,0 +1,23 @@
1
+ import { Base } from "./Base.js";
2
+ export class Announcement extends Base {
3
+ data;
4
+ constructor(data) {
5
+ super();
6
+ this.data = data;
7
+ }
8
+ message(message) {
9
+ this.data.message = message;
10
+ return this;
11
+ }
12
+ type(type) {
13
+ this.data.type = type;
14
+ return this;
15
+ }
16
+ archived(archived) {
17
+ this.data.archived = archived;
18
+ return this;
19
+ }
20
+ serialize() {
21
+ return this.data;
22
+ }
23
+ }
@@ -0,0 +1,6 @@
1
+ export declare class Base {
2
+ use(cb: (thing: this) => this): this;
3
+ }
4
+ export interface Serialize {
5
+ serialize(): Record<string, any>;
6
+ }
@@ -0,0 +1,5 @@
1
+ export class Base {
2
+ use(cb) {
3
+ return cb(this);
4
+ }
5
+ }
@@ -0,0 +1,57 @@
1
+ import { Base, Serialize } from "./Base.js";
2
+ export type ClientConfiguration = {
3
+ insecure?: boolean;
4
+ ignoreRedirect?: boolean;
5
+ timeout?: string;
6
+ dnsResolver?: string;
7
+ oauth2?: {
8
+ tokenUrl?: string;
9
+ clientId?: string;
10
+ clientSecret?: string;
11
+ scopes?: string[];
12
+ };
13
+ proxyUrl?: string;
14
+ identityAwareProxy?: {
15
+ audience: string;
16
+ };
17
+ tls?: {
18
+ certificateFile?: string;
19
+ privateKeyFile?: string;
20
+ renegotiation?: "never" | "once" | "freely";
21
+ };
22
+ network?: "ip" | "ip4" | "ip6";
23
+ tunnel?: string;
24
+ };
25
+ export declare class OAuth2 extends Base implements Serialize {
26
+ data: NonNullable<ClientConfiguration["oauth2"]>;
27
+ constructor(data: NonNullable<ClientConfiguration["oauth2"]>);
28
+ tokenUrl(url: string): this;
29
+ clientId(id: string): this;
30
+ clientSecret(secret: string): this;
31
+ scopes(scopes: string[]): this;
32
+ serialize(): Record<string, any>;
33
+ }
34
+ export declare class Tls extends Base implements Serialize {
35
+ data: NonNullable<ClientConfiguration["tls"]>;
36
+ constructor(data: NonNullable<ClientConfiguration["tls"]>);
37
+ certificateFile(path: string): this;
38
+ privateKeyFile(path: string): this;
39
+ renegotiation(mode: NonNullable<ClientConfiguration["tls"]>["renegotiation"]): this;
40
+ serialize(): Record<string, any>;
41
+ }
42
+ export declare class Client extends Base implements Serialize {
43
+ data: ClientConfiguration;
44
+ constructor(data: ClientConfiguration);
45
+ insecure(insecure: boolean): this;
46
+ ignoreRedirect(ignore: boolean): this;
47
+ timeout(timeout: string): this;
48
+ dnsResolver(resolver: string): this;
49
+ proxyUrl(url: string): this;
50
+ identityAwareProxy(audience: string): this;
51
+ network(network: ClientConfiguration["network"]): this;
52
+ tunnel(tunnel: string): this;
53
+ oauth2(base: NonNullable<ClientConfiguration["oauth2"]>, cb: (oauth2: OAuth2) => OAuth2): this;
54
+ oauth2(cb: (oauth2: OAuth2) => OAuth2): this;
55
+ tls(baseOrCb: NonNullable<ClientConfiguration["tls"]> | ((tls: Tls) => Tls), cb?: (tls: Tls) => Tls): this;
56
+ serialize(): Record<string, any>;
57
+ }
@@ -0,0 +1,126 @@
1
+ import { Base } from "./Base.js";
2
+ export class OAuth2 extends Base {
3
+ data;
4
+ constructor(data) {
5
+ super();
6
+ this.data = data;
7
+ }
8
+ tokenUrl(url) {
9
+ this.data.tokenUrl = url;
10
+ return this;
11
+ }
12
+ clientId(id) {
13
+ this.data.clientId = id;
14
+ return this;
15
+ }
16
+ clientSecret(secret) {
17
+ this.data.clientSecret = secret;
18
+ return this;
19
+ }
20
+ scopes(scopes) {
21
+ this.data.scopes = scopes;
22
+ return this;
23
+ }
24
+ serialize() {
25
+ return this.data;
26
+ }
27
+ }
28
+ export class Tls extends Base {
29
+ data;
30
+ constructor(data) {
31
+ super();
32
+ this.data = data;
33
+ }
34
+ certificateFile(path) {
35
+ this.data.certificateFile = path;
36
+ return this;
37
+ }
38
+ privateKeyFile(path) {
39
+ this.data.privateKeyFile = path;
40
+ return this;
41
+ }
42
+ renegotiation(mode) {
43
+ this.data.renegotiation = mode;
44
+ return this;
45
+ }
46
+ serialize() {
47
+ return this.data;
48
+ }
49
+ }
50
+ export class Client extends Base {
51
+ data;
52
+ constructor(data) {
53
+ super();
54
+ this.data = data;
55
+ }
56
+ insecure(insecure) {
57
+ this.data.insecure = insecure;
58
+ return this;
59
+ }
60
+ ignoreRedirect(ignore) {
61
+ this.data.ignoreRedirect = ignore;
62
+ return this;
63
+ }
64
+ timeout(timeout) {
65
+ this.data.timeout = timeout;
66
+ return this;
67
+ }
68
+ dnsResolver(resolver) {
69
+ this.data.dnsResolver = resolver;
70
+ return this;
71
+ }
72
+ proxyUrl(url) {
73
+ this.data.proxyUrl = url;
74
+ return this;
75
+ }
76
+ identityAwareProxy(audience) {
77
+ if (!this.data.identityAwareProxy) {
78
+ this.data.identityAwareProxy = { audience };
79
+ }
80
+ else {
81
+ this.data.identityAwareProxy.audience = audience;
82
+ }
83
+ return this;
84
+ }
85
+ network(network) {
86
+ this.data.network = network;
87
+ return this;
88
+ }
89
+ tunnel(tunnel) {
90
+ this.data.tunnel = tunnel;
91
+ return this;
92
+ }
93
+ oauth2(baseOrCb, cb) {
94
+ let oauth2Instance;
95
+ if (typeof baseOrCb === "function") {
96
+ oauth2Instance = new OAuth2({});
97
+ oauth2Instance = baseOrCb(oauth2Instance);
98
+ }
99
+ else {
100
+ oauth2Instance = new OAuth2(baseOrCb);
101
+ if (cb) {
102
+ oauth2Instance = cb(oauth2Instance);
103
+ }
104
+ }
105
+ this.data.oauth2 = oauth2Instance.data;
106
+ return this;
107
+ }
108
+ tls(baseOrCb, cb) {
109
+ let tlsInstance;
110
+ if (typeof baseOrCb === "function") {
111
+ tlsInstance = new Tls({});
112
+ tlsInstance = baseOrCb(tlsInstance);
113
+ }
114
+ else {
115
+ tlsInstance = new Tls(baseOrCb);
116
+ if (cb) {
117
+ tlsInstance = cb(tlsInstance);
118
+ }
119
+ }
120
+ this.data.tls = tlsInstance.data;
121
+ return this;
122
+ }
123
+ serialize() {
124
+ return this.data;
125
+ }
126
+ }
@@ -0,0 +1,54 @@
1
+ import { Alerting, AlertingConfiguration } from "./Alerting.js";
2
+ import { Announcement, AnnouncementConfiguration } from "./Announcement.js";
3
+ import { Base, Serialize } from "./Base.js";
4
+ import { Endpoint, EndpointConfiguration } from "./Endpoint.js";
5
+ import { ExternalEndpoint, ExternalEndpointConfiguration } from "./ExternalEndpoint.js";
6
+ import { Maintenance, MaintenanceConfiguration } from "./Maintenance.js";
7
+ import { Security, SecurityConfiguration } from "./Security.js";
8
+ import { Storage, StorageConfiguration } from "./Storage.js";
9
+ import { Tunnel, TunnelingConfiguration } from "./Tunnel.js";
10
+ import { UI, UIConfiguration } from "./UI.js";
11
+ import { Web, WebConfiguration } from "./Web.js";
12
+ export type ConfigurationConfiguration = {
13
+ metrics?: boolean;
14
+ storage?: Storage;
15
+ alerting?: Alerting[];
16
+ announcements?: Announcement[];
17
+ endpoints?: Endpoint[];
18
+ externalEndpoints?: ExternalEndpoint[];
19
+ security?: Security;
20
+ concurrency?: number;
21
+ skipInvalidConfigUpdate?: boolean;
22
+ web?: Web;
23
+ ui?: UI;
24
+ maintenance?: Maintenance[];
25
+ tunneling?: Record<string, Tunnel>;
26
+ };
27
+ export declare class Configuration extends Base implements Serialize {
28
+ data: ConfigurationConfiguration;
29
+ constructor(data: ConfigurationConfiguration);
30
+ metrics(enabled: boolean): this;
31
+ concurrency(concurrency: number): this;
32
+ skipInvalidConfigUpdate(skip: boolean): this;
33
+ storage(base: StorageConfiguration, storage?: (storage: Storage) => Storage): this;
34
+ storage(storage: (storage: Storage) => Storage): this;
35
+ web(base: WebConfiguration, web?: (web: Web) => Web): this;
36
+ web(web: (web: Web) => Web): this;
37
+ ui(base: UIConfiguration, ui?: (ui: UI) => UI): this;
38
+ ui(ui: (ui: UI) => UI): this;
39
+ security(base: SecurityConfiguration, security?: (security: Security) => Security): this;
40
+ security(security: (security: Security) => Security): this;
41
+ alert(base: AlertingConfiguration, alert?: (alert: Alerting) => Alerting): this;
42
+ alert(alert: (alert: Alerting) => Alerting): this;
43
+ announcement(base: AnnouncementConfiguration, announcement?: (announcement: Announcement) => Announcement): this;
44
+ announcement(announcement: (announcement: Announcement) => Announcement): this;
45
+ maintenance(base: MaintenanceConfiguration, maintenance?: (maintenance: Maintenance) => Maintenance): this;
46
+ maintenance(maintenance: (maintenance: Maintenance) => Maintenance): this;
47
+ endpoint(base: EndpointConfiguration, endpoint?: (endpoint: Endpoint) => Endpoint): this;
48
+ endpoint(endpoint: (endpoint: Endpoint) => Endpoint): this;
49
+ externalEndpoint(base: ExternalEndpointConfiguration, endpoint?: (endpoint: ExternalEndpoint) => ExternalEndpoint): this;
50
+ externalEndpoint(endpoint: (endpoint: ExternalEndpoint) => ExternalEndpoint): this;
51
+ tunnel(name: string, base: TunnelingConfiguration, tunnel?: (tunnel: Tunnel) => Tunnel): this;
52
+ tunnel(name: string, tunnel: (tunnel: Tunnel) => Tunnel): this;
53
+ serialize(): Record<string, any>;
54
+ }