@agentsoc/beacon 0.0.1 → 0.0.3
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 +49 -58
- package/dist/beacon-context.d.ts +14 -0
- package/dist/beacon-context.d.ts.map +1 -0
- package/dist/beacon-context.js +49 -0
- package/dist/beacon-update-info.d.ts +23 -0
- package/dist/beacon-update-info.d.ts.map +1 -0
- package/dist/beacon-update-info.js +62 -0
- package/dist/beacon-version.d.ts +5 -0
- package/dist/beacon-version.d.ts.map +1 -0
- package/dist/beacon-version.js +45 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +183 -15
- package/dist/config.d.ts +45 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +94 -0
- package/dist/enrich.d.ts +9 -0
- package/dist/enrich.d.ts.map +1 -0
- package/dist/forwarder.d.ts +20 -0
- package/dist/forwarder.d.ts.map +1 -0
- package/dist/forwarder.js +5 -0
- package/dist/run-beacon.d.ts +5 -0
- package/dist/run-beacon.d.ts.map +1 -0
- package/dist/service-install.d.ts +2 -0
- package/dist/service-install.d.ts.map +1 -0
- package/dist/service-install.js +4 -3
- package/dist/service-status.d.ts +11 -0
- package/dist/service-status.d.ts.map +1 -0
- package/dist/service-status.js +95 -0
- package/dist/stats.d.ts +15 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +71 -0
- package/dist/tail.d.ts +10 -0
- package/dist/tail.d.ts.map +1 -0
- package/package.json +22 -2
package/README.md
CHANGED
|
@@ -12,50 +12,36 @@ The Syslog Beacon CLI allows you to configure, install, and run a lightweight lo
|
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Installers are **hosted on the marketing site** (not duplicated in this repo):
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
| Method | URL / command |
|
|
18
|
+
|--------|----------------|
|
|
19
|
+
| **macOS / Linux (curl)** | `curl -fsSL https://agentsoc.com/connectors/beacon.sh \| bash` |
|
|
20
|
+
| **Windows PowerShell** | `irm https://agentsoc.com/connectors/beacon-install.ps1 \| iex` |
|
|
21
|
+
| **Windows (batch)** | Download and run [beacon-install.bat](https://agentsoc.com/connectors/beacon-install.bat) |
|
|
22
|
+
| **npm** | `npm install -g @agentsoc/beacon` |
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
curl -fsSL https://raw.githubusercontent.com/yourusername/platform.agentsoc.com/main/apps/connectors/syslog-beacon-cli/install.sh | bash
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
#### Windows PowerShell
|
|
24
|
-
|
|
25
|
-
```powershell
|
|
26
|
-
irm https://raw.githubusercontent.com/yourusername/platform.agentsoc.com/main/apps/connectors/syslog-beacon-cli/install.ps1 | iex
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
#### Standard npm
|
|
30
|
-
|
|
31
|
-
Published as [`@agentsoc/beacon`](https://www.npmjs.com/package/@agentsoc/beacon) (npm requires a lowercase scope; same AgentSOC package).
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
npm install -g @agentsoc/beacon
|
|
35
|
-
```
|
|
24
|
+
Published package: [`@agentsoc/beacon`](https://www.npmjs.com/package/@agentsoc/beacon) (npm scope is lowercase `agentsoc`).
|
|
36
25
|
|
|
37
26
|
The `syslog-beacon` command is also installed as an alias for the same CLI.
|
|
38
27
|
|
|
39
|
-
###
|
|
28
|
+
### Run from source (this monorepo)
|
|
40
29
|
|
|
41
30
|
If you have the repository cloned and [Bun](https://bun.sh/) installed:
|
|
42
31
|
|
|
43
32
|
```bash
|
|
44
33
|
cd apps/connectors/syslog-beacon-cli
|
|
45
34
|
bun install
|
|
46
|
-
bun run
|
|
47
|
-
|
|
35
|
+
bun run build:simple
|
|
36
|
+
npm install -g .
|
|
48
37
|
```
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Automated installation scripts are provided for easy setup:
|
|
53
|
-
|
|
54
|
-
- **`install.sh`** - macOS/Linux installer
|
|
55
|
-
- **`install.ps1`** - Windows PowerShell installer
|
|
56
|
-
- **`install.bat`** - Windows batch installer
|
|
39
|
+
Then use `beacon` / `syslog-beacon` like a normal global install:
|
|
57
40
|
|
|
58
|
-
|
|
41
|
+
```bash
|
|
42
|
+
beacon config --key <key> [--env production|development]
|
|
43
|
+
beacon run
|
|
44
|
+
```
|
|
59
45
|
|
|
60
46
|
## Usage
|
|
61
47
|
|
|
@@ -66,21 +52,22 @@ The CLI provides the following commands:
|
|
|
66
52
|
Configure the AgentSOC connection (saves to a local configuration file):
|
|
67
53
|
|
|
68
54
|
```bash
|
|
69
|
-
beacon config --
|
|
55
|
+
beacon config --key <key> [--env production|development]
|
|
70
56
|
```
|
|
71
57
|
|
|
72
|
-
**
|
|
58
|
+
**Parameters:**
|
|
73
59
|
|
|
74
|
-
- `--
|
|
75
|
-
- `--
|
|
60
|
+
- `--key, -k <key>`: AgentSOC API Key (required; e.g., `sk_1234567890abcdef`)
|
|
61
|
+
- `--env, -e <env>`: `production` (default) or `development` — selects default URLs for **log ingest** and for **`beacon status`** (platform API). Production: ingest `https://ingest.agentsoc.com/api/v1/webhooks/syslog`, platform `https://api.agentsoc.com`. Development: ingest `http://localhost:8110/api/v1/webhooks/syslog`, platform `http://localhost:8100`.
|
|
76
62
|
|
|
77
|
-
**
|
|
63
|
+
**Examples:**
|
|
78
64
|
|
|
79
65
|
```bash
|
|
80
|
-
beacon config --
|
|
66
|
+
beacon config --key sk_1234567890abcdef
|
|
67
|
+
beacon config --key sk_1234567890abcdef --env development
|
|
81
68
|
```
|
|
82
69
|
|
|
83
|
-
**Note:** If you run `bun run src/cli.ts config` without
|
|
70
|
+
**Note:** If you run `bun run src/cli.ts config` without `--key`, you'll receive usage help. URLs are not set in `config.json` (use `--env` or `AGENTSOC_ENV`). At runtime you can override **ingest** with `AGENTSOC_INGEST_URL` and the **platform API** (for `beacon status` only) with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL`.
|
|
84
71
|
|
|
85
72
|
### Run Foreground Daemon
|
|
86
73
|
|
|
@@ -101,48 +88,52 @@ beacon run [options]
|
|
|
101
88
|
beacon run --batch-size 50 --flush-ms 5000
|
|
102
89
|
```
|
|
103
90
|
|
|
104
|
-
_Note: You can
|
|
91
|
+
_Note: You can use `AGENTSOC_API_KEY` instead of saving a key in config. Use `AGENTSOC_ENV` (`production` / `development`) to override the saved environment for a single run. `AGENTSOC_INGEST_URL` overrides log shipping only. For `beacon status`, the CLI calls `GET {platform}/api/v1/siem/beacon/validate/key` (default platform from env above); override the platform origin with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL` if ingest and API live on different hosts._
|
|
105
92
|
|
|
106
93
|
### Install Service
|
|
107
94
|
|
|
108
95
|
Install the background service daemon (systemd on Linux, launchd on macOS):
|
|
109
96
|
|
|
110
97
|
```bash
|
|
111
|
-
beacon install
|
|
98
|
+
sudo beacon install
|
|
112
99
|
```
|
|
113
100
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
- Start the daemon using npm script: `npm start` or `bun run start`
|
|
117
|
-
- Install service using npm script: `npm run install-service` or `bun run install-service`
|
|
118
|
-
- Build the distributable: `npm run build:simple` (compiles TypeScript to dist/)
|
|
101
|
+
On macOS the plist is written under `/Library/LaunchDaemons/`, and on Linux the unit file goes under `/etc/systemd/system/`—both require root, so use `sudo`. If `sudo` cannot find `beacon` (for example with nvm), run `sudo env "PATH=$PATH" beacon install` or invoke the CLI with the full path to the global binary.
|
|
119
102
|
|
|
120
|
-
|
|
103
|
+
### Status and stats
|
|
121
104
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
To build the TypeScript files into the `dist/` folder:
|
|
105
|
+
Show whether the systemd/launchd service is present, resolve **organization name and API key label** via the platform API (`GET /api/v1/siem/beacon/validate/key` using your ingest key), and print forwarding counters from the local stats file:
|
|
125
106
|
|
|
126
107
|
```bash
|
|
127
|
-
|
|
108
|
+
beacon status
|
|
128
109
|
```
|
|
129
110
|
|
|
130
|
-
|
|
111
|
+
Use `beacon status --json` for machine-readable output (includes `validateKeyUrl` on errors).
|
|
131
112
|
|
|
132
|
-
|
|
113
|
+
After successful batches, the CLI updates **`stats.json`** next to your config (same config directory as `config.json`—for example `~/Library/Application Support/agentsoc-beacon/` on macOS). The file tracks `logsForwarded`, `batchesSucceeded`, `batchesFailed`, optional `lastError`, and `updatedAt`. If the beacon runs as another user (e.g. root), that user’s config directory holds the stats file.
|
|
133
114
|
|
|
134
|
-
|
|
135
|
-
- Copy the `install.ps1` script to your repository (Windows PowerShell users)
|
|
136
|
-
- Copy the `install.bat` script to your repository (Windows batch users)
|
|
115
|
+
The marketing site’s product demo terminal runs through **`beacon status`** so visitors can see a sample of this output.
|
|
137
116
|
|
|
138
|
-
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
- Start the daemon using npm script: `npm start` or `bun run start`
|
|
120
|
+
- Install service using npm script: `npm run install-service` or `bun run install-service`
|
|
121
|
+
- Build the distributable: `npm run build:simple` (compiles TypeScript to `dist/`)
|
|
122
|
+
|
|
123
|
+
## Building & distribution
|
|
124
|
+
|
|
125
|
+
### Build the package
|
|
139
126
|
|
|
140
127
|
```bash
|
|
141
|
-
|
|
128
|
+
npm run build:simple
|
|
142
129
|
```
|
|
143
130
|
|
|
144
|
-
|
|
131
|
+
### Publish to npm
|
|
132
|
+
|
|
133
|
+
From this directory, after bumping `version` in `package.json`:
|
|
145
134
|
|
|
146
135
|
```bash
|
|
147
|
-
npm
|
|
136
|
+
npm publish --access public
|
|
148
137
|
```
|
|
138
|
+
|
|
139
|
+
Public install entrypoints live under **`https://agentsoc.com/connectors/`** (`beacon.sh`, `beacon-install.ps1`, `beacon-install.bat`).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface BeaconContextOk {
|
|
2
|
+
ok: true;
|
|
3
|
+
organizationName: string | null;
|
|
4
|
+
organizationSlug: string | null;
|
|
5
|
+
apiKeyName: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BeaconContextErr {
|
|
8
|
+
ok: false;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
export type BeaconContextResult = BeaconContextOk | BeaconContextErr;
|
|
12
|
+
/** Calls platform `GET /api/v1/siem/beacon/validate/key` with the ingest API key. */
|
|
13
|
+
export declare function fetchBeaconContext(validateKeyUrl: string, apiKey: string): Promise<BeaconContextResult>;
|
|
14
|
+
//# sourceMappingURL=beacon-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-context.d.ts","sourceRoot":"","sources":["../src/beacon-context.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAWrE,qFAAqF;AACrF,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,CAAC,CAgD9B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Calls platform `GET /api/v1/siem/beacon/validate/key` with the ingest API key. */
|
|
2
|
+
export async function fetchBeaconContext(validateKeyUrl, apiKey) {
|
|
3
|
+
const controller = new AbortController();
|
|
4
|
+
const t = setTimeout(() => controller.abort(), 12_000);
|
|
5
|
+
try {
|
|
6
|
+
const res = await fetch(validateKeyUrl, {
|
|
7
|
+
method: "GET",
|
|
8
|
+
headers: { "X-API-Key": apiKey },
|
|
9
|
+
signal: controller.signal,
|
|
10
|
+
});
|
|
11
|
+
const text = await res.text();
|
|
12
|
+
let body;
|
|
13
|
+
try {
|
|
14
|
+
body = text ? JSON.parse(text) : null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return { ok: false, message: "Invalid response from platform API" };
|
|
18
|
+
}
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
const err = body;
|
|
21
|
+
const msg = err && typeof err.error === "string"
|
|
22
|
+
? err.error
|
|
23
|
+
: `HTTP ${res.status}`;
|
|
24
|
+
return { ok: false, message: msg };
|
|
25
|
+
}
|
|
26
|
+
const data = body;
|
|
27
|
+
if (!data?.success || !data.apiKey?.name) {
|
|
28
|
+
return { ok: false, message: "Unexpected response from platform API" };
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
organizationName: data.organization?.name ?? null,
|
|
33
|
+
organizationSlug: data.organization?.slug ?? null,
|
|
34
|
+
apiKeyName: data.apiKey.name,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
39
|
+
return { ok: false, message: "Request timed out" };
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
message: e instanceof Error ? e.message : String(e),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
clearTimeout(t);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type BeaconUpdateInfo = {
|
|
2
|
+
success: boolean;
|
|
3
|
+
package: string;
|
|
4
|
+
latestVersion: string | null;
|
|
5
|
+
registryResolved: boolean;
|
|
6
|
+
install: {
|
|
7
|
+
npm: string;
|
|
8
|
+
bun: string;
|
|
9
|
+
pnpm: string;
|
|
10
|
+
};
|
|
11
|
+
docsUrl: string;
|
|
12
|
+
installScriptUrl: string;
|
|
13
|
+
};
|
|
14
|
+
export type BeaconUpdateFetchResult = {
|
|
15
|
+
ok: true;
|
|
16
|
+
info: BeaconUpdateInfo;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
/** Latest @agentsoc/beacon version from the public npm registry (no AgentSOC API). */
|
|
22
|
+
export declare function fetchBeaconUpdateFromNpm(): Promise<BeaconUpdateFetchResult>;
|
|
23
|
+
//# sourceMappingURL=beacon-update-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-update-info.d.ts","sourceRoot":"","sources":["../src/beacon-update-info.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAsBnC,sFAAsF;AACtF,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAyCjF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const BEACON_PACKAGE = "@agentsoc/beacon";
|
|
2
|
+
const NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(BEACON_PACKAGE)}`;
|
|
3
|
+
const DOC_URL = "https://agentsoc.com/products/agentsoc-beacon";
|
|
4
|
+
const INSTALL_SCRIPT_URL = "https://agentsoc.com/connectors/beacon.sh";
|
|
5
|
+
function buildInfo(latestVersion, registryResolved) {
|
|
6
|
+
return {
|
|
7
|
+
success: true,
|
|
8
|
+
package: BEACON_PACKAGE,
|
|
9
|
+
latestVersion,
|
|
10
|
+
registryResolved,
|
|
11
|
+
install: {
|
|
12
|
+
npm: `npm install -g ${BEACON_PACKAGE}@latest`,
|
|
13
|
+
bun: `bun add -g ${BEACON_PACKAGE}@latest`,
|
|
14
|
+
pnpm: `pnpm add -g ${BEACON_PACKAGE}@latest`,
|
|
15
|
+
},
|
|
16
|
+
docsUrl: DOC_URL,
|
|
17
|
+
installScriptUrl: INSTALL_SCRIPT_URL,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Latest @agentsoc/beacon version from the public npm registry (no AgentSOC API). */
|
|
21
|
+
export async function fetchBeaconUpdateFromNpm() {
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const t = setTimeout(() => controller.abort(), 12_000);
|
|
24
|
+
try {
|
|
25
|
+
const res = await fetch(NPM_REGISTRY_URL, {
|
|
26
|
+
headers: { Accept: "application/json" },
|
|
27
|
+
signal: controller.signal,
|
|
28
|
+
});
|
|
29
|
+
const text = await res.text();
|
|
30
|
+
let body;
|
|
31
|
+
try {
|
|
32
|
+
body = text ? JSON.parse(text) : null;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { ok: false, message: "Invalid JSON from registry.npmjs.org" };
|
|
36
|
+
}
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
message: `registry.npmjs.org returned HTTP ${res.status}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const data = body;
|
|
44
|
+
const latest = data["dist-tags"]?.latest?.trim() ?? null;
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
info: buildInfo(latest, true),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
52
|
+
return { ok: false, message: "Request timed out" };
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
message: e instanceof Error ? e.message : String(e),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
clearTimeout(t);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Resolve @agentsoc/beacon version from the installed package.json (works for global npm install). */
|
|
2
|
+
export declare function readBeaconCliVersion(): string;
|
|
3
|
+
/** Simple semver compare for numeric x.y.z (ignores prerelease tail for ordering). */
|
|
4
|
+
export declare function semverLessThan(a: string, b: string): boolean;
|
|
5
|
+
//# sourceMappingURL=beacon-version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacon-version.d.ts","sourceRoot":"","sources":["../src/beacon-version.ts"],"names":[],"mappings":"AAIA,uGAAuG;AACvG,wBAAgB,oBAAoB,IAAI,MAAM,CAsB7C;AAOD,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAW5D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/** Resolve @agentsoc/beacon version from the installed package.json (works for global npm install). */
|
|
5
|
+
export function readBeaconCliVersion() {
|
|
6
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
for (let i = 0; i < 8; i++) {
|
|
8
|
+
const pkgPath = join(dir, "package.json");
|
|
9
|
+
if (existsSync(pkgPath)) {
|
|
10
|
+
try {
|
|
11
|
+
const j = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
12
|
+
if (j.name === "@agentsoc/beacon" && typeof j.version === "string") {
|
|
13
|
+
return j.version;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
/* try parent */
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const parent = dirname(dir);
|
|
21
|
+
if (parent === dir)
|
|
22
|
+
break;
|
|
23
|
+
dir = parent;
|
|
24
|
+
}
|
|
25
|
+
return "0.0.0";
|
|
26
|
+
}
|
|
27
|
+
function stripPrerelease(v) {
|
|
28
|
+
const i = v.indexOf("-");
|
|
29
|
+
return i === -1 ? v : v.slice(0, i);
|
|
30
|
+
}
|
|
31
|
+
/** Simple semver compare for numeric x.y.z (ignores prerelease tail for ordering). */
|
|
32
|
+
export function semverLessThan(a, b) {
|
|
33
|
+
const pa = stripPrerelease(a).split(".").map((x) => parseInt(x, 10) || 0);
|
|
34
|
+
const pb = stripPrerelease(b).split(".").map((x) => parseInt(x, 10) || 0);
|
|
35
|
+
const n = Math.max(pa.length, pb.length);
|
|
36
|
+
for (let i = 0; i < n; i++) {
|
|
37
|
+
const da = pa[i] ?? 0;
|
|
38
|
+
const db = pb[i] ?? 0;
|
|
39
|
+
if (da < db)
|
|
40
|
+
return true;
|
|
41
|
+
if (da > db)
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
CHANGED
|
@@ -1,35 +1,56 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
2
3
|
import { Command } from "commander";
|
|
3
|
-
import { loadConfig, saveConfig } from "./config.js";
|
|
4
|
+
import { BEACON_CONFIG_REQUIRED_MESSAGE, coerceBeaconEnvironment, loadConfig, parseBeaconEnvironment, resolveBeaconApiKey, resolveSiemBeaconValidateKeyUrl, resolveIngestUrl, saveConfig, } from "./config.js";
|
|
5
|
+
import { fetchBeaconContext } from "./beacon-context.js";
|
|
6
|
+
import { fetchBeaconUpdateFromNpm } from "./beacon-update-info.js";
|
|
7
|
+
import { readBeaconCliVersion, semverLessThan } from "./beacon-version.js";
|
|
4
8
|
import { runBeacon } from "./run-beacon.js";
|
|
5
9
|
import { installService } from "./service-install.js";
|
|
10
|
+
import { probeServiceStatus } from "./service-status.js";
|
|
11
|
+
import { getStatsFilePath, readStats } from "./stats.js";
|
|
12
|
+
const BEACON_VERSION = readBeaconCliVersion();
|
|
6
13
|
const program = new Command();
|
|
7
14
|
program
|
|
8
15
|
.name("beacon")
|
|
9
16
|
.description("AgentSOC Syslog Beacon - Lightweight background log forwarder")
|
|
10
|
-
.version(
|
|
17
|
+
.version(BEACON_VERSION, "-v, --version");
|
|
11
18
|
program
|
|
12
19
|
.command("config")
|
|
13
20
|
.description("Configure the AgentSOC connection")
|
|
14
|
-
.option("-
|
|
21
|
+
.option("-e, --env <env>", "Environment: production (default) or development")
|
|
15
22
|
.option("-k, --key <key>", "AgentSOC API Key")
|
|
16
23
|
.action(async (options) => {
|
|
17
|
-
if (!options.
|
|
18
|
-
console.log("\n[beacon] Missing required
|
|
19
|
-
console.log("Usage: beacon config --
|
|
24
|
+
if (!options.key) {
|
|
25
|
+
console.log("\n[beacon] Missing required option.\n");
|
|
26
|
+
console.log("Usage: beacon config --key <key> [--env production|development]\n");
|
|
20
27
|
console.log("Examples:");
|
|
21
|
-
console.log("
|
|
22
|
-
console.log(" beacon config --
|
|
28
|
+
console.log(" beacon config --key sk_1234567890abcdef");
|
|
29
|
+
console.log(" beacon config --key sk_1234567890abcdef --env development\n");
|
|
23
30
|
console.log("Options:");
|
|
24
|
-
console.log(" -
|
|
25
|
-
console.log(" -
|
|
31
|
+
console.log(" -k, --key <key> AgentSOC API Key (required)");
|
|
32
|
+
console.log(" -e, --env <env> production (default) or development; sets ingest + platform API defaults\n");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const existing = await loadConfig();
|
|
36
|
+
let environment;
|
|
37
|
+
try {
|
|
38
|
+
environment =
|
|
39
|
+
options.env !== undefined
|
|
40
|
+
? parseBeaconEnvironment(options.env)
|
|
41
|
+
: (coerceBeaconEnvironment(existing.environment) ?? "production");
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.error("[beacon]", e instanceof Error ? e.message : String(e));
|
|
26
45
|
process.exit(1);
|
|
27
46
|
}
|
|
28
47
|
await saveConfig({
|
|
29
|
-
ingestUrl: options.url,
|
|
30
48
|
apiKey: options.key,
|
|
49
|
+
environment,
|
|
50
|
+
agentId: existing.agentId,
|
|
31
51
|
});
|
|
32
52
|
console.log("[beacon] Config saved.");
|
|
53
|
+
console.log(`[beacon] Environment: ${environment}`);
|
|
33
54
|
});
|
|
34
55
|
program
|
|
35
56
|
.command("install")
|
|
@@ -43,6 +64,153 @@ program
|
|
|
43
64
|
process.exit(1);
|
|
44
65
|
}
|
|
45
66
|
});
|
|
67
|
+
program
|
|
68
|
+
.command("status")
|
|
69
|
+
.description("Show service state and forwarding statistics")
|
|
70
|
+
.option("--json", "Print machine-readable JSON on stdout")
|
|
71
|
+
.action(async (opts) => {
|
|
72
|
+
const svc = probeServiceStatus();
|
|
73
|
+
const stats = await readStats();
|
|
74
|
+
const statsPath = getStatsFilePath();
|
|
75
|
+
const cfg = await loadConfig();
|
|
76
|
+
const apiKey = resolveBeaconApiKey(cfg);
|
|
77
|
+
const validateKeyUrl = resolveSiemBeaconValidateKeyUrl(cfg);
|
|
78
|
+
const context = apiKey
|
|
79
|
+
? await fetchBeaconContext(validateKeyUrl, apiKey)
|
|
80
|
+
: ({
|
|
81
|
+
ok: false,
|
|
82
|
+
message: BEACON_CONFIG_REQUIRED_MESSAGE,
|
|
83
|
+
});
|
|
84
|
+
if (opts.json) {
|
|
85
|
+
console.log(JSON.stringify({
|
|
86
|
+
service: svc,
|
|
87
|
+
stats,
|
|
88
|
+
statsPath,
|
|
89
|
+
validateKeyUrl,
|
|
90
|
+
context: context.ok
|
|
91
|
+
? {
|
|
92
|
+
organizationName: context.organizationName,
|
|
93
|
+
organizationSlug: context.organizationSlug,
|
|
94
|
+
apiKeyName: context.apiKeyName,
|
|
95
|
+
}
|
|
96
|
+
: { error: context.message },
|
|
97
|
+
}, null, 2));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const labelW = 26;
|
|
101
|
+
const line = (label, value) => {
|
|
102
|
+
console.log(` ${label.padEnd(labelW)}${value}`);
|
|
103
|
+
};
|
|
104
|
+
console.log("\n AgentSOC Beacon — Status\n");
|
|
105
|
+
console.log(" Account");
|
|
106
|
+
if (context.ok) {
|
|
107
|
+
line("Organization", context.organizationName ??
|
|
108
|
+
"(name unavailable — check platform API / database)");
|
|
109
|
+
line("API key", context.apiKeyName);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
line("Connection", context.message);
|
|
113
|
+
}
|
|
114
|
+
console.log("\n Service");
|
|
115
|
+
line(`Daemon (${svc.manager})`, svc.installed ? svc.stateLabel : "not installed");
|
|
116
|
+
if (svc.active === true)
|
|
117
|
+
line("Running", "yes");
|
|
118
|
+
else if (svc.active === false)
|
|
119
|
+
line("Running", "no");
|
|
120
|
+
else
|
|
121
|
+
line("Running", "n/a");
|
|
122
|
+
if (svc.detail)
|
|
123
|
+
line("Note", svc.detail);
|
|
124
|
+
console.log("\n Forwarding (this machine)");
|
|
125
|
+
line("Log entries forwarded", String(stats.logsForwarded));
|
|
126
|
+
line("Successful batches", String(stats.batchesSucceeded));
|
|
127
|
+
line("Failed batches", String(stats.batchesFailed));
|
|
128
|
+
if (stats.updatedAt && stats.updatedAt !== new Date(0).toISOString()) {
|
|
129
|
+
line("Last stats update", stats.updatedAt);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
line("Last stats update", "(none yet)");
|
|
133
|
+
}
|
|
134
|
+
if (stats.lastError) {
|
|
135
|
+
line("Last error", stats.lastError);
|
|
136
|
+
}
|
|
137
|
+
console.log();
|
|
138
|
+
});
|
|
139
|
+
program
|
|
140
|
+
.command("update")
|
|
141
|
+
.description("Check for a newer Beacon CLI and optionally install it")
|
|
142
|
+
.option("--json", "Print machine-readable JSON on stdout")
|
|
143
|
+
.option("-y, --yes", "Run npm install -g @agentsoc/beacon@latest (non-interactive upgrade)")
|
|
144
|
+
.action(async (opts) => {
|
|
145
|
+
const current = BEACON_VERSION;
|
|
146
|
+
const fetched = await fetchBeaconUpdateFromNpm();
|
|
147
|
+
if (opts.json) {
|
|
148
|
+
const latest = fetched.ok ? fetched.info.latestVersion : null;
|
|
149
|
+
const outdated = latest != null &&
|
|
150
|
+
latest.length > 0 &&
|
|
151
|
+
semverLessThan(current, latest);
|
|
152
|
+
console.log(JSON.stringify({
|
|
153
|
+
currentVersion: current,
|
|
154
|
+
registry: "https://registry.npmjs.org/@agentsoc%2fbeacon",
|
|
155
|
+
remote: fetched.ok ? fetched.info : null,
|
|
156
|
+
error: fetched.ok ? undefined : fetched.message,
|
|
157
|
+
updateAvailable: fetched.ok ? outdated : null,
|
|
158
|
+
}, null, 2));
|
|
159
|
+
if (!fetched.ok)
|
|
160
|
+
process.exit(1);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (!fetched.ok) {
|
|
164
|
+
console.error(`[beacon] Could not reach npm registry: ${fetched.message}`);
|
|
165
|
+
console.error("[beacon] You can still run: npm install -g @agentsoc/beacon@latest");
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
const { info } = fetched;
|
|
169
|
+
const latest = info.latestVersion;
|
|
170
|
+
console.log("\n AgentSOC Beacon — Update check\n");
|
|
171
|
+
console.log(` This install ${current}`);
|
|
172
|
+
if (latest) {
|
|
173
|
+
console.log(` Latest on registry ${latest}`);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(" Latest on registry (unavailable — unexpected npm response)");
|
|
177
|
+
}
|
|
178
|
+
const canCompare = Boolean(latest && latest.length > 0);
|
|
179
|
+
const outdated = canCompare && semverLessThan(current, latest);
|
|
180
|
+
if (canCompare && !outdated) {
|
|
181
|
+
console.log("\n You are on the latest published version.\n");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (canCompare && outdated) {
|
|
185
|
+
console.log("\n A newer version is available.\n");
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
console.log("\n Compare versions manually, or reinstall with:\n");
|
|
189
|
+
}
|
|
190
|
+
console.log(` ${info.install.npm}`);
|
|
191
|
+
console.log(` ${info.install.bun}`);
|
|
192
|
+
console.log(` ${info.install.pnpm}`);
|
|
193
|
+
if (info.docsUrl) {
|
|
194
|
+
console.log(`\n Docs: ${info.docsUrl}`);
|
|
195
|
+
}
|
|
196
|
+
if (opts.yes) {
|
|
197
|
+
if (!outdated && canCompare) {
|
|
198
|
+
console.log("\n[beacon] Already up to date — skipping install.\n");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
console.log("\n[beacon] Running npm install -g @agentsoc/beacon@latest …\n");
|
|
202
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
203
|
+
try {
|
|
204
|
+
execFileSync(npm, ["install", "-g", "@agentsoc/beacon@latest"], { stdio: "inherit", env: process.env });
|
|
205
|
+
console.log("\n[beacon] Update finished. Run `beacon --version` to verify.\n");
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
console.log("\n To upgrade now, run the same command with --yes\n");
|
|
213
|
+
});
|
|
46
214
|
program
|
|
47
215
|
.command("run")
|
|
48
216
|
.description("Run the forwarder daemon (foreground)")
|
|
@@ -50,10 +218,10 @@ program
|
|
|
50
218
|
.option("--flush-ms <n>", "Flush interval in ms", "2000")
|
|
51
219
|
.action(async (options) => {
|
|
52
220
|
const config = await loadConfig();
|
|
53
|
-
const apiKey =
|
|
54
|
-
const ingestUrl =
|
|
55
|
-
if (!apiKey
|
|
56
|
-
console.error(
|
|
221
|
+
const apiKey = resolveBeaconApiKey(config);
|
|
222
|
+
const ingestUrl = resolveIngestUrl(config);
|
|
223
|
+
if (!apiKey) {
|
|
224
|
+
console.error(`[beacon] ${BEACON_CONFIG_REQUIRED_MESSAGE}`);
|
|
57
225
|
process.exit(1);
|
|
58
226
|
}
|
|
59
227
|
console.log("[beacon] Starting in foreground...");
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const INGEST_URL_PRODUCTION = "https://ingest.agentsoc.com/api/v1/webhooks/syslog";
|
|
2
|
+
export declare const INGEST_URL_DEVELOPMENT = "http://localhost:8110/api/v1/webhooks/syslog";
|
|
3
|
+
/** Platform API (for `beacon status` key validation — not log ingest). */
|
|
4
|
+
export declare const PLATFORM_API_PRODUCTION = "https://api.agentsoc.com";
|
|
5
|
+
export declare const PLATFORM_API_DEVELOPMENT = "http://localhost:8100";
|
|
6
|
+
/** Path on the platform API for SIEM ingest key validation (`beacon status`). */
|
|
7
|
+
export declare const SIEM_BEACON_VALIDATE_KEY_PATH = "/api/v1/siem/beacon/validate/key";
|
|
8
|
+
export type BeaconEnvironment = "production" | "development";
|
|
9
|
+
/** API key from saved config or process environment (trimmed). */
|
|
10
|
+
export declare function resolveBeaconApiKey(config: BeaconConfig): string | undefined;
|
|
11
|
+
/** Shown when run/install needs a key and none is configured. */
|
|
12
|
+
export declare const BEACON_CONFIG_REQUIRED_MESSAGE = "Beacon is not configured. Run: beacon config --key <your-api-key> [--env production|development]. Or set AGENTSOC_API_KEY in your environment.";
|
|
13
|
+
export interface BeaconConfig {
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
/** @deprecated Resolved from environment; not set by the CLI */
|
|
16
|
+
ingestUrl?: string;
|
|
17
|
+
/** Defaults to production when omitted */
|
|
18
|
+
environment?: BeaconEnvironment;
|
|
19
|
+
agentId?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function parseBeaconEnvironment(input: string): BeaconEnvironment;
|
|
22
|
+
export declare function coerceBeaconEnvironment(value: unknown): BeaconEnvironment | undefined;
|
|
23
|
+
export declare function ingestUrlForEnvironment(env: BeaconEnvironment): string;
|
|
24
|
+
export declare function effectiveEnvironment(config: BeaconConfig): BeaconEnvironment;
|
|
25
|
+
/**
|
|
26
|
+
* Ingest URL used at runtime. Optional AGENTSOC_INGEST_URL overrides (legacy
|
|
27
|
+
* / advanced); otherwise derived from AGENTSOC_ENV or saved environment.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveIngestUrl(config: BeaconConfig): string;
|
|
30
|
+
/**
|
|
31
|
+
* Platform API origin (no trailing slash).
|
|
32
|
+
* Override with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolvePlatformApiBase(config: BeaconConfig): string;
|
|
35
|
+
/**
|
|
36
|
+
* Full URL for `GET …/siem/beacon/validate/key` (organization + API key label for `beacon status`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveSiemBeaconValidateKeyUrl(config: BeaconConfig): string;
|
|
39
|
+
/** @deprecated Use {@link resolveSiemBeaconValidateKeyUrl} */
|
|
40
|
+
export declare function resolveBeaconContextUrl(config: BeaconConfig): string;
|
|
41
|
+
export declare function getConfigDir(): string;
|
|
42
|
+
export declare function getConfigFile(): string;
|
|
43
|
+
export declare function loadConfig(): Promise<BeaconConfig>;
|
|
44
|
+
export declare function saveConfig(config: BeaconConfig): Promise<void>;
|
|
45
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,uDACoB,CAAC;AAEvD,eAAO,MAAM,sBAAsB,iDACa,CAAC;AAEjD,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAEhE,iFAAiF;AACjF,eAAO,MAAM,6BAA6B,qCACN,CAAC;AAErC,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,aAAa,CAAC;AAE7D,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAK5E;AAED,iEAAiE;AACjE,eAAO,MAAM,8BAA8B,mJACuG,CAAC;AAEnJ,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAOvE;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,iBAAiB,GAAG,SAAS,CAU/B;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAItE;AAmBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,iBAAiB,CAM5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAI7D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAMnE;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,YAAY,GACnB,MAAM,CAER;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEpE;AAED,wBAAgB,YAAY,IAAI,MAAM,CAarC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC,CAQxD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAepE"}
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,100 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
|
+
export const INGEST_URL_PRODUCTION = "https://ingest.agentsoc.com/api/v1/webhooks/syslog";
|
|
5
|
+
export const INGEST_URL_DEVELOPMENT = "http://localhost:8110/api/v1/webhooks/syslog";
|
|
6
|
+
/** Platform API (for `beacon status` key validation — not log ingest). */
|
|
7
|
+
export const PLATFORM_API_PRODUCTION = "https://api.agentsoc.com";
|
|
8
|
+
export const PLATFORM_API_DEVELOPMENT = "http://localhost:8100";
|
|
9
|
+
/** Path on the platform API for SIEM ingest key validation (`beacon status`). */
|
|
10
|
+
export const SIEM_BEACON_VALIDATE_KEY_PATH = "/api/v1/siem/beacon/validate/key";
|
|
11
|
+
/** API key from saved config or process environment (trimmed). */
|
|
12
|
+
export function resolveBeaconApiKey(config) {
|
|
13
|
+
const fromEnv = process.env.AGENTSOC_API_KEY?.trim();
|
|
14
|
+
if (fromEnv)
|
|
15
|
+
return fromEnv;
|
|
16
|
+
const fromFile = config.apiKey?.trim();
|
|
17
|
+
return fromFile || undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Shown when run/install needs a key and none is configured. */
|
|
20
|
+
export const BEACON_CONFIG_REQUIRED_MESSAGE = "Beacon is not configured. Run: beacon config --key <your-api-key> [--env production|development]. Or set AGENTSOC_API_KEY in your environment.";
|
|
21
|
+
export function parseBeaconEnvironment(input) {
|
|
22
|
+
const s = input.toLowerCase().trim();
|
|
23
|
+
if (s === "production" || s === "prod")
|
|
24
|
+
return "production";
|
|
25
|
+
if (s === "development" || s === "dev")
|
|
26
|
+
return "development";
|
|
27
|
+
throw new Error(`Invalid environment "${input}". Use production or development (prod / dev).`);
|
|
28
|
+
}
|
|
29
|
+
export function coerceBeaconEnvironment(value) {
|
|
30
|
+
if (value === "production" || value === "development")
|
|
31
|
+
return value;
|
|
32
|
+
if (typeof value === "string") {
|
|
33
|
+
try {
|
|
34
|
+
return parseBeaconEnvironment(value);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
export function ingestUrlForEnvironment(env) {
|
|
43
|
+
return env === "development"
|
|
44
|
+
? INGEST_URL_DEVELOPMENT
|
|
45
|
+
: INGEST_URL_PRODUCTION;
|
|
46
|
+
}
|
|
47
|
+
function platformApiBaseForEnvironment(env) {
|
|
48
|
+
return env === "development" ? PLATFORM_API_DEVELOPMENT : PLATFORM_API_PRODUCTION;
|
|
49
|
+
}
|
|
50
|
+
function environmentFromProcessEnv() {
|
|
51
|
+
const raw = process.env.AGENTSOC_ENV?.trim();
|
|
52
|
+
if (!raw)
|
|
53
|
+
return undefined;
|
|
54
|
+
try {
|
|
55
|
+
return parseBeaconEnvironment(raw);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
console.warn(`[beacon] Ignoring invalid AGENTSOC_ENV="${raw}" (use production or development).`);
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function effectiveEnvironment(config) {
|
|
63
|
+
return (environmentFromProcessEnv() ??
|
|
64
|
+
coerceBeaconEnvironment(config.environment) ??
|
|
65
|
+
"production");
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Ingest URL used at runtime. Optional AGENTSOC_INGEST_URL overrides (legacy
|
|
69
|
+
* / advanced); otherwise derived from AGENTSOC_ENV or saved environment.
|
|
70
|
+
*/
|
|
71
|
+
export function resolveIngestUrl(config) {
|
|
72
|
+
const override = process.env.AGENTSOC_INGEST_URL?.trim();
|
|
73
|
+
if (override)
|
|
74
|
+
return override;
|
|
75
|
+
return ingestUrlForEnvironment(effectiveEnvironment(config));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Platform API origin (no trailing slash).
|
|
79
|
+
* Override with `AGENTSOC_PLATFORM_URL` or `AGENTSOC_PLATFORM_API_BASE_URL`.
|
|
80
|
+
*/
|
|
81
|
+
export function resolvePlatformApiBase(config) {
|
|
82
|
+
const override = process.env.AGENTSOC_PLATFORM_URL?.trim() ||
|
|
83
|
+
process.env.AGENTSOC_PLATFORM_API_BASE_URL?.trim();
|
|
84
|
+
if (override)
|
|
85
|
+
return override.replace(/\/$/, "");
|
|
86
|
+
return platformApiBaseForEnvironment(effectiveEnvironment(config));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Full URL for `GET …/siem/beacon/validate/key` (organization + API key label for `beacon status`).
|
|
90
|
+
*/
|
|
91
|
+
export function resolveSiemBeaconValidateKeyUrl(config) {
|
|
92
|
+
return `${resolvePlatformApiBase(config)}${SIEM_BEACON_VALIDATE_KEY_PATH}`;
|
|
93
|
+
}
|
|
94
|
+
/** @deprecated Use {@link resolveSiemBeaconValidateKeyUrl} */
|
|
95
|
+
export function resolveBeaconContextUrl(config) {
|
|
96
|
+
return resolveSiemBeaconValidateKeyUrl(config);
|
|
97
|
+
}
|
|
4
98
|
export function getConfigDir() {
|
|
5
99
|
const home = os.homedir();
|
|
6
100
|
if (process.platform === "win32") {
|
package/dist/enrich.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,CA8BrD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HostInfo } from "./enrich.js";
|
|
2
|
+
export interface ForwarderOptions {
|
|
3
|
+
ingestUrl: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
batchSize?: number;
|
|
6
|
+
flushMs?: number;
|
|
7
|
+
host: HostInfo;
|
|
8
|
+
}
|
|
9
|
+
export declare class Forwarder {
|
|
10
|
+
private opts;
|
|
11
|
+
private buffer;
|
|
12
|
+
private timer;
|
|
13
|
+
private readonly batchSize;
|
|
14
|
+
private readonly flushMs;
|
|
15
|
+
constructor(opts: ForwarderOptions);
|
|
16
|
+
pushLog(line: string): void;
|
|
17
|
+
private flush;
|
|
18
|
+
stop(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=forwarder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forwarder.d.ts","sourceRoot":"","sources":["../src/forwarder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;CAChB;AA6ED,qBAAa,SAAS;IAMR,OAAO,CAAC,IAAI;IALxB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAEb,IAAI,EAAE,gBAAgB;IAKnC,OAAO,CAAC,IAAI,EAAE,MAAM;YAoCb,KAAK;IA4CN,IAAI;CAKlB"}
|
package/dist/forwarder.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { recordFailedBatch, recordSuccessfulBatch } from "./stats.js";
|
|
1
2
|
function parseSyslogPri(line) {
|
|
2
3
|
// Default mapping if line does not start with <PRI>
|
|
3
4
|
let severity = 5; // notice (maps to 'low' severity in our logic)
|
|
@@ -114,14 +115,18 @@ export class Forwarder {
|
|
|
114
115
|
});
|
|
115
116
|
if (!res.ok) {
|
|
116
117
|
const text = await res.text();
|
|
118
|
+
const msg = `HTTP ${res.status} ${text}`;
|
|
117
119
|
console.error(`[syslog-beacon] Failed to push logs: HTTP ${res.status} ${text}`);
|
|
120
|
+
await recordFailedBatch(msg);
|
|
118
121
|
}
|
|
119
122
|
else {
|
|
120
123
|
console.log(`[syslog-beacon] Successfully pushed ${payload.length} logs`);
|
|
124
|
+
await recordSuccessfulBatch(payload.length);
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
catch (err) {
|
|
124
128
|
console.error(`[syslog-beacon] Ingest error:`, err);
|
|
129
|
+
await recordFailedBatch(err instanceof Error ? err.message : String(err));
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
async stop() {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-beacon.d.ts","sourceRoot":"","sources":["../src/run-beacon.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG7D,wBAAsB,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC;;GAiBnE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-install.d.ts","sourceRoot":"","sources":["../src/service-install.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,kBAgEnC"}
|
package/dist/service-install.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
|
-
import { loadConfig } from './config.js';
|
|
4
|
+
import { BEACON_CONFIG_REQUIRED_MESSAGE, loadConfig } from './config.js';
|
|
5
5
|
export async function installService() {
|
|
6
6
|
const config = await loadConfig();
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
// Service units do not inherit the install shell's env — key must be saved in config.
|
|
8
|
+
if (!config.apiKey?.trim()) {
|
|
9
|
+
throw new Error(BEACON_CONFIG_REQUIRED_MESSAGE);
|
|
9
10
|
}
|
|
10
11
|
const isBun = process.execPath.endsWith('bun') || process.execPath.endsWith('bun.exe');
|
|
11
12
|
const runner = isBun ? process.execPath : 'node';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ServiceManager = "systemd" | "launchd" | "none";
|
|
2
|
+
export interface ServiceStatus {
|
|
3
|
+
manager: ServiceManager;
|
|
4
|
+
installed: boolean;
|
|
5
|
+
active: boolean | null;
|
|
6
|
+
/** Human-readable state from the platform (e.g. active, inactive, running) */
|
|
7
|
+
stateLabel: string;
|
|
8
|
+
detail?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function probeServiceStatus(): ServiceStatus;
|
|
11
|
+
//# sourceMappingURL=service-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-status.d.ts","sourceRoot":"","sources":["../src/service-status.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACvB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,wBAAgB,kBAAkB,IAAI,aAAa,CA4FlD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
function trimDetail(s, max = 200) {
|
|
4
|
+
const one = s.replace(/\s+/g, " ").trim();
|
|
5
|
+
return one.length <= max ? one : `${one.slice(0, max)}…`;
|
|
6
|
+
}
|
|
7
|
+
export function probeServiceStatus() {
|
|
8
|
+
if (process.platform === "linux") {
|
|
9
|
+
const unitPath = "/etc/systemd/system/syslog-beacon.service";
|
|
10
|
+
const installed = fs.existsSync(unitPath);
|
|
11
|
+
if (!installed) {
|
|
12
|
+
return {
|
|
13
|
+
manager: "systemd",
|
|
14
|
+
installed: false,
|
|
15
|
+
active: null,
|
|
16
|
+
stateLabel: "not installed",
|
|
17
|
+
detail: "No unit at /etc/systemd/system/syslog-beacon.service",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const out = execFileSync("systemctl", ["is-active", "syslog-beacon"], {
|
|
22
|
+
encoding: "utf8",
|
|
23
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
24
|
+
}).trim();
|
|
25
|
+
const active = out === "active";
|
|
26
|
+
return {
|
|
27
|
+
manager: "systemd",
|
|
28
|
+
installed: true,
|
|
29
|
+
active,
|
|
30
|
+
stateLabel: out || "unknown",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const status = err.status;
|
|
35
|
+
const stderr = err.stderr?.toString?.() ?? "";
|
|
36
|
+
if (status === 3) {
|
|
37
|
+
return {
|
|
38
|
+
manager: "systemd",
|
|
39
|
+
installed: true,
|
|
40
|
+
active: false,
|
|
41
|
+
stateLabel: "inactive",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
manager: "systemd",
|
|
46
|
+
installed: true,
|
|
47
|
+
active: false,
|
|
48
|
+
stateLabel: "unknown",
|
|
49
|
+
detail: trimDetail(stderr || String(err)),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (process.platform === "darwin") {
|
|
54
|
+
const plistPath = "/Library/LaunchDaemons/com.agentsoc.syslog-beacon.plist";
|
|
55
|
+
const installed = fs.existsSync(plistPath);
|
|
56
|
+
if (!installed) {
|
|
57
|
+
return {
|
|
58
|
+
manager: "launchd",
|
|
59
|
+
installed: false,
|
|
60
|
+
active: null,
|
|
61
|
+
stateLabel: "not installed",
|
|
62
|
+
detail: `No plist at ${plistPath}`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const out = execFileSync("launchctl", ["print", "system/com.agentsoc.syslog-beacon"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
67
|
+
const m = out.match(/^\s*state\s*=\s*(\S+)/m);
|
|
68
|
+
const state = m?.[1] ?? "unknown";
|
|
69
|
+
const active = state === "running";
|
|
70
|
+
return {
|
|
71
|
+
manager: "launchd",
|
|
72
|
+
installed: true,
|
|
73
|
+
active,
|
|
74
|
+
stateLabel: state,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const stderr = err.stderr?.toString?.() ?? "";
|
|
79
|
+
return {
|
|
80
|
+
manager: "launchd",
|
|
81
|
+
installed: true,
|
|
82
|
+
active: null,
|
|
83
|
+
stateLabel: "unknown",
|
|
84
|
+
detail: trimDetail(stderr || String(err)),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
manager: "none",
|
|
90
|
+
installed: false,
|
|
91
|
+
active: null,
|
|
92
|
+
stateLabel: "unsupported",
|
|
93
|
+
detail: "Automatic service detection is only available on Linux (systemd) and macOS (launchd).",
|
|
94
|
+
};
|
|
95
|
+
}
|
package/dist/stats.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare const STATS_VERSION: 1;
|
|
2
|
+
export interface BeaconStatsFile {
|
|
3
|
+
version: typeof STATS_VERSION;
|
|
4
|
+
updatedAt: string;
|
|
5
|
+
logsForwarded: number;
|
|
6
|
+
batchesSucceeded: number;
|
|
7
|
+
batchesFailed: number;
|
|
8
|
+
lastError?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function getStatsFilePath(): string;
|
|
11
|
+
export declare function readStats(): Promise<BeaconStatsFile>;
|
|
12
|
+
export declare function recordSuccessfulBatch(logCount: number): Promise<void>;
|
|
13
|
+
export declare function recordFailedBatch(message: string): Promise<void>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,aAAa,EAAG,CAAU,CAAC;AAEjC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,aAAa,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,eAAe,CAAC,CAa1D;AAWD,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc3E;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAetE"}
|
package/dist/stats.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getConfigDir } from "./config.js";
|
|
4
|
+
const STATS_VERSION = 1;
|
|
5
|
+
const emptyStats = () => ({
|
|
6
|
+
version: STATS_VERSION,
|
|
7
|
+
updatedAt: new Date(0).toISOString(),
|
|
8
|
+
logsForwarded: 0,
|
|
9
|
+
batchesSucceeded: 0,
|
|
10
|
+
batchesFailed: 0,
|
|
11
|
+
});
|
|
12
|
+
export function getStatsFilePath() {
|
|
13
|
+
return path.join(getConfigDir(), "stats.json");
|
|
14
|
+
}
|
|
15
|
+
export async function readStats() {
|
|
16
|
+
try {
|
|
17
|
+
const raw = await fs.readFile(getStatsFilePath(), "utf8");
|
|
18
|
+
const parsed = JSON.parse(raw);
|
|
19
|
+
if (parsed.version !== STATS_VERSION)
|
|
20
|
+
return emptyStats();
|
|
21
|
+
return {
|
|
22
|
+
...emptyStats(),
|
|
23
|
+
...parsed,
|
|
24
|
+
version: STATS_VERSION,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return emptyStats();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function writeStatsAtomic(stats) {
|
|
32
|
+
const file = getStatsFilePath();
|
|
33
|
+
const dir = path.dirname(file);
|
|
34
|
+
await fs.mkdir(dir, { recursive: true });
|
|
35
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
36
|
+
await fs.writeFile(tmp, JSON.stringify(stats, null, 2), "utf8");
|
|
37
|
+
await fs.rename(tmp, file);
|
|
38
|
+
}
|
|
39
|
+
export async function recordSuccessfulBatch(logCount) {
|
|
40
|
+
try {
|
|
41
|
+
const cur = await readStats();
|
|
42
|
+
await writeStatsAtomic({
|
|
43
|
+
version: STATS_VERSION,
|
|
44
|
+
updatedAt: new Date().toISOString(),
|
|
45
|
+
logsForwarded: cur.logsForwarded + logCount,
|
|
46
|
+
batchesSucceeded: cur.batchesSucceeded + 1,
|
|
47
|
+
batchesFailed: cur.batchesFailed,
|
|
48
|
+
lastError: undefined,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// stats are best-effort; never break forwarding
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function recordFailedBatch(message) {
|
|
56
|
+
try {
|
|
57
|
+
const cur = await readStats();
|
|
58
|
+
const trimmed = message.replace(/\s+/g, " ").slice(0, 500);
|
|
59
|
+
await writeStatsAtomic({
|
|
60
|
+
version: STATS_VERSION,
|
|
61
|
+
updatedAt: new Date().toISOString(),
|
|
62
|
+
logsForwarded: cur.logsForwarded,
|
|
63
|
+
batchesSucceeded: cur.batchesSucceeded,
|
|
64
|
+
batchesFailed: cur.batchesFailed + 1,
|
|
65
|
+
lastError: trimmed || "Unknown error",
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// best-effort
|
|
70
|
+
}
|
|
71
|
+
}
|
package/dist/tail.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../src/tail.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAEjD,qBAAa,YAAY;IAIX,OAAO,CAAC,KAAK;IAHzB,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,SAAS,CAAC,CAAe;gBAEb,KAAK,EAAE,WAAW;IAE/B,KAAK;IAkDL,IAAI;CAQZ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentsoc/beacon",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Lightweight, background-running log forwarder (beacon) for AgentSOC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,11 +8,31 @@
|
|
|
8
8
|
"syslog-beacon": "./dist/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"main": "./dist/cli.js",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./dist/cli.js",
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
"./config": {
|
|
15
|
+
"types": "./dist/config.d.ts",
|
|
16
|
+
"import": "./dist/config.js"
|
|
17
|
+
},
|
|
18
|
+
"./stats": {
|
|
19
|
+
"types": "./dist/stats.d.ts",
|
|
20
|
+
"import": "./dist/stats.js"
|
|
21
|
+
},
|
|
22
|
+
"./service-status": {
|
|
23
|
+
"types": "./dist/service-status.d.ts",
|
|
24
|
+
"import": "./dist/service-status.js"
|
|
25
|
+
},
|
|
26
|
+
"./service-install": {
|
|
27
|
+
"types": "./dist/service-install.d.ts",
|
|
28
|
+
"import": "./dist/service-install.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
11
31
|
"files": [
|
|
12
32
|
"dist"
|
|
13
33
|
],
|
|
14
34
|
"scripts": {
|
|
15
|
-
"build": "bun run --cwd ../../.. bun build --target
|
|
35
|
+
"build": "bun run --cwd ../../.. bun build --target node --entry-points ./apps/connectors/syslog-beacon-cli/src/cli.ts --outdir ./apps/connectors/syslog-beacon-cli/dist --minify",
|
|
16
36
|
"build:simple": "tsc",
|
|
17
37
|
"start": "bun run src/cli.ts run",
|
|
18
38
|
"install-service": "bun run src/cli.ts install"
|