@theholocron/holocron-plugin-axiom 3.54.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.
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/index.d.mts +115 -0
- package/dist/index.mjs +128 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Newton Koumantzelis
|
|
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,75 @@
|
|
|
1
|
+
<!-- editorconfig-checker-disable-file -->
|
|
2
|
+
|
|
3
|
+
# `@theholocron/holocron-plugin-axiom`
|
|
4
|
+
|
|
5
|
+
Axiom plugin for [Holocron](../cli). Implements the `logs` capability
|
|
6
|
+
against [Axiom's REST API](https://axiom.co/docs/restapi/introduction),
|
|
7
|
+
plus exports `verifyToken` + `AUTH_HINT` for use by `holocron auth`.
|
|
8
|
+
|
|
9
|
+
> This plugin does **not** ship log lines. `@theholocron/logger`'s Axiom
|
|
10
|
+
> transport reads `HOLOCRON_AXIOM_TOKEN` / `HOLOCRON_AXIOM_DATASET`
|
|
11
|
+
> directly at startup. The `logs` capability exists only for the
|
|
12
|
+
> management surface — `holocron setup` provisions the aggregation
|
|
13
|
+
> datasets and `holocron doctor` checks connectivity.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add -D @theholocron/holocron-plugin-axiom
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Auth
|
|
22
|
+
|
|
23
|
+
Token resolution order:
|
|
24
|
+
|
|
25
|
+
1. `--token <TOKEN>` flag on the holocron invocation
|
|
26
|
+
2. `HOLOCRON_AXIOM_TOKEN` env var (preferred — explicit intent)
|
|
27
|
+
3. `AXIOM_TOKEN` env var (Axiom-native, works in CI)
|
|
28
|
+
4. Keyring `axiom.<org>` — tried first when an org is active via `--org`, `HOLOCRON_ORG`, or `org` in `holocron.config.ts`
|
|
29
|
+
5. Keyring `axiom` — unnamespaced fallback; set via `holocron auth set axiom <token>`
|
|
30
|
+
6. `AuthError` naming both env vars + the auth hint
|
|
31
|
+
|
|
32
|
+
Generate an API token at **app.axiom.co/settings/api-tokens** with
|
|
33
|
+
permission to read and create datasets.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
holocron auth set axiom.theholocron <TOKEN>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**CI**: the keyring is unavailable in headless containers — expose the
|
|
40
|
+
token as `HOLOCRON_AXIOM_TOKEN` (or `AXIOM_TOKEN`) in the workflow env.
|
|
41
|
+
|
|
42
|
+
## Config
|
|
43
|
+
|
|
44
|
+
```jsonc
|
|
45
|
+
{
|
|
46
|
+
"providers": {
|
|
47
|
+
"logs": "axiom",
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
No options are required. `holocron setup` provisions the `holocron-ci`
|
|
53
|
+
and `holocron-local` datasets; `holocron doctor` checks the dataset
|
|
54
|
+
named by `HOLOCRON_AXIOM_DATASET` / `AXIOM_DATASET`. An explicit
|
|
55
|
+
`logs: ["axiom", { "dataset": "holocron-ci" }]` overrides the env var
|
|
56
|
+
for `doctor`.
|
|
57
|
+
|
|
58
|
+
`HOLOCRON_AXIOM_DATASET` is **not a secret** — set it in your shell
|
|
59
|
+
profile locally (`holocron-local`) or as an org CI secret
|
|
60
|
+
(`holocron-ci`). Leave it unset locally to skip Axiom entirely.
|
|
61
|
+
|
|
62
|
+
## What's implemented
|
|
63
|
+
|
|
64
|
+
| Method | Behavior |
|
|
65
|
+
| --------------- | ------------------------------------------------------------------------------------------------ |
|
|
66
|
+
| `describe` | Returns `{ provider: "axiom", envKeys: ["HOLOCRON_AXIOM_TOKEN", "HOLOCRON_AXIOM_DATASET"] }`. |
|
|
67
|
+
| `whoami` | `GET /v2/datasets/{dataset}` — verifies the token and the configured dataset's reachability. |
|
|
68
|
+
| `ensureDataset` | `GET /v2/datasets/{name}`; on 404, `POST /v2/datasets`. Returns `{ alreadyExists }`. Idempotent. |
|
|
69
|
+
|
|
70
|
+
Plugin-level exports (not capability methods, per the auth-bootstrap convention):
|
|
71
|
+
|
|
72
|
+
| Export | Purpose |
|
|
73
|
+
| ------------- | ------------------------------------------------------------------------------------------- |
|
|
74
|
+
| `verifyToken` | `GET /v2/user` — returns `{ ok: true, subject: "user @ …" }` or `{ ok: false, message }`. |
|
|
75
|
+
| `AUTH_HINT` | One-line hint printed by `holocron auth set` when no token is supplied or the token is bad. |
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { AuthError, Logs, ResolveTokenInput } from "@theholocron/cli";
|
|
2
|
+
//#region src/auth.d.ts
|
|
3
|
+
declare const resolveToken: (input?: ResolveTokenInput) => string;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/rest.d.ts
|
|
6
|
+
/** Axiom dataset — the subset of fields Holocron reads. */
|
|
7
|
+
interface AxiomDataset {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Axiom user — the subset returned by `GET /v2/user`. */
|
|
13
|
+
interface AxiomUser {
|
|
14
|
+
id: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
email?: string;
|
|
17
|
+
emails?: string[];
|
|
18
|
+
}
|
|
19
|
+
interface AxiomClientOptions {
|
|
20
|
+
token: string;
|
|
21
|
+
/** Override the API base URL (default `https://api.axiom.co`). */
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
/** Override `fetch` for tests. */
|
|
24
|
+
fetch?: typeof fetch;
|
|
25
|
+
}
|
|
26
|
+
interface AxiomRestClient {
|
|
27
|
+
getDataset(name: string): Promise<AxiomDataset>;
|
|
28
|
+
createDataset(input: {
|
|
29
|
+
name: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
}): Promise<AxiomDataset>;
|
|
32
|
+
getCurrentUser(): Promise<AxiomUser>;
|
|
33
|
+
}
|
|
34
|
+
declare function createAxiomClient(opts: AxiomClientOptions): AxiomRestClient;
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/capabilities/logs.d.ts
|
|
37
|
+
interface AxiomLogsOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Target dataset, resolved from `HOLOCRON_AXIOM_DATASET` /
|
|
40
|
+
* `AXIOM_DATASET`. Required for `whoami`; not needed for `describe`
|
|
41
|
+
* or `ensureDataset` (which takes an explicit name).
|
|
42
|
+
*/
|
|
43
|
+
dataset?: string;
|
|
44
|
+
}
|
|
45
|
+
declare class AxiomLogs implements Logs {
|
|
46
|
+
private readonly client;
|
|
47
|
+
private readonly opts;
|
|
48
|
+
readonly key: "logs";
|
|
49
|
+
readonly providerName = "axiom";
|
|
50
|
+
constructor(client: AxiomRestClient, opts: AxiomLogsOptions);
|
|
51
|
+
describe(): Promise<{
|
|
52
|
+
provider: string;
|
|
53
|
+
envKeys: string[];
|
|
54
|
+
}>;
|
|
55
|
+
whoami(): Promise<{
|
|
56
|
+
ok: boolean;
|
|
57
|
+
dataset: string;
|
|
58
|
+
}>;
|
|
59
|
+
ensureDataset(name: string): Promise<{
|
|
60
|
+
alreadyExists: boolean;
|
|
61
|
+
}>;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/verify-token.d.ts
|
|
65
|
+
/**
|
|
66
|
+
* `verifyToken` — plugin-level export used by `holocron auth set axiom`
|
|
67
|
+
* + `holocron auth check`. Hits `GET /v2/user` and translates the
|
|
68
|
+
* response into the normalized `VerifyTokenResult` shape.
|
|
69
|
+
*
|
|
70
|
+
* Kept as a standalone function (not a capability method) so the auth
|
|
71
|
+
* command can call it without initializing the full plugin.
|
|
72
|
+
*/
|
|
73
|
+
interface VerifyTokenSuccess {
|
|
74
|
+
ok: true;
|
|
75
|
+
subject: string;
|
|
76
|
+
}
|
|
77
|
+
interface VerifyTokenFailure {
|
|
78
|
+
ok: false;
|
|
79
|
+
message: string;
|
|
80
|
+
}
|
|
81
|
+
type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
|
|
82
|
+
interface VerifyTokenOptions {
|
|
83
|
+
baseUrl?: string;
|
|
84
|
+
fetch?: typeof fetch;
|
|
85
|
+
}
|
|
86
|
+
declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/index.d.ts
|
|
89
|
+
interface AxiomPluginOptions extends ResolveTokenInput, AxiomLogsOptions {
|
|
90
|
+
/** Override base URL for tests. */
|
|
91
|
+
baseUrl?: string;
|
|
92
|
+
/** Override `fetch` for tests. */
|
|
93
|
+
fetch?: typeof fetch;
|
|
94
|
+
}
|
|
95
|
+
interface PluginContext {
|
|
96
|
+
options: AxiomPluginOptions & {
|
|
97
|
+
dataset?: string;
|
|
98
|
+
};
|
|
99
|
+
client: AxiomRestClient;
|
|
100
|
+
}
|
|
101
|
+
declare function createContext(options: AxiomPluginOptions): PluginContext;
|
|
102
|
+
declare function logs(ctx: PluginContext): Logs;
|
|
103
|
+
declare function createPlugin(options: AxiomPluginOptions): {
|
|
104
|
+
name: string;
|
|
105
|
+
capabilities: {
|
|
106
|
+
logs: () => Logs;
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* One-line hint shown by `holocron auth set axiom` when no token is
|
|
111
|
+
* supplied or when the supplied token is rejected.
|
|
112
|
+
*/
|
|
113
|
+
declare const AUTH_HINT: string;
|
|
114
|
+
//#endregion
|
|
115
|
+
export { AUTH_HINT, AuthError, type AxiomClientOptions, type AxiomDataset, AxiomLogs, type AxiomLogsOptions, AxiomPluginOptions, type AxiomRestClient, type AxiomUser, PluginContext, type ResolveTokenInput, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, createAxiomClient, createContext, createPlugin, logs, resolveToken, verifyToken };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { AuthError, ProviderApiError, createResolveToken, createRestClient } from "@theholocron/cli";
|
|
2
|
+
//#region src/auth.ts
|
|
3
|
+
const resolveToken = createResolveToken({
|
|
4
|
+
envName: "HOLOCRON_AXIOM_TOKEN",
|
|
5
|
+
vendorEnvName: "AXIOM_TOKEN",
|
|
6
|
+
keyringService: "axiom",
|
|
7
|
+
errorMessage: "no Axiom token found. Pass --token <TOKEN>, set HOLOCRON_AXIOM_TOKEN / AXIOM_TOKEN, or run: holocron auth set axiom <TOKEN>"
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/capabilities/logs.ts
|
|
11
|
+
var AxiomLogs = class {
|
|
12
|
+
client;
|
|
13
|
+
opts;
|
|
14
|
+
key = "logs";
|
|
15
|
+
providerName = "axiom";
|
|
16
|
+
constructor(client, opts) {
|
|
17
|
+
this.client = client;
|
|
18
|
+
this.opts = opts;
|
|
19
|
+
}
|
|
20
|
+
async describe() {
|
|
21
|
+
return {
|
|
22
|
+
provider: "axiom",
|
|
23
|
+
envKeys: ["HOLOCRON_AXIOM_TOKEN", "HOLOCRON_AXIOM_DATASET"]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async whoami() {
|
|
27
|
+
const dataset = this.opts.dataset;
|
|
28
|
+
if (!dataset) throw new Error("@theholocron/holocron-plugin-axiom needs a dataset (HOLOCRON_AXIOM_DATASET / AXIOM_DATASET) for whoami");
|
|
29
|
+
await this.client.getDataset(dataset);
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
dataset
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async ensureDataset(name) {
|
|
36
|
+
try {
|
|
37
|
+
await this.client.getDataset(name);
|
|
38
|
+
return { alreadyExists: true };
|
|
39
|
+
} catch (err) {
|
|
40
|
+
if (!(err instanceof ProviderApiError) || err.status !== 404) throw err;
|
|
41
|
+
}
|
|
42
|
+
await this.client.createDataset({
|
|
43
|
+
name,
|
|
44
|
+
description: "Managed by holocron"
|
|
45
|
+
});
|
|
46
|
+
return { alreadyExists: false };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
function createAxiomClient(opts) {
|
|
50
|
+
const rest = createRestClient({
|
|
51
|
+
baseUrl: opts.baseUrl ?? "https://api.axiom.co",
|
|
52
|
+
token: opts.token,
|
|
53
|
+
vendor: "Axiom",
|
|
54
|
+
fetch: opts.fetch
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
getDataset: (name) => rest.request(`/v2/datasets/${encodeURIComponent(name)}`),
|
|
58
|
+
createDataset: (input) => rest.request("/v2/datasets", {
|
|
59
|
+
method: "POST",
|
|
60
|
+
body: input
|
|
61
|
+
}),
|
|
62
|
+
getCurrentUser: () => rest.request("/v2/user")
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/verify-token.ts
|
|
67
|
+
/**
|
|
68
|
+
* `verifyToken` — plugin-level export used by `holocron auth set axiom`
|
|
69
|
+
* + `holocron auth check`. Hits `GET /v2/user` and translates the
|
|
70
|
+
* response into the normalized `VerifyTokenResult` shape.
|
|
71
|
+
*
|
|
72
|
+
* Kept as a standalone function (not a capability method) so the auth
|
|
73
|
+
* command can call it without initializing the full plugin.
|
|
74
|
+
*/
|
|
75
|
+
async function verifyToken(token, opts = {}) {
|
|
76
|
+
const client = createAxiomClient({
|
|
77
|
+
token,
|
|
78
|
+
baseUrl: opts.baseUrl,
|
|
79
|
+
fetch: opts.fetch
|
|
80
|
+
});
|
|
81
|
+
try {
|
|
82
|
+
const me = await client.getCurrentUser();
|
|
83
|
+
return {
|
|
84
|
+
ok: true,
|
|
85
|
+
subject: `user @ ${me.email ?? me.emails?.[0] ?? me.name ?? me.id ?? "unknown"}`
|
|
86
|
+
};
|
|
87
|
+
} catch (err) {
|
|
88
|
+
return {
|
|
89
|
+
ok: false,
|
|
90
|
+
message: err instanceof Error ? err.message : String(err)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/index.ts
|
|
96
|
+
function createContext(options) {
|
|
97
|
+
const token = resolveToken(options);
|
|
98
|
+
const env = options.env ?? process.env;
|
|
99
|
+
const dataset = options.dataset ?? env.HOLOCRON_AXIOM_DATASET ?? env.AXIOM_DATASET;
|
|
100
|
+
return {
|
|
101
|
+
options: {
|
|
102
|
+
...options,
|
|
103
|
+
dataset
|
|
104
|
+
},
|
|
105
|
+
client: createAxiomClient({
|
|
106
|
+
token,
|
|
107
|
+
baseUrl: options.baseUrl,
|
|
108
|
+
fetch: options.fetch
|
|
109
|
+
})
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function logs(ctx) {
|
|
113
|
+
return new AxiomLogs(ctx.client, { dataset: ctx.options.dataset });
|
|
114
|
+
}
|
|
115
|
+
function createPlugin(options) {
|
|
116
|
+
const ctx = createContext(options);
|
|
117
|
+
return {
|
|
118
|
+
name: "@theholocron/holocron-plugin-axiom",
|
|
119
|
+
capabilities: { logs: () => logs(ctx) }
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* One-line hint shown by `holocron auth set axiom` when no token is
|
|
124
|
+
* supplied or when the supplied token is rejected.
|
|
125
|
+
*/
|
|
126
|
+
const AUTH_HINT = "generate an Axiom API token at https://app.axiom.co/settings/api-tokens with dataset read + create permissions, then run: holocron auth set axiom <TOKEN>";
|
|
127
|
+
//#endregion
|
|
128
|
+
export { AUTH_HINT, AuthError, AxiomLogs, createAxiomClient, createContext, createPlugin, logs, resolveToken, verifyToken };
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@theholocron/holocron-plugin-axiom",
|
|
3
|
+
"version": "3.54.0",
|
|
4
|
+
"description": "Holocron plugin for Axiom. Implements the logs capability against Axiom's REST API — dataset provisioning and connectivity checks, plus verifyToken + AUTH_HINT for `holocron auth`.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"axiom",
|
|
7
|
+
"holocron",
|
|
8
|
+
"logs",
|
|
9
|
+
"plugin"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/theholocron/holocron/tree/main/packages/holocron-plugin-axiom#readme",
|
|
12
|
+
"bugs": "https://github.com/theholocron/holocron/issues",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/theholocron/holocron.git",
|
|
16
|
+
"directory": "packages/holocron-plugin-axiom"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Newton Koumantzelis",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"type": "module",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.mts",
|
|
25
|
+
"import": "./dist/index.mjs",
|
|
26
|
+
"default": "./dist/index.mjs"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@theholocron/eslint-config": "^7.32.1",
|
|
34
|
+
"@theholocron/tsconfig": "^7.32.1",
|
|
35
|
+
"@theholocron/tsdown-config": "^7.32.1",
|
|
36
|
+
"@theholocron/vitest-config": "^7.32.1",
|
|
37
|
+
"@types/node": "^26",
|
|
38
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
39
|
+
"@vitest/eslint-plugin": "^1.6.27",
|
|
40
|
+
"eslint": "^10.8.1",
|
|
41
|
+
"eslint-plugin-n": "^18.3.0",
|
|
42
|
+
"globals": "^17.11.0",
|
|
43
|
+
"tsdown": "^0.22.14",
|
|
44
|
+
"tsx": "4.23.12",
|
|
45
|
+
"typescript": "^5.9.3",
|
|
46
|
+
"vitest": "^4.1.11",
|
|
47
|
+
"@theholocron/cli": "3.54.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@theholocron/cli": "3.54.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsdown",
|
|
60
|
+
"lint": "eslint .",
|
|
61
|
+
"typecheck": "tsc --noEmit",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:watch": "vitest",
|
|
64
|
+
"test:coverage": "vitest run --coverage",
|
|
65
|
+
"validate": "tsx scripts/validate.mjs"
|
|
66
|
+
}
|
|
67
|
+
}
|