@hasna/events 0.1.6 → 0.1.8
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/README.md +10 -0
- package/dist/cli/index.js +82 -2
- package/dist/commander.js +53 -0
- package/dist/index.js +55 -0
- package/dist/storage.d.ts +3 -1
- package/dist/storage.js +55 -0
- package/dist/types.d.ts +41 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -219,6 +219,16 @@ events events replay --type ticket.created
|
|
|
219
219
|
events events replay --dry-run
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
+
Machine-readable status:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
events status --json
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The status contract reports event, channel, delivery, file, and transport counts
|
|
229
|
+
only. It does not include event payloads, webhook signing secrets, command
|
|
230
|
+
environment values, or channel targets.
|
|
231
|
+
|
|
222
232
|
Use `--json` for script-friendly output and `--dir <path>` for isolated data.
|
|
223
233
|
|
|
224
234
|
## App Integration Pattern
|
package/dist/cli/index.js
CHANGED
|
@@ -62,6 +62,13 @@ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
|
62
62
|
function getEventsDataDir(override) {
|
|
63
63
|
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
|
|
64
64
|
}
|
|
65
|
+
function getActiveEventsDirEnv() {
|
|
66
|
+
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
67
|
+
return HASNA_EVENTS_DIR_ENV;
|
|
68
|
+
if (process.env[HASNA_EVENTS_HOME_ENV])
|
|
69
|
+
return HASNA_EVENTS_HOME_ENV;
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
65
72
|
|
|
66
73
|
class JsonEventsStore {
|
|
67
74
|
dataDir;
|
|
@@ -174,6 +181,52 @@ class JsonEventsStore {
|
|
|
174
181
|
});
|
|
175
182
|
}
|
|
176
183
|
}
|
|
184
|
+
async function getEventsStatus(dataDir) {
|
|
185
|
+
const store = new JsonEventsStore(dataDir);
|
|
186
|
+
await store.init();
|
|
187
|
+
const [channels, events, deliveries] = await Promise.all([
|
|
188
|
+
store.listChannels(),
|
|
189
|
+
store.listEvents(),
|
|
190
|
+
store.listDeliveries()
|
|
191
|
+
]);
|
|
192
|
+
const transports = channels.reduce((counts, channel) => {
|
|
193
|
+
counts[channel.transport] = (counts[channel.transport] ?? 0) + 1;
|
|
194
|
+
return counts;
|
|
195
|
+
}, {});
|
|
196
|
+
return {
|
|
197
|
+
service: "events",
|
|
198
|
+
schemaVersion: "1.0",
|
|
199
|
+
dataDir: store.dataDir,
|
|
200
|
+
env: {
|
|
201
|
+
primary: HASNA_EVENTS_DIR_ENV,
|
|
202
|
+
fallback: HASNA_EVENTS_HOME_ENV,
|
|
203
|
+
active: getActiveEventsDirEnv()
|
|
204
|
+
},
|
|
205
|
+
files: {
|
|
206
|
+
channels: statusFile(store.dataDir, "channels.json", channels.length),
|
|
207
|
+
events: statusFile(store.dataDir, "events.json", events.length),
|
|
208
|
+
deliveries: statusFile(store.dataDir, "deliveries.json", deliveries.length)
|
|
209
|
+
},
|
|
210
|
+
counts: {
|
|
211
|
+
channels: channels.length,
|
|
212
|
+
enabledChannels: channels.filter((channel) => channel.enabled).length,
|
|
213
|
+
disabledChannels: channels.filter((channel) => !channel.enabled).length,
|
|
214
|
+
events: events.length,
|
|
215
|
+
deliveries: deliveries.length
|
|
216
|
+
},
|
|
217
|
+
transports,
|
|
218
|
+
safety: {
|
|
219
|
+
includesEventPayloads: false,
|
|
220
|
+
includesWebhookSecrets: false,
|
|
221
|
+
listOutputsRedactSecrets: true,
|
|
222
|
+
statusOutputIsMetadataOnly: true
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function statusFile(dataDir, fileName, records) {
|
|
227
|
+
const path = join(dataDir, fileName);
|
|
228
|
+
return { path, exists: existsSync(path), records };
|
|
229
|
+
}
|
|
177
230
|
|
|
178
231
|
// src/transports.ts
|
|
179
232
|
import { randomUUID } from "crypto";
|
|
@@ -564,10 +617,19 @@ function parseGlobalArgs(argv) {
|
|
|
564
617
|
return { json, dir, rest };
|
|
565
618
|
}
|
|
566
619
|
function takeOption(args, name) {
|
|
620
|
+
const equalsPrefix = `${name}=`;
|
|
621
|
+
const equalsIndex = args.findIndex((arg) => arg.startsWith(equalsPrefix));
|
|
622
|
+
if (equalsIndex !== -1) {
|
|
623
|
+
const value2 = args[equalsIndex]?.slice(equalsPrefix.length);
|
|
624
|
+
args.splice(equalsIndex, 1);
|
|
625
|
+
return value2;
|
|
626
|
+
}
|
|
567
627
|
const index = args.indexOf(name);
|
|
568
628
|
if (index === -1)
|
|
569
629
|
return;
|
|
570
630
|
const value = args[index + 1];
|
|
631
|
+
if (value === undefined)
|
|
632
|
+
throw new Error(`${name} requires a value`);
|
|
571
633
|
args.splice(index, 2);
|
|
572
634
|
return value;
|
|
573
635
|
}
|
|
@@ -580,7 +642,7 @@ function takeFlag(args, name) {
|
|
|
580
642
|
}
|
|
581
643
|
function takeMany(args, name) {
|
|
582
644
|
const values = [];
|
|
583
|
-
while (args.includes(name)) {
|
|
645
|
+
while (args.includes(name) || args.some((arg) => arg.startsWith(`${name}=`))) {
|
|
584
646
|
const value = takeOption(args, name);
|
|
585
647
|
if (value !== undefined)
|
|
586
648
|
values.push(value);
|
|
@@ -643,6 +705,7 @@ Usage:
|
|
|
643
705
|
${name} [--dir <path>] [--json] webhooks list
|
|
644
706
|
${name} [--dir <path>] [--json] webhooks remove <id>
|
|
645
707
|
${name} [--dir <path>] [--json] webhooks test <id>
|
|
708
|
+
${name} [--dir <path>] [--json] status
|
|
646
709
|
${name} [--dir <path>] [--json] events emit <type>${options.source ? "" : " --source <source>"} [options]
|
|
647
710
|
${name} [--dir <path>] [--json] events list [--limit <n>]
|
|
648
711
|
${name} [--dir <path>] [--json] events replay [--id <event-id>] [--dry-run]
|
|
@@ -703,6 +766,14 @@ async function runEventsCli(argv = process.argv.slice(2), options = {}) {
|
|
|
703
766
|
console.log(version());
|
|
704
767
|
return;
|
|
705
768
|
}
|
|
769
|
+
if (group === "status") {
|
|
770
|
+
const status = await getEventsStatus(parsed.dir);
|
|
771
|
+
output(parsed, status, () => {
|
|
772
|
+
console.log(`events ${status.counts.events} event(s), ${status.counts.channels} channel(s), ${status.counts.deliveries} delivery record(s)`);
|
|
773
|
+
console.log(`dataDir: ${status.dataDir}`);
|
|
774
|
+
});
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
706
777
|
const store = new JsonEventsStore(parsed.dir);
|
|
707
778
|
const client = new EventsClient({ store });
|
|
708
779
|
if (group === "webhooks") {
|
|
@@ -710,6 +781,10 @@ async function runEventsCli(argv = process.argv.slice(2), options = {}) {
|
|
|
710
781
|
printWebhooksHelp(options);
|
|
711
782
|
return;
|
|
712
783
|
}
|
|
784
|
+
if (tail.includes("--help") || tail.includes("-h")) {
|
|
785
|
+
printWebhooksHelp(options);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
713
788
|
await handleWebhooks(client, command, tail, parsed, options);
|
|
714
789
|
return;
|
|
715
790
|
}
|
|
@@ -718,6 +793,10 @@ async function runEventsCli(argv = process.argv.slice(2), options = {}) {
|
|
|
718
793
|
printEventsHelp(options);
|
|
719
794
|
return;
|
|
720
795
|
}
|
|
796
|
+
if (tail.includes("--help") || tail.includes("-h")) {
|
|
797
|
+
printEventsHelp(options);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
721
800
|
await handleEvents(client, command, tail, parsed, options);
|
|
722
801
|
return;
|
|
723
802
|
}
|
|
@@ -735,6 +814,7 @@ async function handleWebhooks(client, command, tail, parsed, options) {
|
|
|
735
814
|
const retryBackoffMs = numberOption(takeOption(args, "--retry-backoff-ms"));
|
|
736
815
|
const disabled = takeFlag(args, "--disabled");
|
|
737
816
|
const headerValues = takeMany(args, "--header");
|
|
817
|
+
const commandArgs = takeMany(args, "--arg");
|
|
738
818
|
const redactions = takeMany(args, "--redact");
|
|
739
819
|
const filters = parseFilter(args);
|
|
740
820
|
const target = args[0];
|
|
@@ -755,7 +835,7 @@ async function handleWebhooks(client, command, tail, parsed, options) {
|
|
|
755
835
|
if (transport === "webhook") {
|
|
756
836
|
channel.webhook = { url: target, secret, headers: parseHeaders(headerValues), timeoutMs };
|
|
757
837
|
} else if (transport === "command") {
|
|
758
|
-
channel.command = { command: target, args: args.slice(1), timeoutMs };
|
|
838
|
+
channel.command = { command: target, args: [...args.slice(1), ...commandArgs], timeoutMs };
|
|
759
839
|
} else {
|
|
760
840
|
throw new Error(`Transport ${transport} is reserved for future use and cannot be added yet`);
|
|
761
841
|
}
|
package/dist/commander.js
CHANGED
|
@@ -52,6 +52,13 @@ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
|
52
52
|
function getEventsDataDir(override) {
|
|
53
53
|
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
|
|
54
54
|
}
|
|
55
|
+
function getActiveEventsDirEnv() {
|
|
56
|
+
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
57
|
+
return HASNA_EVENTS_DIR_ENV;
|
|
58
|
+
if (process.env[HASNA_EVENTS_HOME_ENV])
|
|
59
|
+
return HASNA_EVENTS_HOME_ENV;
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
55
62
|
|
|
56
63
|
class JsonEventsStore {
|
|
57
64
|
dataDir;
|
|
@@ -164,6 +171,52 @@ class JsonEventsStore {
|
|
|
164
171
|
});
|
|
165
172
|
}
|
|
166
173
|
}
|
|
174
|
+
async function getEventsStatus(dataDir) {
|
|
175
|
+
const store = new JsonEventsStore(dataDir);
|
|
176
|
+
await store.init();
|
|
177
|
+
const [channels, events, deliveries] = await Promise.all([
|
|
178
|
+
store.listChannels(),
|
|
179
|
+
store.listEvents(),
|
|
180
|
+
store.listDeliveries()
|
|
181
|
+
]);
|
|
182
|
+
const transports = channels.reduce((counts, channel) => {
|
|
183
|
+
counts[channel.transport] = (counts[channel.transport] ?? 0) + 1;
|
|
184
|
+
return counts;
|
|
185
|
+
}, {});
|
|
186
|
+
return {
|
|
187
|
+
service: "events",
|
|
188
|
+
schemaVersion: "1.0",
|
|
189
|
+
dataDir: store.dataDir,
|
|
190
|
+
env: {
|
|
191
|
+
primary: HASNA_EVENTS_DIR_ENV,
|
|
192
|
+
fallback: HASNA_EVENTS_HOME_ENV,
|
|
193
|
+
active: getActiveEventsDirEnv()
|
|
194
|
+
},
|
|
195
|
+
files: {
|
|
196
|
+
channels: statusFile(store.dataDir, "channels.json", channels.length),
|
|
197
|
+
events: statusFile(store.dataDir, "events.json", events.length),
|
|
198
|
+
deliveries: statusFile(store.dataDir, "deliveries.json", deliveries.length)
|
|
199
|
+
},
|
|
200
|
+
counts: {
|
|
201
|
+
channels: channels.length,
|
|
202
|
+
enabledChannels: channels.filter((channel) => channel.enabled).length,
|
|
203
|
+
disabledChannels: channels.filter((channel) => !channel.enabled).length,
|
|
204
|
+
events: events.length,
|
|
205
|
+
deliveries: deliveries.length
|
|
206
|
+
},
|
|
207
|
+
transports,
|
|
208
|
+
safety: {
|
|
209
|
+
includesEventPayloads: false,
|
|
210
|
+
includesWebhookSecrets: false,
|
|
211
|
+
listOutputsRedactSecrets: true,
|
|
212
|
+
statusOutputIsMetadataOnly: true
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function statusFile(dataDir, fileName, records) {
|
|
217
|
+
const path = join(dataDir, fileName);
|
|
218
|
+
return { path, exists: existsSync(path), records };
|
|
219
|
+
}
|
|
167
220
|
|
|
168
221
|
// src/signing.ts
|
|
169
222
|
import { createHmac, timingSafeEqual } from "crypto";
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,13 @@ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
|
52
52
|
function getEventsDataDir(override) {
|
|
53
53
|
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
|
|
54
54
|
}
|
|
55
|
+
function getActiveEventsDirEnv() {
|
|
56
|
+
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
57
|
+
return HASNA_EVENTS_DIR_ENV;
|
|
58
|
+
if (process.env[HASNA_EVENTS_HOME_ENV])
|
|
59
|
+
return HASNA_EVENTS_HOME_ENV;
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
55
62
|
|
|
56
63
|
class JsonEventsStore {
|
|
57
64
|
dataDir;
|
|
@@ -164,6 +171,52 @@ class JsonEventsStore {
|
|
|
164
171
|
});
|
|
165
172
|
}
|
|
166
173
|
}
|
|
174
|
+
async function getEventsStatus(dataDir) {
|
|
175
|
+
const store = new JsonEventsStore(dataDir);
|
|
176
|
+
await store.init();
|
|
177
|
+
const [channels, events, deliveries] = await Promise.all([
|
|
178
|
+
store.listChannels(),
|
|
179
|
+
store.listEvents(),
|
|
180
|
+
store.listDeliveries()
|
|
181
|
+
]);
|
|
182
|
+
const transports = channels.reduce((counts, channel) => {
|
|
183
|
+
counts[channel.transport] = (counts[channel.transport] ?? 0) + 1;
|
|
184
|
+
return counts;
|
|
185
|
+
}, {});
|
|
186
|
+
return {
|
|
187
|
+
service: "events",
|
|
188
|
+
schemaVersion: "1.0",
|
|
189
|
+
dataDir: store.dataDir,
|
|
190
|
+
env: {
|
|
191
|
+
primary: HASNA_EVENTS_DIR_ENV,
|
|
192
|
+
fallback: HASNA_EVENTS_HOME_ENV,
|
|
193
|
+
active: getActiveEventsDirEnv()
|
|
194
|
+
},
|
|
195
|
+
files: {
|
|
196
|
+
channels: statusFile(store.dataDir, "channels.json", channels.length),
|
|
197
|
+
events: statusFile(store.dataDir, "events.json", events.length),
|
|
198
|
+
deliveries: statusFile(store.dataDir, "deliveries.json", deliveries.length)
|
|
199
|
+
},
|
|
200
|
+
counts: {
|
|
201
|
+
channels: channels.length,
|
|
202
|
+
enabledChannels: channels.filter((channel) => channel.enabled).length,
|
|
203
|
+
disabledChannels: channels.filter((channel) => !channel.enabled).length,
|
|
204
|
+
events: events.length,
|
|
205
|
+
deliveries: deliveries.length
|
|
206
|
+
},
|
|
207
|
+
transports,
|
|
208
|
+
safety: {
|
|
209
|
+
includesEventPayloads: false,
|
|
210
|
+
includesWebhookSecrets: false,
|
|
211
|
+
listOutputsRedactSecrets: true,
|
|
212
|
+
statusOutputIsMetadataOnly: true
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function statusFile(dataDir, fileName, records) {
|
|
217
|
+
const path = join(dataDir, fileName);
|
|
218
|
+
return { path, exists: existsSync(path), records };
|
|
219
|
+
}
|
|
167
220
|
|
|
168
221
|
// src/signing.ts
|
|
169
222
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
@@ -558,7 +611,9 @@ export {
|
|
|
558
611
|
redactPaths,
|
|
559
612
|
matchString,
|
|
560
613
|
isTimestampWithinTolerance,
|
|
614
|
+
getEventsStatus,
|
|
561
615
|
getEventsDataDir,
|
|
616
|
+
getActiveEventsDirEnv,
|
|
562
617
|
eventMatchesFilter,
|
|
563
618
|
dispatchWebhook,
|
|
564
619
|
dispatchCommand,
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type { ChannelConfig, DeliveryResult, EventEnvelope, StoredEventsData } from "./types.js";
|
|
1
|
+
import type { ChannelConfig, DeliveryResult, EventEnvelope, EventsStatus, StoredEventsData } from "./types.js";
|
|
2
2
|
export declare const HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
|
|
3
3
|
export declare const HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
4
4
|
export declare function getEventsDataDir(override?: string): string;
|
|
5
|
+
export declare function getActiveEventsDirEnv(): EventsStatus["env"]["active"];
|
|
5
6
|
export interface EventsStore {
|
|
6
7
|
dataDir: string;
|
|
7
8
|
init(): Promise<void>;
|
|
@@ -42,3 +43,4 @@ export declare class JsonEventsStore implements EventsStore {
|
|
|
42
43
|
private readJson;
|
|
43
44
|
private writeJson;
|
|
44
45
|
}
|
|
46
|
+
export declare function getEventsStatus(dataDir?: string): Promise<EventsStatus>;
|
package/dist/storage.js
CHANGED
|
@@ -9,6 +9,13 @@ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
|
9
9
|
function getEventsDataDir(override) {
|
|
10
10
|
return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
|
|
11
11
|
}
|
|
12
|
+
function getActiveEventsDirEnv() {
|
|
13
|
+
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
14
|
+
return HASNA_EVENTS_DIR_ENV;
|
|
15
|
+
if (process.env[HASNA_EVENTS_HOME_ENV])
|
|
16
|
+
return HASNA_EVENTS_HOME_ENV;
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
12
19
|
|
|
13
20
|
class JsonEventsStore {
|
|
14
21
|
dataDir;
|
|
@@ -121,8 +128,56 @@ class JsonEventsStore {
|
|
|
121
128
|
});
|
|
122
129
|
}
|
|
123
130
|
}
|
|
131
|
+
async function getEventsStatus(dataDir) {
|
|
132
|
+
const store = new JsonEventsStore(dataDir);
|
|
133
|
+
await store.init();
|
|
134
|
+
const [channels, events, deliveries] = await Promise.all([
|
|
135
|
+
store.listChannels(),
|
|
136
|
+
store.listEvents(),
|
|
137
|
+
store.listDeliveries()
|
|
138
|
+
]);
|
|
139
|
+
const transports = channels.reduce((counts, channel) => {
|
|
140
|
+
counts[channel.transport] = (counts[channel.transport] ?? 0) + 1;
|
|
141
|
+
return counts;
|
|
142
|
+
}, {});
|
|
143
|
+
return {
|
|
144
|
+
service: "events",
|
|
145
|
+
schemaVersion: "1.0",
|
|
146
|
+
dataDir: store.dataDir,
|
|
147
|
+
env: {
|
|
148
|
+
primary: HASNA_EVENTS_DIR_ENV,
|
|
149
|
+
fallback: HASNA_EVENTS_HOME_ENV,
|
|
150
|
+
active: getActiveEventsDirEnv()
|
|
151
|
+
},
|
|
152
|
+
files: {
|
|
153
|
+
channels: statusFile(store.dataDir, "channels.json", channels.length),
|
|
154
|
+
events: statusFile(store.dataDir, "events.json", events.length),
|
|
155
|
+
deliveries: statusFile(store.dataDir, "deliveries.json", deliveries.length)
|
|
156
|
+
},
|
|
157
|
+
counts: {
|
|
158
|
+
channels: channels.length,
|
|
159
|
+
enabledChannels: channels.filter((channel) => channel.enabled).length,
|
|
160
|
+
disabledChannels: channels.filter((channel) => !channel.enabled).length,
|
|
161
|
+
events: events.length,
|
|
162
|
+
deliveries: deliveries.length
|
|
163
|
+
},
|
|
164
|
+
transports,
|
|
165
|
+
safety: {
|
|
166
|
+
includesEventPayloads: false,
|
|
167
|
+
includesWebhookSecrets: false,
|
|
168
|
+
listOutputsRedactSecrets: true,
|
|
169
|
+
statusOutputIsMetadataOnly: true
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function statusFile(dataDir, fileName, records) {
|
|
174
|
+
const path = join(dataDir, fileName);
|
|
175
|
+
return { path, exists: existsSync(path), records };
|
|
176
|
+
}
|
|
124
177
|
export {
|
|
178
|
+
getEventsStatus,
|
|
125
179
|
getEventsDataDir,
|
|
180
|
+
getActiveEventsDirEnv,
|
|
126
181
|
JsonEventsStore,
|
|
127
182
|
HASNA_EVENTS_HOME_ENV,
|
|
128
183
|
HASNA_EVENTS_DIR_ENV
|
package/dist/types.d.ts
CHANGED
|
@@ -117,3 +117,44 @@ export interface EmitResult<TData extends EventData = EventData> {
|
|
|
117
117
|
deliveries: DeliveryResult[];
|
|
118
118
|
deduped: boolean;
|
|
119
119
|
}
|
|
120
|
+
export interface EventsStatus {
|
|
121
|
+
service: "events";
|
|
122
|
+
schemaVersion: "1.0";
|
|
123
|
+
dataDir: string;
|
|
124
|
+
env: {
|
|
125
|
+
primary: "HASNA_EVENTS_DIR";
|
|
126
|
+
fallback: "HASNA_EVENTS_HOME";
|
|
127
|
+
active: "HASNA_EVENTS_DIR" | "HASNA_EVENTS_HOME" | null;
|
|
128
|
+
};
|
|
129
|
+
files: {
|
|
130
|
+
channels: {
|
|
131
|
+
path: string;
|
|
132
|
+
exists: boolean;
|
|
133
|
+
records: number;
|
|
134
|
+
};
|
|
135
|
+
events: {
|
|
136
|
+
path: string;
|
|
137
|
+
exists: boolean;
|
|
138
|
+
records: number;
|
|
139
|
+
};
|
|
140
|
+
deliveries: {
|
|
141
|
+
path: string;
|
|
142
|
+
exists: boolean;
|
|
143
|
+
records: number;
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
counts: {
|
|
147
|
+
channels: number;
|
|
148
|
+
enabledChannels: number;
|
|
149
|
+
disabledChannels: number;
|
|
150
|
+
events: number;
|
|
151
|
+
deliveries: number;
|
|
152
|
+
};
|
|
153
|
+
transports: Record<string, number>;
|
|
154
|
+
safety: {
|
|
155
|
+
includesEventPayloads: false;
|
|
156
|
+
includesWebhookSecrets: false;
|
|
157
|
+
listOutputsRedactSecrets: true;
|
|
158
|
+
statusOutputIsMetadataOnly: true;
|
|
159
|
+
};
|
|
160
|
+
}
|