@pellux/goodvibes-daemon-sdk 0.33.37 → 0.33.38
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/dist/api-router.d.ts +20 -0
- package/dist/api-router.d.ts.map +1 -1
- package/dist/api-router.js +20 -0
- package/dist/automation.js +2 -2
- package/dist/context.d.ts +51 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/error-response.d.ts +32 -0
- package/dist/error-response.d.ts.map +1 -1
- package/dist/error-response.js +28 -0
- package/dist/http-policy.d.ts +39 -0
- package/dist/http-policy.d.ts.map +1 -1
- package/dist/http-policy.js +23 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/integration-route-types.d.ts +1 -0
- package/dist/integration-route-types.d.ts.map +1 -1
- package/dist/integration-routes.d.ts.map +1 -1
- package/dist/integration-routes.js +27 -2
- package/dist/knowledge-routes.d.ts.map +1 -1
- package/dist/knowledge-routes.js +125 -18
- package/dist/operator.js +2 -0
- package/dist/pagination.d.ts +110 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +136 -0
- package/dist/route-helpers.d.ts +123 -0
- package/dist/route-helpers.d.ts.map +1 -1
- package/dist/route-helpers.js +112 -1
- package/dist/runtime-automation-routes.d.ts.map +1 -1
- package/dist/runtime-automation-routes.js +58 -3
- package/package.json +3 -3
package/dist/route-helpers.d.ts
CHANGED
|
@@ -1,30 +1,153 @@
|
|
|
1
|
+
/** A plain JSON object (record of string keys to unknown values). */
|
|
1
2
|
export type JsonRecord = Record<string, unknown>;
|
|
3
|
+
/** Alias for `JsonRecord` used for request/response body shapes. */
|
|
2
4
|
export type JsonBody = JsonRecord;
|
|
5
|
+
/** A named parse schema for a daemon route request body. */
|
|
3
6
|
export interface RouteBodySchema<T> {
|
|
7
|
+
/** Identifies which route this schema belongs to (for error messages). */
|
|
4
8
|
readonly routeId: string;
|
|
9
|
+
/** Parse a raw JSON body into `T`, or return an error `Response` on validation failure. */
|
|
5
10
|
readonly parse: (body: JsonRecord) => T | Response;
|
|
6
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Create a typed `RouteBodySchema` from a route id and a parse function.
|
|
14
|
+
*
|
|
15
|
+
* @param routeId - Route identifier for error context.
|
|
16
|
+
* @param parse - Function that validates and transforms a `JsonRecord` to `T`, or returns an error `Response`.
|
|
17
|
+
* @returns A `RouteBodySchema<T>` ready to use in route handlers.
|
|
18
|
+
*/
|
|
7
19
|
export declare function createRouteBodySchema<T>(routeId: string, parse: (body: JsonRecord) => T | Response): RouteBodySchema<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Create a typed registry of route body schemas, inferring the full map type.
|
|
22
|
+
*
|
|
23
|
+
* @param schemas - Map of route ids to `RouteBodySchema` instances.
|
|
24
|
+
* @returns The same map with its literal type preserved.
|
|
25
|
+
*/
|
|
8
26
|
export declare function createRouteBodySchemaRegistry<const TSchemaMap extends Record<string, RouteBodySchema<unknown>>>(schemas: TSchemaMap): TSchemaMap;
|
|
27
|
+
/** Type guard that returns `true` when `value` is a non-null, non-array plain object. */
|
|
9
28
|
export declare function isJsonRecord(value: unknown): value is JsonRecord;
|
|
29
|
+
/**
|
|
30
|
+
* Recursively convert a value to a JSON-safe representation, replacing circular
|
|
31
|
+
* references with `{ $ref: '<json-path>' }` entries.
|
|
32
|
+
*
|
|
33
|
+
* @param value - The value to serialize.
|
|
34
|
+
* @returns A JSON-safe copy of `value`.
|
|
35
|
+
*/
|
|
10
36
|
export declare function toSerializableJson(value: unknown, stack?: Map<object, string>, path?: string): unknown;
|
|
37
|
+
/**
|
|
38
|
+
* Create a JSON `Response` from any value, safely handling circular references.
|
|
39
|
+
*
|
|
40
|
+
* @param body - The value to serialize as the response body.
|
|
41
|
+
* @param init - Optional `ResponseInit` (status, headers, etc.).
|
|
42
|
+
* @returns A `Response` with `Content-Type: application/json`.
|
|
43
|
+
*/
|
|
11
44
|
export declare function serializableJsonResponse(body: unknown, init?: ResponseInit): Response;
|
|
45
|
+
/** Options for bounded integer parsing from query parameters or request bodies. */
|
|
12
46
|
export interface BoundedIntegerOptions {
|
|
47
|
+
/** Default value to use when the input is absent or invalid. */
|
|
13
48
|
readonly fallback: number;
|
|
49
|
+
/** Inclusive lower bound. Defaults to `0`. */
|
|
14
50
|
readonly min?: number | undefined;
|
|
51
|
+
/** Inclusive upper bound. Defaults to `1000`. */
|
|
15
52
|
readonly max?: number | undefined;
|
|
16
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Parse an integer from a raw query-parameter string, clamping to `[min, max]` and
|
|
56
|
+
* falling back to `options.fallback` when the value is absent or non-finite.
|
|
57
|
+
*
|
|
58
|
+
* @param raw - The raw string value (or `null` if the parameter was absent).
|
|
59
|
+
* @param options - Bounds and fallback configuration.
|
|
60
|
+
* @returns A clamped integer within `[min, max]`.
|
|
61
|
+
*/
|
|
17
62
|
export declare function readBoundedInteger(raw: string | null, options: BoundedIntegerOptions): number;
|
|
63
|
+
/**
|
|
64
|
+
* Parse a positive integer (min=1) from a query-parameter string.
|
|
65
|
+
*
|
|
66
|
+
* @param raw - The raw string value (or `null`).
|
|
67
|
+
* @param fallback - Default when absent or invalid.
|
|
68
|
+
* @param max - Upper bound; defaults to `1000`.
|
|
69
|
+
* @returns A clamped integer in `[1, max]`.
|
|
70
|
+
*/
|
|
18
71
|
export declare function readBoundedPositiveInteger(raw: string | null, fallback: number, max?: number): number;
|
|
72
|
+
/**
|
|
73
|
+
* Parse a bounded integer from a parsed JSON body value.
|
|
74
|
+
*
|
|
75
|
+
* @param value - The raw body value (should be `number`).
|
|
76
|
+
* @param fallback - Default when absent or non-finite.
|
|
77
|
+
* @param max - Inclusive upper bound.
|
|
78
|
+
* @param min - Inclusive lower bound; defaults to `1`.
|
|
79
|
+
* @returns A clamped integer in `[min, max]`.
|
|
80
|
+
*/
|
|
19
81
|
export declare function readBoundedBodyInteger(value: unknown, fallback: number, max: number, min?: number): number;
|
|
82
|
+
/**
|
|
83
|
+
* Parse an optional bounded integer from a query-parameter string.
|
|
84
|
+
* Returns `undefined` when the parameter is absent or non-finite.
|
|
85
|
+
*
|
|
86
|
+
* @param raw - The raw string value (or `null`).
|
|
87
|
+
* @param min - Inclusive lower bound.
|
|
88
|
+
* @param max - Inclusive upper bound.
|
|
89
|
+
* @returns A clamped integer or `undefined`.
|
|
90
|
+
*/
|
|
20
91
|
export declare function readOptionalBoundedInteger(raw: string | null, min: number, max: number): number | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Read a non-empty trimmed string from a JSON body field, returning `undefined` if absent or blank.
|
|
94
|
+
*
|
|
95
|
+
* @param body - The parsed request body.
|
|
96
|
+
* @param key - The field key to read.
|
|
97
|
+
* @returns The trimmed string, or `undefined`.
|
|
98
|
+
*/
|
|
21
99
|
export declare function readOptionalStringField(body: JsonRecord, key: string): string | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Read an array of non-empty trimmed strings from a JSON body field.
|
|
102
|
+
* Entries that are not strings or are blank are skipped. Returns `undefined` when
|
|
103
|
+
* the field is absent, not an array, or all entries were invalid.
|
|
104
|
+
*
|
|
105
|
+
* @param body - The parsed request body.
|
|
106
|
+
* @param key - The field key to read.
|
|
107
|
+
* @param max - Maximum number of entries to include; defaults to `128`.
|
|
108
|
+
* @returns A non-empty string array, or `undefined`.
|
|
109
|
+
*/
|
|
22
110
|
export declare function readStringArrayField(body: JsonRecord, key: string, max?: number): string[] | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Test whether a single granted scope string covers the required scope.
|
|
113
|
+
* Supports exact match, wildcard `'*'`, and prefix wildcard (e.g. `'sessions:*'`).
|
|
114
|
+
*
|
|
115
|
+
* @param granted - A scope string held by the caller.
|
|
116
|
+
* @param required - The scope the operation requires.
|
|
117
|
+
* @returns `true` if `granted` covers `required`.
|
|
118
|
+
*/
|
|
23
119
|
export declare function scopeMatches(granted: string, required: string): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Return `true` if the caller holds at least one of the required scopes.
|
|
122
|
+
*
|
|
123
|
+
* @param grantedScopes - Scopes held by the caller (or `undefined` for no scopes).
|
|
124
|
+
* @param requiredScopes - Scopes to check against.
|
|
125
|
+
*/
|
|
24
126
|
export declare function hasAnyScope(grantedScopes: readonly string[] | undefined, requiredScopes: readonly string[]): boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Return the subset of `requiredScopes` not covered by `grantedScopes`.
|
|
129
|
+
*
|
|
130
|
+
* @param grantedScopes - Scopes held by the caller (or `undefined` for no scopes).
|
|
131
|
+
* @param requiredScopes - The full set of required scopes.
|
|
132
|
+
* @returns An array of scope strings that are missing; empty if all are satisfied.
|
|
133
|
+
*/
|
|
25
134
|
export declare function missingScopes(grantedScopes: readonly string[] | undefined, requiredScopes: readonly string[]): string[];
|
|
135
|
+
/** The set of lifecycle action strings accepted by channel lifecycle endpoints. */
|
|
26
136
|
export type ChannelLifecycleAction = 'inspect' | 'setup' | 'retest' | 'connect' | 'disconnect' | 'start' | 'stop' | 'login' | 'logout' | 'wait_login';
|
|
137
|
+
/** The conversation kind values accepted by channel conversation endpoints. */
|
|
27
138
|
export type ChannelConversationKind = 'direct' | 'group' | 'channel' | 'thread' | 'service';
|
|
139
|
+
/**
|
|
140
|
+
* Validate and narrow an unknown value to `ChannelLifecycleAction`.
|
|
141
|
+
*
|
|
142
|
+
* @param value - The raw input (typically from a URL path segment or body field).
|
|
143
|
+
* @returns The typed action string, or `null` if the value is not a valid action.
|
|
144
|
+
*/
|
|
28
145
|
export declare function readChannelLifecycleAction(value: unknown): ChannelLifecycleAction | null;
|
|
146
|
+
/**
|
|
147
|
+
* Validate and narrow an unknown value to `ChannelConversationKind`.
|
|
148
|
+
*
|
|
149
|
+
* @param value - The raw input (typically from a URL path segment or body field).
|
|
150
|
+
* @returns The typed kind string, or `null` if the value is not a valid kind.
|
|
151
|
+
*/
|
|
29
152
|
export declare function readChannelConversationKind(value: unknown): ChannelConversationKind | null;
|
|
30
153
|
//# sourceMappingURL=route-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../src/route-helpers.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACjD,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC;AAElC,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,CAAC,GAAG,QAAQ,CAAC;CACpD;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,CAAC,GAAG,QAAQ,GACxC,eAAe,CAAC,CAAC,CAAC,CAEpB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,EACjE,OAAO,EAAE,UAAU,GAAG,UAAU,CAEjC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,sBAA4B,EAAE,IAAI,SAAM,GAAG,OAAO,CAiBzG;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAErF;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAS7F;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAQ,GAAG,MAAM,CAEpG;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,SAAI,GAAG,MAAM,CAGrG;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3G;AAMD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzF;
|
|
1
|
+
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../src/route-helpers.ts"],"names":[],"mappings":"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"}
|
package/dist/route-helpers.js
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a typed `RouteBodySchema` from a route id and a parse function.
|
|
3
|
+
*
|
|
4
|
+
* @param routeId - Route identifier for error context.
|
|
5
|
+
* @param parse - Function that validates and transforms a `JsonRecord` to `T`, or returns an error `Response`.
|
|
6
|
+
* @returns A `RouteBodySchema<T>` ready to use in route handlers.
|
|
7
|
+
*/
|
|
1
8
|
export function createRouteBodySchema(routeId, parse) {
|
|
2
9
|
return { routeId, parse };
|
|
3
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a typed registry of route body schemas, inferring the full map type.
|
|
13
|
+
*
|
|
14
|
+
* @param schemas - Map of route ids to `RouteBodySchema` instances.
|
|
15
|
+
* @returns The same map with its literal type preserved.
|
|
16
|
+
*/
|
|
4
17
|
export function createRouteBodySchemaRegistry(schemas) {
|
|
5
18
|
return schemas;
|
|
6
19
|
}
|
|
20
|
+
/** Type guard that returns `true` when `value` is a non-null, non-array plain object. */
|
|
7
21
|
export function isJsonRecord(value) {
|
|
8
22
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Recursively convert a value to a JSON-safe representation, replacing circular
|
|
26
|
+
* references with `{ $ref: '<json-path>' }` entries.
|
|
27
|
+
*
|
|
28
|
+
* @param value - The value to serialize.
|
|
29
|
+
* @returns A JSON-safe copy of `value`.
|
|
30
|
+
*/
|
|
10
31
|
export function toSerializableJson(value, stack = new Map(), path = '$') {
|
|
11
32
|
if (!value || typeof value !== 'object')
|
|
12
33
|
return value;
|
|
@@ -24,9 +45,24 @@ export function toSerializableJson(value, stack = new Map(), path = '$') {
|
|
|
24
45
|
toSerializableJson(entry, next, `${path}.${key}`),
|
|
25
46
|
]));
|
|
26
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Create a JSON `Response` from any value, safely handling circular references.
|
|
50
|
+
*
|
|
51
|
+
* @param body - The value to serialize as the response body.
|
|
52
|
+
* @param init - Optional `ResponseInit` (status, headers, etc.).
|
|
53
|
+
* @returns A `Response` with `Content-Type: application/json`.
|
|
54
|
+
*/
|
|
27
55
|
export function serializableJsonResponse(body, init) {
|
|
28
56
|
return Response.json(toSerializableJson(body), init);
|
|
29
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Parse an integer from a raw query-parameter string, clamping to `[min, max]` and
|
|
60
|
+
* falling back to `options.fallback` when the value is absent or non-finite.
|
|
61
|
+
*
|
|
62
|
+
* @param raw - The raw string value (or `null` if the parameter was absent).
|
|
63
|
+
* @param options - Bounds and fallback configuration.
|
|
64
|
+
* @returns A clamped integer within `[min, max]`.
|
|
65
|
+
*/
|
|
30
66
|
export function readBoundedInteger(raw, options) {
|
|
31
67
|
const min = options.min ?? 0;
|
|
32
68
|
const max = options.max ?? 1_000;
|
|
@@ -39,14 +75,40 @@ export function readBoundedInteger(raw, options) {
|
|
|
39
75
|
return clampInteger(options.fallback, min, max);
|
|
40
76
|
return clampInteger(value, min, max);
|
|
41
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Parse a positive integer (min=1) from a query-parameter string.
|
|
80
|
+
*
|
|
81
|
+
* @param raw - The raw string value (or `null`).
|
|
82
|
+
* @param fallback - Default when absent or invalid.
|
|
83
|
+
* @param max - Upper bound; defaults to `1000`.
|
|
84
|
+
* @returns A clamped integer in `[1, max]`.
|
|
85
|
+
*/
|
|
42
86
|
export function readBoundedPositiveInteger(raw, fallback, max = 1_000) {
|
|
43
87
|
return readBoundedInteger(raw, { fallback, min: 1, max });
|
|
44
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse a bounded integer from a parsed JSON body value.
|
|
91
|
+
*
|
|
92
|
+
* @param value - The raw body value (should be `number`).
|
|
93
|
+
* @param fallback - Default when absent or non-finite.
|
|
94
|
+
* @param max - Inclusive upper bound.
|
|
95
|
+
* @param min - Inclusive lower bound; defaults to `1`.
|
|
96
|
+
* @returns A clamped integer in `[min, max]`.
|
|
97
|
+
*/
|
|
45
98
|
export function readBoundedBodyInteger(value, fallback, max, min = 1) {
|
|
46
99
|
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
47
100
|
return clampInteger(fallback, min, max);
|
|
48
101
|
return clampInteger(value, min, max);
|
|
49
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Parse an optional bounded integer from a query-parameter string.
|
|
105
|
+
* Returns `undefined` when the parameter is absent or non-finite.
|
|
106
|
+
*
|
|
107
|
+
* @param raw - The raw string value (or `null`).
|
|
108
|
+
* @param min - Inclusive lower bound.
|
|
109
|
+
* @param max - Inclusive upper bound.
|
|
110
|
+
* @returns A clamped integer or `undefined`.
|
|
111
|
+
*/
|
|
50
112
|
export function readOptionalBoundedInteger(raw, min, max) {
|
|
51
113
|
if (raw === null || raw.trim() === '')
|
|
52
114
|
return undefined;
|
|
@@ -58,11 +120,27 @@ export function readOptionalBoundedInteger(raw, min, max) {
|
|
|
58
120
|
function clampInteger(value, min, max) {
|
|
59
121
|
return Math.min(max, Math.max(min, Math.trunc(value)));
|
|
60
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Read a non-empty trimmed string from a JSON body field, returning `undefined` if absent or blank.
|
|
125
|
+
*
|
|
126
|
+
* @param body - The parsed request body.
|
|
127
|
+
* @param key - The field key to read.
|
|
128
|
+
* @returns The trimmed string, or `undefined`.
|
|
129
|
+
*/
|
|
61
130
|
export function readOptionalStringField(body, key) {
|
|
62
131
|
const value = body[key];
|
|
63
132
|
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
64
133
|
}
|
|
65
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Read an array of non-empty trimmed strings from a JSON body field.
|
|
136
|
+
* Entries that are not strings or are blank are skipped. Returns `undefined` when
|
|
137
|
+
* the field is absent, not an array, or all entries were invalid.
|
|
138
|
+
*
|
|
139
|
+
* @param body - The parsed request body.
|
|
140
|
+
* @param key - The field key to read.
|
|
141
|
+
* @param max - Maximum number of entries to include; defaults to `128`.
|
|
142
|
+
* @returns A non-empty string array, or `undefined`.
|
|
143
|
+
*/
|
|
66
144
|
export function readStringArrayField(body, key, max = 128) {
|
|
67
145
|
const value = body[key];
|
|
68
146
|
if (!Array.isArray(value))
|
|
@@ -78,6 +156,14 @@ export function readStringArrayField(body, key, max = 128) {
|
|
|
78
156
|
}
|
|
79
157
|
return output.length > 0 ? output : undefined;
|
|
80
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Test whether a single granted scope string covers the required scope.
|
|
161
|
+
* Supports exact match, wildcard `'*'`, and prefix wildcard (e.g. `'sessions:*'`).
|
|
162
|
+
*
|
|
163
|
+
* @param granted - A scope string held by the caller.
|
|
164
|
+
* @param required - The scope the operation requires.
|
|
165
|
+
* @returns `true` if `granted` covers `required`.
|
|
166
|
+
*/
|
|
81
167
|
export function scopeMatches(granted, required) {
|
|
82
168
|
if (granted === '*' || granted === required)
|
|
83
169
|
return true;
|
|
@@ -86,14 +172,33 @@ export function scopeMatches(granted, required) {
|
|
|
86
172
|
}
|
|
87
173
|
return false;
|
|
88
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Return `true` if the caller holds at least one of the required scopes.
|
|
177
|
+
*
|
|
178
|
+
* @param grantedScopes - Scopes held by the caller (or `undefined` for no scopes).
|
|
179
|
+
* @param requiredScopes - Scopes to check against.
|
|
180
|
+
*/
|
|
89
181
|
export function hasAnyScope(grantedScopes, requiredScopes) {
|
|
90
182
|
const granted = grantedScopes ?? [];
|
|
91
183
|
return requiredScopes.some((required) => granted.some((entry) => scopeMatches(entry, required)));
|
|
92
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Return the subset of `requiredScopes` not covered by `grantedScopes`.
|
|
187
|
+
*
|
|
188
|
+
* @param grantedScopes - Scopes held by the caller (or `undefined` for no scopes).
|
|
189
|
+
* @param requiredScopes - The full set of required scopes.
|
|
190
|
+
* @returns An array of scope strings that are missing; empty if all are satisfied.
|
|
191
|
+
*/
|
|
93
192
|
export function missingScopes(grantedScopes, requiredScopes) {
|
|
94
193
|
const granted = grantedScopes ?? [];
|
|
95
194
|
return requiredScopes.filter((required) => !granted.some((entry) => scopeMatches(entry, required)));
|
|
96
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Validate and narrow an unknown value to `ChannelLifecycleAction`.
|
|
198
|
+
*
|
|
199
|
+
* @param value - The raw input (typically from a URL path segment or body field).
|
|
200
|
+
* @returns The typed action string, or `null` if the value is not a valid action.
|
|
201
|
+
*/
|
|
97
202
|
export function readChannelLifecycleAction(value) {
|
|
98
203
|
return value === 'inspect'
|
|
99
204
|
|| value === 'setup'
|
|
@@ -108,6 +213,12 @@ export function readChannelLifecycleAction(value) {
|
|
|
108
213
|
? value
|
|
109
214
|
: null;
|
|
110
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Validate and narrow an unknown value to `ChannelConversationKind`.
|
|
218
|
+
*
|
|
219
|
+
* @param value - The raw input (typically from a URL path segment or body field).
|
|
220
|
+
* @returns The typed kind string, or `null` if the value is not a valid kind.
|
|
221
|
+
*/
|
|
111
222
|
export function readChannelConversationKind(value) {
|
|
112
223
|
return value === 'direct' || value === 'group' || value === 'channel' || value === 'thread' || value === 'service'
|
|
113
224
|
? value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-automation-routes.d.ts","sourceRoot":"","sources":["../src/runtime-automation-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-automation-routes.d.ts","sourceRoot":"","sources":["../src/runtime-automation-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AA4B1E,wBAAgB,0CAA0C,CACxD,OAAO,EAAE,yBAAyB,GACjC,oCAAoC,CAoBtC"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { withAdmin } from './auth-helpers.js';
|
|
2
2
|
import { jsonErrorResponse } from './error-response.js';
|
|
3
|
-
import {
|
|
3
|
+
import { hasPaginationParams, paginateItems } from './pagination.js';
|
|
4
|
+
import { createRouteBodySchema, createRouteBodySchemaRegistry, readBoundedBodyInteger, readBoundedPositiveInteger, readOptionalStringField, readStringArrayField, } from './route-helpers.js';
|
|
5
|
+
const DEFAULT_AUTOMATION_LIST_LIMIT = 100;
|
|
6
|
+
const MAX_AUTOMATION_LIST_LIMIT = 500;
|
|
4
7
|
export function createDaemonRuntimeAutomationRouteHandlers(context) {
|
|
5
8
|
return {
|
|
6
|
-
getAutomationJobs: () =>
|
|
9
|
+
getAutomationJobs: (url) => handleGetAutomationJobs(context, url),
|
|
7
10
|
postAutomationJob: async (request) => withAdmin(context, request, () => handlePostSchedule(context, request)),
|
|
8
|
-
getAutomationRuns: () =>
|
|
11
|
+
getAutomationRuns: (url) => handleGetAutomationRuns(context, url),
|
|
9
12
|
getAutomationRun: (runId) => handleGetAutomationRun(context, runId),
|
|
10
13
|
getAutomationHeartbeat: () => Response.json({ pending: [] }),
|
|
11
14
|
postAutomationHeartbeat: async (request) => withAdmin(context, request, () => handlePostAutomationHeartbeat(context, request)),
|
|
@@ -200,3 +203,55 @@ function findAutomationJob(context, id) {
|
|
|
200
203
|
// exact-match only — prefix match was non-deterministic when multiple ids share a prefix.
|
|
201
204
|
return context.automationManager.listJobs().find((entry) => entry.id === id);
|
|
202
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Handle GET /api/automation/jobs.
|
|
208
|
+
*
|
|
209
|
+
* Without pagination params (`?limit=` / `?cursor=`): returns `{ jobs: [...] }` (backward compat).
|
|
210
|
+
* With pagination params: returns `PaginatedResponse<AutomationJobLike>` as `{ items, nextCursor, hasMore }`.
|
|
211
|
+
*
|
|
212
|
+
* ### Deletion recovery
|
|
213
|
+
* `AutomationJobLike` exposes only `{ id: string }` at the SDK boundary — there is
|
|
214
|
+
* no stable timestamp field on jobs. Insertion-point recovery on mid-walk deletion
|
|
215
|
+
* is therefore **not available** for this endpoint; if the cursor item is deleted,
|
|
216
|
+
* the walk restarts from index 0. If a timestamp is added to `AutomationJobLike`
|
|
217
|
+
* in the future, thread it as `getCreatedAt` here.
|
|
218
|
+
*/
|
|
219
|
+
function handleGetAutomationJobs(context, url) {
|
|
220
|
+
const jobs = context.automationManager.listJobs();
|
|
221
|
+
if (!url || !hasPaginationParams(url)) {
|
|
222
|
+
return Response.json({ jobs });
|
|
223
|
+
}
|
|
224
|
+
const limit = readBoundedPositiveInteger(url.searchParams.get('limit'), DEFAULT_AUTOMATION_LIST_LIMIT, MAX_AUTOMATION_LIST_LIMIT);
|
|
225
|
+
const rawCursor = url.searchParams.get('cursor');
|
|
226
|
+
const result = paginateItems(jobs, limit, rawCursor, (j) => j.id);
|
|
227
|
+
if ('error' in result) {
|
|
228
|
+
return jsonErrorResponse({ error: result.error }, { status: 400 });
|
|
229
|
+
}
|
|
230
|
+
return Response.json(result);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Handle GET /api/automation/runs.
|
|
234
|
+
*
|
|
235
|
+
* Without pagination params (`?limit=` / `?cursor=`): returns `{ runs: [...] }` (backward compat).
|
|
236
|
+
* With pagination params: returns `PaginatedResponse<AutomationRunLike>` as `{ items, nextCursor, hasMore }`.
|
|
237
|
+
*
|
|
238
|
+
* ### Deletion recovery
|
|
239
|
+
* `AutomationRunLike` carries a required `queuedAt: number` field which serves as
|
|
240
|
+
* the stable creation-time timestamp. Insertion-point recovery on mid-walk
|
|
241
|
+
* deletion is **active** for this endpoint via `getCreatedAt: (r) => r.queuedAt`.
|
|
242
|
+
* Runs are listed in descending `queuedAt` order (newest first), so
|
|
243
|
+
* `descending: true` is passed to `paginateItems` for correct recovery.
|
|
244
|
+
*/
|
|
245
|
+
function handleGetAutomationRuns(context, url) {
|
|
246
|
+
const runs = context.automationManager.listRuns();
|
|
247
|
+
if (!url || !hasPaginationParams(url)) {
|
|
248
|
+
return Response.json({ runs });
|
|
249
|
+
}
|
|
250
|
+
const limit = readBoundedPositiveInteger(url.searchParams.get('limit'), DEFAULT_AUTOMATION_LIST_LIMIT, MAX_AUTOMATION_LIST_LIMIT);
|
|
251
|
+
const rawCursor = url.searchParams.get('cursor');
|
|
252
|
+
const result = paginateItems(runs, limit, rawCursor, (r) => r.id, (r) => r.queuedAt, { descending: true });
|
|
253
|
+
if ('error' in result) {
|
|
254
|
+
return jsonErrorResponse({ error: result.error }, { status: 400 });
|
|
255
|
+
}
|
|
256
|
+
return Response.json(result);
|
|
257
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-daemon-sdk",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.38",
|
|
4
4
|
"engines": {
|
|
5
5
|
"bun": "1.3.10",
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -157,8 +157,8 @@
|
|
|
157
157
|
"control-plane"
|
|
158
158
|
],
|
|
159
159
|
"dependencies": {
|
|
160
|
-
"@pellux/goodvibes-contracts": "0.33.
|
|
161
|
-
"@pellux/goodvibes-errors": "0.33.
|
|
160
|
+
"@pellux/goodvibes-contracts": "0.33.38",
|
|
161
|
+
"@pellux/goodvibes-errors": "0.33.38"
|
|
162
162
|
},
|
|
163
163
|
"publishConfig": {
|
|
164
164
|
"access": "public"
|