@bpmnkit/api 0.0.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 +150 -0
- package/dist/generated/admin-resources.d.ts +199 -0
- package/dist/generated/admin-resources.js +381 -0
- package/dist/generated/admin-types.d.ts +283 -0
- package/dist/generated/admin-types.js +4 -0
- package/dist/generated/resources.d.ts +1519 -0
- package/dist/generated/resources.js +2650 -0
- package/dist/generated/types.d.ts +11946 -0
- package/dist/generated/types.js +4 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +10 -0
- package/dist/runtime/auth.d.ts +31 -0
- package/dist/runtime/auth.js +136 -0
- package/dist/runtime/cache.d.ts +13 -0
- package/dist/runtime/cache.js +48 -0
- package/dist/runtime/cache.test.d.ts +2 -0
- package/dist/runtime/cache.test.js +38 -0
- package/dist/runtime/client.d.ts +25 -0
- package/dist/runtime/client.js +33 -0
- package/dist/runtime/config.d.ts +15 -0
- package/dist/runtime/config.js +371 -0
- package/dist/runtime/errors.d.ts +53 -0
- package/dist/runtime/errors.js +101 -0
- package/dist/runtime/errors.test.d.ts +2 -0
- package/dist/runtime/errors.test.js +40 -0
- package/dist/runtime/events.d.ts +12 -0
- package/dist/runtime/events.js +48 -0
- package/dist/runtime/events.test.d.ts +2 -0
- package/dist/runtime/events.test.js +57 -0
- package/dist/runtime/http.d.ts +15 -0
- package/dist/runtime/http.js +210 -0
- package/dist/runtime/logger.d.ts +9 -0
- package/dist/runtime/logger.js +34 -0
- package/dist/runtime/relations.d.ts +43 -0
- package/dist/runtime/relations.js +54 -0
- package/dist/runtime/retry.d.ts +14 -0
- package/dist/runtime/retry.js +41 -0
- package/dist/runtime/retry.test.d.ts +2 -0
- package/dist/runtime/retry.test.js +46 -0
- package/dist/runtime/token-cache.d.ts +42 -0
- package/dist/runtime/token-cache.js +104 -0
- package/dist/runtime/types.d.ts +191 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/yaml.d.ts +14 -0
- package/dist/runtime/yaml.js +234 -0
- package/dist/runtime/yaml.test.d.ts +2 -0
- package/dist/runtime/yaml.test.js +93 -0
- package/package.json +31 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
export type LogLevel = "debug" | "info" | "warn" | "error" | "none";
|
|
2
|
+
export interface LoggerConfig {
|
|
3
|
+
level?: LogLevel;
|
|
4
|
+
/** Custom sink. Defaults to console. */
|
|
5
|
+
sink?: (level: LogLevel, message: string, data?: unknown) => void;
|
|
6
|
+
}
|
|
7
|
+
export interface RetryConfig {
|
|
8
|
+
/** Maximum number of attempts (including the first). Default: 3. */
|
|
9
|
+
maxAttempts?: number;
|
|
10
|
+
/** Initial delay in ms. Default: 100. */
|
|
11
|
+
initialDelay?: number;
|
|
12
|
+
/** Maximum delay cap in ms. Default: 30_000. */
|
|
13
|
+
maxDelay?: number;
|
|
14
|
+
/** Multiplier applied to delay after each failure. Default: 2. */
|
|
15
|
+
backoffFactor?: number;
|
|
16
|
+
/** HTTP status codes that trigger a retry. Default: [429, 500, 502, 503, 504]. */
|
|
17
|
+
retryOn?: number[];
|
|
18
|
+
}
|
|
19
|
+
export interface CacheConfig {
|
|
20
|
+
/** Enable response caching for eventually-consistent GET/POST-search endpoints. Default: false. */
|
|
21
|
+
enabled?: boolean;
|
|
22
|
+
/** Time-to-live in ms. Default: 30_000. */
|
|
23
|
+
ttl?: number;
|
|
24
|
+
/** Maximum number of cached entries. Default: 500. */
|
|
25
|
+
maxSize?: number;
|
|
26
|
+
}
|
|
27
|
+
/** A cached OAuth2 access token. */
|
|
28
|
+
export interface CachedToken {
|
|
29
|
+
accessToken: string;
|
|
30
|
+
/** Unix timestamp (ms) when the token expires. */
|
|
31
|
+
expiresAt: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Interface for a persistent OAuth2 token store.
|
|
35
|
+
* Implement this to store tokens in Redis, a database, or any custom backend.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const redisStore: TokenStore = {
|
|
40
|
+
* async get(key) {
|
|
41
|
+
* const raw = await redis.get(`token:${key}`);
|
|
42
|
+
* return raw ? JSON.parse(raw) : null;
|
|
43
|
+
* },
|
|
44
|
+
* async set(key, token) {
|
|
45
|
+
* const ttl = Math.floor((token.expiresAt - Date.now()) / 1000);
|
|
46
|
+
* await redis.set(`token:${key}`, JSON.stringify(token), "EX", ttl);
|
|
47
|
+
* },
|
|
48
|
+
* };
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export interface TokenStore {
|
|
52
|
+
get(key: string): Promise<CachedToken | null>;
|
|
53
|
+
set(key: string, token: CachedToken): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
export interface TokenCacheConfig {
|
|
56
|
+
/**
|
|
57
|
+
* Disable the persistent token cache entirely.
|
|
58
|
+
* The token will only be held in memory for the lifetime of the client instance.
|
|
59
|
+
* Default: false.
|
|
60
|
+
*/
|
|
61
|
+
disabled?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Absolute path to the token cache JSON file.
|
|
64
|
+
* Defaults to `{osConfigDir}/camunda-api/token-cache.json`.
|
|
65
|
+
*/
|
|
66
|
+
filePath?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Custom token store. When provided, overrides the default file-based cache.
|
|
69
|
+
* Use this to store tokens in Redis, a database, or any other backend.
|
|
70
|
+
*/
|
|
71
|
+
store?: TokenStore;
|
|
72
|
+
}
|
|
73
|
+
export type AuthConfig = {
|
|
74
|
+
type: "bearer";
|
|
75
|
+
token: string;
|
|
76
|
+
} | {
|
|
77
|
+
type: "oauth2";
|
|
78
|
+
clientId: string;
|
|
79
|
+
clientSecret: string;
|
|
80
|
+
/** Token endpoint URL. */
|
|
81
|
+
tokenUrl: string;
|
|
82
|
+
scope?: string;
|
|
83
|
+
/** OAuth2 audience parameter. Required by Camunda Cloud (default: "zeebe.camunda.io"). */
|
|
84
|
+
audience?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Persistent token cache configuration.
|
|
87
|
+
* Enabled by default — tokens survive process restarts.
|
|
88
|
+
*/
|
|
89
|
+
tokenCache?: TokenCacheConfig;
|
|
90
|
+
} | {
|
|
91
|
+
type: "basic";
|
|
92
|
+
username: string;
|
|
93
|
+
password: string;
|
|
94
|
+
} | {
|
|
95
|
+
type: "none";
|
|
96
|
+
};
|
|
97
|
+
export interface CamundaClientConfig {
|
|
98
|
+
/** Base URL of the Camunda cluster, e.g. http://localhost:8080/v2 */
|
|
99
|
+
baseUrl: string;
|
|
100
|
+
auth: AuthConfig;
|
|
101
|
+
/**
|
|
102
|
+
* Path to a YAML config file. Fields from the file are merged with lower
|
|
103
|
+
* priority than values passed directly to the constructor.
|
|
104
|
+
*/
|
|
105
|
+
configFile?: string;
|
|
106
|
+
retry?: RetryConfig;
|
|
107
|
+
cache?: CacheConfig;
|
|
108
|
+
logger?: LoggerConfig;
|
|
109
|
+
/** Request timeout in ms. Default: 30_000. */
|
|
110
|
+
timeout?: number;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* All fields optional — missing values are resolved from the config file
|
|
114
|
+
* or environment variables. Useful when config is fully provided via env/file.
|
|
115
|
+
*/
|
|
116
|
+
export type CamundaClientInput = {
|
|
117
|
+
baseUrl?: string;
|
|
118
|
+
auth?: AuthConfig;
|
|
119
|
+
configFile?: string;
|
|
120
|
+
retry?: RetryConfig;
|
|
121
|
+
cache?: CacheConfig;
|
|
122
|
+
logger?: LoggerConfig;
|
|
123
|
+
timeout?: number;
|
|
124
|
+
};
|
|
125
|
+
export interface RequestEvent {
|
|
126
|
+
method: string;
|
|
127
|
+
url: string;
|
|
128
|
+
headers: Record<string, string>;
|
|
129
|
+
body?: unknown;
|
|
130
|
+
}
|
|
131
|
+
export interface ResponseEvent {
|
|
132
|
+
method: string;
|
|
133
|
+
url: string;
|
|
134
|
+
status: number;
|
|
135
|
+
durationMs: number;
|
|
136
|
+
cached: boolean;
|
|
137
|
+
}
|
|
138
|
+
export interface RawResponseEvent {
|
|
139
|
+
method: string;
|
|
140
|
+
url: string;
|
|
141
|
+
status: number;
|
|
142
|
+
headers: Record<string, string>;
|
|
143
|
+
body: string;
|
|
144
|
+
requestHeaders: Record<string, string>;
|
|
145
|
+
requestBody?: string;
|
|
146
|
+
}
|
|
147
|
+
export interface ErrorEvent {
|
|
148
|
+
method: string;
|
|
149
|
+
url: string;
|
|
150
|
+
error: Error;
|
|
151
|
+
}
|
|
152
|
+
export interface RetryEvent {
|
|
153
|
+
method: string;
|
|
154
|
+
url: string;
|
|
155
|
+
attempt: number;
|
|
156
|
+
maxAttempts: number;
|
|
157
|
+
delayMs: number;
|
|
158
|
+
reason: string;
|
|
159
|
+
}
|
|
160
|
+
export interface TokenRefreshEvent {
|
|
161
|
+
tokenUrl: string;
|
|
162
|
+
}
|
|
163
|
+
export interface CacheEvent {
|
|
164
|
+
url: string;
|
|
165
|
+
}
|
|
166
|
+
export type ClientEventMap = {
|
|
167
|
+
request: RequestEvent;
|
|
168
|
+
response: ResponseEvent;
|
|
169
|
+
rawResponse: RawResponseEvent;
|
|
170
|
+
error: ErrorEvent;
|
|
171
|
+
retry: RetryEvent;
|
|
172
|
+
tokenRefresh: TokenRefreshEvent;
|
|
173
|
+
cacheHit: CacheEvent;
|
|
174
|
+
cacheMiss: CacheEvent;
|
|
175
|
+
};
|
|
176
|
+
export interface RequestOptions {
|
|
177
|
+
method: string;
|
|
178
|
+
path: string;
|
|
179
|
+
pathParams?: Record<string, string | number>;
|
|
180
|
+
query?: Record<string, unknown>;
|
|
181
|
+
body?: unknown;
|
|
182
|
+
/** Whether this response may be served from cache. */
|
|
183
|
+
cacheable?: boolean;
|
|
184
|
+
/** Override timeout for this request. */
|
|
185
|
+
timeout?: number;
|
|
186
|
+
/** Custom Accept header. Defaults to "application/json". */
|
|
187
|
+
accept?: string;
|
|
188
|
+
/** How to parse the response body. Defaults to "json". */
|
|
189
|
+
responseType?: "json" | "text";
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal YAML parser for Camunda client config files.
|
|
3
|
+
* Handles block mappings, block sequences, inline arrays, all scalar types,
|
|
4
|
+
* quoted strings, and comments. No external dependencies.
|
|
5
|
+
*/
|
|
6
|
+
type Scalar = string | number | boolean | null;
|
|
7
|
+
export interface YamlObject {
|
|
8
|
+
[key: string]: Scalar | YamlObject | YamlArray;
|
|
9
|
+
}
|
|
10
|
+
interface YamlArray extends Array<Scalar | YamlObject | YamlArray> {
|
|
11
|
+
}
|
|
12
|
+
export declare function parseYaml(text: string): YamlObject;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=yaml.d.ts.map
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal YAML parser for Camunda client config files.
|
|
3
|
+
* Handles block mappings, block sequences, inline arrays, all scalar types,
|
|
4
|
+
* quoted strings, and comments. No external dependencies.
|
|
5
|
+
*/
|
|
6
|
+
export function parseYaml(text) {
|
|
7
|
+
const lines = buildLines(text);
|
|
8
|
+
const [value] = parseMapping(lines, 0, 0);
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
// ─── Preprocessing ────────────────────────────────────────────────────────────
|
|
12
|
+
function buildLines(text) {
|
|
13
|
+
const result = [];
|
|
14
|
+
for (const raw of text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n")) {
|
|
15
|
+
let indent = 0;
|
|
16
|
+
for (const ch of raw) {
|
|
17
|
+
if (ch === " ")
|
|
18
|
+
indent++;
|
|
19
|
+
else if (ch === "\t")
|
|
20
|
+
indent += 2;
|
|
21
|
+
else
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
const content = stripInlineComment(raw.trim());
|
|
25
|
+
if (content !== "")
|
|
26
|
+
result.push({ indent, content });
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
function stripInlineComment(s) {
|
|
31
|
+
let inSingle = false;
|
|
32
|
+
let inDouble = false;
|
|
33
|
+
for (let i = 0; i < s.length; i++) {
|
|
34
|
+
const ch = s[i];
|
|
35
|
+
if (ch === "'" && !inDouble) {
|
|
36
|
+
inSingle = !inSingle;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (ch === '"' && !inSingle) {
|
|
40
|
+
inDouble = !inDouble;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (ch === "#" && !inSingle && !inDouble && i > 0 && s[i - 1] === " ") {
|
|
44
|
+
return s.slice(0, i).trimEnd();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return s;
|
|
48
|
+
}
|
|
49
|
+
// ─── Recursive parser ─────────────────────────────────────────────────────────
|
|
50
|
+
/** Parse a mapping block. Returns [object, nextPos]. */
|
|
51
|
+
function parseMapping(lines, startPos, baseIndent) {
|
|
52
|
+
const obj = {};
|
|
53
|
+
let pos = startPos;
|
|
54
|
+
while (pos < lines.length) {
|
|
55
|
+
const line = lines[pos];
|
|
56
|
+
if (!line || line.indent < baseIndent)
|
|
57
|
+
break;
|
|
58
|
+
if (line.indent > baseIndent) {
|
|
59
|
+
// Indented line where we don't expect it — skip safely
|
|
60
|
+
pos++;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const [key, rest] = splitMappingKey(line.content);
|
|
64
|
+
if (key === null) {
|
|
65
|
+
pos++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
pos++;
|
|
69
|
+
if (rest === null) {
|
|
70
|
+
// Value is on following lines
|
|
71
|
+
const next = lines[pos];
|
|
72
|
+
if (!next || next.indent <= baseIndent) {
|
|
73
|
+
obj[key] = null;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const childIndent = next.indent;
|
|
77
|
+
if (next.content.startsWith("- ") || next.content === "-") {
|
|
78
|
+
const [seq, nextPos] = parseSequence(lines, pos, childIndent);
|
|
79
|
+
obj[key] = seq;
|
|
80
|
+
pos = nextPos;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const [map, nextPos] = parseMapping(lines, pos, childIndent);
|
|
84
|
+
obj[key] = map;
|
|
85
|
+
pos = nextPos;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (rest.startsWith("[")) {
|
|
89
|
+
obj[key] = parseInlineArray(rest);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
obj[key] = parseScalar(rest);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return [obj, pos];
|
|
96
|
+
}
|
|
97
|
+
/** Parse a sequence block. Returns [array, nextPos]. */
|
|
98
|
+
function parseSequence(lines, startPos, baseIndent) {
|
|
99
|
+
const arr = [];
|
|
100
|
+
let pos = startPos;
|
|
101
|
+
while (pos < lines.length) {
|
|
102
|
+
const line = lines[pos];
|
|
103
|
+
if (!line || line.indent < baseIndent)
|
|
104
|
+
break;
|
|
105
|
+
if (!line.content.startsWith("- ") && line.content !== "-")
|
|
106
|
+
break;
|
|
107
|
+
const itemText = line.content.slice(1).trimStart();
|
|
108
|
+
pos++;
|
|
109
|
+
if (itemText === "") {
|
|
110
|
+
const next = lines[pos];
|
|
111
|
+
if (!next || next.indent <= baseIndent) {
|
|
112
|
+
arr.push(null);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Could be a nested mapping or sequence
|
|
116
|
+
if (next.content.startsWith("- ") || next.content === "-") {
|
|
117
|
+
const [child, nextPos] = parseSequence(lines, pos, next.indent);
|
|
118
|
+
arr.push(child);
|
|
119
|
+
pos = nextPos;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const [child, nextPos] = parseMapping(lines, pos, next.indent);
|
|
123
|
+
arr.push(child);
|
|
124
|
+
pos = nextPos;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (itemText.startsWith("[")) {
|
|
128
|
+
arr.push(parseInlineArray(itemText));
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
arr.push(parseScalar(itemText));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return [arr, pos];
|
|
135
|
+
}
|
|
136
|
+
function parseInlineArray(text) {
|
|
137
|
+
let inner = text.trim();
|
|
138
|
+
if (inner.startsWith("["))
|
|
139
|
+
inner = inner.slice(1);
|
|
140
|
+
if (inner.endsWith("]"))
|
|
141
|
+
inner = inner.slice(0, -1);
|
|
142
|
+
if (!inner.trim())
|
|
143
|
+
return [];
|
|
144
|
+
return splitByComma(inner).map((item) => parseScalar(item.trim()));
|
|
145
|
+
}
|
|
146
|
+
// ─── Key extraction ───────────────────────────────────────────────────────────
|
|
147
|
+
/**
|
|
148
|
+
* Split `key: value rest` → [key, "value rest"] or [key, null] for blank value.
|
|
149
|
+
* Returns [null, null] if the line is not a mapping entry.
|
|
150
|
+
*/
|
|
151
|
+
function splitMappingKey(content) {
|
|
152
|
+
// Quoted key
|
|
153
|
+
if (content.startsWith('"') || content.startsWith("'")) {
|
|
154
|
+
const q = content[0];
|
|
155
|
+
const close = content.indexOf(q, 1);
|
|
156
|
+
if (close >= 0 && content[close + 1] === ":") {
|
|
157
|
+
const key = content.slice(1, close);
|
|
158
|
+
const after = content.slice(close + 2).trimStart();
|
|
159
|
+
return [key, after || null];
|
|
160
|
+
}
|
|
161
|
+
return [null, null];
|
|
162
|
+
}
|
|
163
|
+
// Plain key — find `:` that is not part of `://`
|
|
164
|
+
for (let i = 0; i < content.length; i++) {
|
|
165
|
+
if (content[i] !== ":")
|
|
166
|
+
continue;
|
|
167
|
+
const next = content[i + 1];
|
|
168
|
+
if (next === "/" || next === ":")
|
|
169
|
+
continue; // skip :// and ::
|
|
170
|
+
if (next !== " " && next !== undefined)
|
|
171
|
+
continue; // must be `: ` or end of string
|
|
172
|
+
const key = content.slice(0, i).trim();
|
|
173
|
+
if (!key)
|
|
174
|
+
continue;
|
|
175
|
+
const after = content.slice(i + 1).trimStart();
|
|
176
|
+
return [key, after || null];
|
|
177
|
+
}
|
|
178
|
+
return [null, null];
|
|
179
|
+
}
|
|
180
|
+
// ─── Scalar parsing ───────────────────────────────────────────────────────────
|
|
181
|
+
function parseScalar(s) {
|
|
182
|
+
const str = s.trim();
|
|
183
|
+
if (str === "" || str === "null" || str === "~")
|
|
184
|
+
return null;
|
|
185
|
+
if (str === "true" || str === "yes" || str === "on")
|
|
186
|
+
return true;
|
|
187
|
+
if (str === "false" || str === "no" || str === "off")
|
|
188
|
+
return false;
|
|
189
|
+
if (str.startsWith('"') && str.endsWith('"') && str.length >= 2) {
|
|
190
|
+
return str
|
|
191
|
+
.slice(1, -1)
|
|
192
|
+
.replace(/\\n/g, "\n")
|
|
193
|
+
.replace(/\\t/g, "\t")
|
|
194
|
+
.replace(/\\"/g, '"')
|
|
195
|
+
.replace(/\\\\/g, "\\");
|
|
196
|
+
}
|
|
197
|
+
if (str.startsWith("'") && str.endsWith("'") && str.length >= 2) {
|
|
198
|
+
return str.slice(1, -1).replace(/''/g, "'");
|
|
199
|
+
}
|
|
200
|
+
if (/^-?\d+$/.test(str))
|
|
201
|
+
return Number.parseInt(str, 10);
|
|
202
|
+
if (/^-?\d*\.?\d+([eE][+-]?\d+)?$/.test(str))
|
|
203
|
+
return Number.parseFloat(str);
|
|
204
|
+
return str;
|
|
205
|
+
}
|
|
206
|
+
function splitByComma(text) {
|
|
207
|
+
const parts = [];
|
|
208
|
+
let depth = 0;
|
|
209
|
+
let current = "";
|
|
210
|
+
let inSingle = false;
|
|
211
|
+
let inDouble = false;
|
|
212
|
+
for (const ch of text) {
|
|
213
|
+
if (ch === "'" && !inDouble)
|
|
214
|
+
inSingle = !inSingle;
|
|
215
|
+
else if (ch === '"' && !inSingle)
|
|
216
|
+
inDouble = !inDouble;
|
|
217
|
+
else if (!inSingle && !inDouble) {
|
|
218
|
+
if (ch === "[" || ch === "{")
|
|
219
|
+
depth++;
|
|
220
|
+
else if (ch === "]" || ch === "}")
|
|
221
|
+
depth--;
|
|
222
|
+
else if (ch === "," && depth === 0) {
|
|
223
|
+
parts.push(current.trim());
|
|
224
|
+
current = "";
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
current += ch;
|
|
229
|
+
}
|
|
230
|
+
if (current.trim())
|
|
231
|
+
parts.push(current.trim());
|
|
232
|
+
return parts;
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=yaml.js.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { parseYaml } from "./yaml.js";
|
|
3
|
+
describe("parseYaml", () => {
|
|
4
|
+
it("parses basic key-value pairs", () => {
|
|
5
|
+
const result = parseYaml("baseUrl: http://localhost:8080/v2\ntimeout: 30000");
|
|
6
|
+
expect(result.baseUrl).toBe("http://localhost:8080/v2");
|
|
7
|
+
expect(result.timeout).toBe(30000);
|
|
8
|
+
});
|
|
9
|
+
it("parses nested mappings", () => {
|
|
10
|
+
const result = parseYaml(`
|
|
11
|
+
auth:
|
|
12
|
+
type: oauth2
|
|
13
|
+
clientId: my-client
|
|
14
|
+
tokenUrl: https://example.com/token
|
|
15
|
+
`);
|
|
16
|
+
expect(result.auth).toEqual({
|
|
17
|
+
type: "oauth2",
|
|
18
|
+
clientId: "my-client",
|
|
19
|
+
tokenUrl: "https://example.com/token",
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
it("parses inline arrays", () => {
|
|
23
|
+
const result = parseYaml("retryOn: [429, 500, 503]");
|
|
24
|
+
expect(result.retryOn).toEqual([429, 500, 503]);
|
|
25
|
+
});
|
|
26
|
+
it("parses block sequences", () => {
|
|
27
|
+
const result = parseYaml(`
|
|
28
|
+
items:
|
|
29
|
+
- 429
|
|
30
|
+
- 500
|
|
31
|
+
- 503
|
|
32
|
+
`);
|
|
33
|
+
expect(result.items).toEqual([429, 500, 503]);
|
|
34
|
+
});
|
|
35
|
+
it("parses booleans", () => {
|
|
36
|
+
const result = parseYaml("enabled: true\ndisabled: false");
|
|
37
|
+
expect(result.enabled).toBe(true);
|
|
38
|
+
expect(result.disabled).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
it("parses null values", () => {
|
|
41
|
+
const result = parseYaml("value: null");
|
|
42
|
+
expect(result.value).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
it("parses double-quoted strings with escapes", () => {
|
|
45
|
+
const result = parseYaml('key: "hello\\nworld"');
|
|
46
|
+
expect(result.key).toBe("hello\nworld");
|
|
47
|
+
});
|
|
48
|
+
it("parses single-quoted strings", () => {
|
|
49
|
+
const result = parseYaml("key: 'it''s fine'");
|
|
50
|
+
expect(result.key).toBe("it's fine");
|
|
51
|
+
});
|
|
52
|
+
it("strips inline comments", () => {
|
|
53
|
+
const result = parseYaml("baseUrl: http://localhost # comment\ntimeout: 5000 # ms");
|
|
54
|
+
expect(result.baseUrl).toBe("http://localhost");
|
|
55
|
+
expect(result.timeout).toBe(5000);
|
|
56
|
+
});
|
|
57
|
+
it("handles URLs with :// correctly (not treated as key: value)", () => {
|
|
58
|
+
const result = parseYaml("tokenUrl: https://login.example.com/oauth/token");
|
|
59
|
+
expect(result.tokenUrl).toBe("https://login.example.com/oauth/token");
|
|
60
|
+
});
|
|
61
|
+
it("parses a realistic config file", () => {
|
|
62
|
+
const yaml = `
|
|
63
|
+
baseUrl: http://localhost:8080/v2
|
|
64
|
+
auth:
|
|
65
|
+
type: oauth2
|
|
66
|
+
clientId: my-client
|
|
67
|
+
clientSecret: my-secret
|
|
68
|
+
tokenUrl: https://auth.example.com/token
|
|
69
|
+
tokenCache:
|
|
70
|
+
disabled: false
|
|
71
|
+
filePath: /tmp/token-cache.json
|
|
72
|
+
retry:
|
|
73
|
+
maxAttempts: 3
|
|
74
|
+
initialDelay: 100
|
|
75
|
+
retryOn: [429, 500, 502, 503, 504]
|
|
76
|
+
cache:
|
|
77
|
+
enabled: true
|
|
78
|
+
ttl: 30000
|
|
79
|
+
logger:
|
|
80
|
+
level: info
|
|
81
|
+
timeout: 10000
|
|
82
|
+
`;
|
|
83
|
+
const result = parseYaml(yaml);
|
|
84
|
+
expect(result.baseUrl).toBe("http://localhost:8080/v2");
|
|
85
|
+
expect(result.auth.type).toBe("oauth2");
|
|
86
|
+
expect(result.auth.clientId).toBe("my-client");
|
|
87
|
+
expect(result.retry.maxAttempts).toBe(3);
|
|
88
|
+
expect(result.retry.retryOn).toEqual([429, 500, 502, 503, 504]);
|
|
89
|
+
expect(result.cache.enabled).toBe(true);
|
|
90
|
+
expect(result.timeout).toBe(10000);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=yaml.test.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bpmnkit/api",
|
|
3
|
+
"version": "0.0.8",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"files": ["dist/**/*.js", "dist/**/*.d.ts"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"generate": "node scripts/generate.mjs",
|
|
17
|
+
"generate:admin": "node scripts/generate.mjs --api admin",
|
|
18
|
+
"build": "node scripts/generate.mjs && node scripts/generate.mjs --api admin && tsc",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"check": "biome check .",
|
|
21
|
+
"test": "vitest run"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {},
|
|
24
|
+
"description": "TypeScript client for the Camunda 8 REST API — 180 typed operations, OAuth2, retries, and caching",
|
|
25
|
+
"keywords": ["camunda", "zeebe", "bpmn", "api", "client", "rest", "typescript"],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/bpmnkit/monorepo"
|
|
30
|
+
}
|
|
31
|
+
}
|