@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 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
+ }