@arnek/arnekellmann-sdk 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.
- package/README.md +55 -0
- package/cli.js +42 -0
- package/index.d.ts +24 -0
- package/index.js +32 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Arne Kellmann JavaScript / TypeScript SDK and CLI
|
|
2
|
+
|
|
3
|
+
JavaScript / TypeScript package for the anonymous, read-only consulting services API.
|
|
4
|
+
SDK integration source is distributed separately from the
|
|
5
|
+
private website repository at [arnekellmann-agent-tools](https://github.com/ArneFfm/arnekellmann-agent-tools).
|
|
6
|
+
No open-source license has been granted.
|
|
7
|
+
|
|
8
|
+
Requires Node.js 20 or later:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install @arnek/arnekellmann-sdk
|
|
12
|
+
npx arnekellmann --help
|
|
13
|
+
npx arnekellmann services de
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { ArneKellmannClient, ServicesApiError } from '@arnek/arnekellmann-sdk';
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const catalog = await new ArneKellmannClient().listServices('en');
|
|
21
|
+
console.log(catalog.services);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error instanceof ServicesApiError) {
|
|
24
|
+
console.error(error.status, error.retryAfter);
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`listServices(language = 'en')` accepts `en` or `de` and returns the complete
|
|
31
|
+
catalog: `language`, `services` (`id`, `name`, `description`, `url`), `pricing`
|
|
32
|
+
(custom quote, no published rates), and `contactUrl`. TypeScript declarations
|
|
33
|
+
are included. No pagination is needed for this small catalog.
|
|
34
|
+
|
|
35
|
+
CLI output is JSON on stdout; failures go to stderr with exit code 1. `--help`
|
|
36
|
+
and `--version` work offline. To use a local development server:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npx arnekellmann services en --base-url http://localhost:4321
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The constructor accepts the same HTTP(S) base URL; API paths resolve from its
|
|
43
|
+
origin. URLs containing credentials are rejected. Requests send
|
|
44
|
+
`Accept: application/json`, time out after ten seconds, and are never retried
|
|
45
|
+
automatically. HTTP errors include `status` and the raw `retryAfter` header
|
|
46
|
+
(seconds or HTTP date, or null). Fetch/network and JSON parsing errors propagate.
|
|
47
|
+
|
|
48
|
+
There are no credentials, contact submission, booking or payment methods. A
|
|
49
|
+
contact URL is informational; opening it does not send an enquiry.
|
|
50
|
+
|
|
51
|
+
Package validation: `npm pack --dry-run` from this directory. Installing the
|
|
52
|
+
result of `npm pack` exercises the same CLI and included type declarations.
|
|
53
|
+
|
|
54
|
+
[API documentation](https://arnekellmann.de/developers) ·
|
|
55
|
+
[OpenAPI](https://arnekellmann.de/api/openapi.json)
|
package/cli.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { parseArgs } from 'node:util';
|
|
4
|
+
import { ArneKellmannClient } from './index.js';
|
|
5
|
+
|
|
6
|
+
const usage = `Usage: arnekellmann services [en|de] [--base-url URL]
|
|
7
|
+
arnekellmann --help
|
|
8
|
+
arnekellmann --version
|
|
9
|
+
|
|
10
|
+
Reads public consulting services as JSON. No credentials or writes.
|
|
11
|
+
Default URL: https://arnekellmann.de. Requests time out after 10 seconds.`;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const { values, positionals } = parseArgs({
|
|
15
|
+
allowPositionals: true,
|
|
16
|
+
options: {
|
|
17
|
+
help: { type: 'boolean', short: 'h' },
|
|
18
|
+
version: { type: 'boolean', short: 'v' },
|
|
19
|
+
'base-url': { type: 'string' },
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
if (values.help) {
|
|
23
|
+
console.log(usage);
|
|
24
|
+
} else if (values.version) {
|
|
25
|
+
console.log(
|
|
26
|
+
JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')).version
|
|
27
|
+
);
|
|
28
|
+
} else {
|
|
29
|
+
const [command, language = 'en', ...extra] = positionals;
|
|
30
|
+
if (command !== 'services' || extra.length) throw new Error(usage);
|
|
31
|
+
console.log(
|
|
32
|
+
JSON.stringify(
|
|
33
|
+
await new ArneKellmannClient(values['base-url']).listServices(language),
|
|
34
|
+
null,
|
|
35
|
+
2
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(error.message);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type Language = 'en' | 'de';
|
|
2
|
+
export interface Service {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
url: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ServicesResponse {
|
|
9
|
+
language: Language;
|
|
10
|
+
services: Service[];
|
|
11
|
+
pricing: { type: 'custom_quote'; publishedRates: false; url: string };
|
|
12
|
+
contactUrl: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class ArneKellmannClient {
|
|
15
|
+
constructor(baseUrl?: string);
|
|
16
|
+
baseUrl: URL;
|
|
17
|
+
listServices(language?: Language): Promise<ServicesResponse>;
|
|
18
|
+
}
|
|
19
|
+
export declare class ServicesApiError extends Error {
|
|
20
|
+
constructor(status: number, retryAfter?: string | null);
|
|
21
|
+
status: number;
|
|
22
|
+
/** Raw Retry-After header, either seconds or an HTTP date; null when absent. */
|
|
23
|
+
retryAfter: string | null;
|
|
24
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Read-only client. No contact submission or automatic retries. */
|
|
2
|
+
export class ArneKellmannClient {
|
|
3
|
+
constructor(baseUrl = 'https://arnekellmann.de') {
|
|
4
|
+
this.baseUrl = new URL(baseUrl);
|
|
5
|
+
if (
|
|
6
|
+
!['http:', 'https:'].includes(this.baseUrl.protocol) ||
|
|
7
|
+
this.baseUrl.username ||
|
|
8
|
+
this.baseUrl.password
|
|
9
|
+
) {
|
|
10
|
+
throw new Error('Use an HTTP(S) base URL without credentials.');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async listServices(language = 'en') {
|
|
14
|
+
if (!['en', 'de'].includes(language)) throw new Error('Use language en or de.');
|
|
15
|
+
const response = await fetch(new URL(`/api/v1/services?language=${language}`, this.baseUrl), {
|
|
16
|
+
headers: { Accept: 'application/json' },
|
|
17
|
+
signal: AbortSignal.timeout(10000),
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok)
|
|
20
|
+
throw new ServicesApiError(response.status, response.headers.get('Retry-After'));
|
|
21
|
+
return response.json();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ServicesApiError extends Error {
|
|
26
|
+
constructor(status, retryAfter = null) {
|
|
27
|
+
super(`Services API returned HTTP ${status}`);
|
|
28
|
+
this.name = 'ServicesApiError';
|
|
29
|
+
this.status = status;
|
|
30
|
+
this.retryAfter = retryAfter;
|
|
31
|
+
}
|
|
32
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arnek/arnekellmann-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Read the public Arne Kellmann consulting services API.",
|
|
6
|
+
"homepage": "https://arnekellmann.de/developers",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/ArneFfm/arnekellmann-agent-tools.git",
|
|
10
|
+
"directory": "packages/sdk-js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"import": "./index.js"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"arnekellmann": "./cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"index.js",
|
|
21
|
+
"cli.js",
|
|
22
|
+
"README.md",
|
|
23
|
+
"index.d.ts"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20"
|
|
27
|
+
},
|
|
28
|
+
"types": "./index.d.ts",
|
|
29
|
+
"license": "UNLICENSED",
|
|
30
|
+
"keywords": [
|
|
31
|
+
"arnekellmann",
|
|
32
|
+
"consulting",
|
|
33
|
+
"sdk",
|
|
34
|
+
"cli"
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
}
|
|
39
|
+
}
|