@karmaniverous/jeeves-server-core 0.3.0 → 0.4.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 +11 -3
- package/dist/src/endpoints.js +15 -2
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/schema.d.ts +1 -0
- package/dist/src/schema.js +22 -0
- package/dist/src/schema.publicUrl.test.d.ts +1 -0
- package/dist/src/schema.test.d.ts +1 -0
- package/dist/src/types.d.ts +5 -0
- package/dist/src/urlKey.d.ts +24 -0
- package/dist/src/urlKey.js +43 -0
- package/dist/src/urlKey.test.d.ts +1 -0
- package/package.json +11 -9
package/README.md
CHANGED
|
@@ -14,26 +14,34 @@ Shared workspace package providing cryptographic utilities and API types consume
|
|
|
14
14
|
| `computeDeepShareKey(seed, path, params)` | HMAC-SHA256 key for deep directory shares with depth/dirs/stack/expiry |
|
|
15
15
|
| `timingSafeEqual(a, b)` | Constant-time string comparison to prevent timing attacks |
|
|
16
16
|
|
|
17
|
+
### URL Key Parameter
|
|
18
|
+
|
|
19
|
+
| Export | Description |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `URL_KEY_PARAM` | `'k'`: the query parameter every generated URL carries its auth key in |
|
|
22
|
+
| `LEGACY_URL_KEY_PARAM` | `'key'`: the old name, still accepted everywhere |
|
|
23
|
+
| `getUrlKey(query)` | Read the auth key from a parsed query object or `URLSearchParams`: `k` wins when both names are present; empty values count as absent; the first of repeated values is used |
|
|
24
|
+
|
|
17
25
|
### Config Schema
|
|
18
26
|
|
|
19
27
|
| Export | Description |
|
|
20
28
|
| --- | --- |
|
|
21
29
|
| `loggingConfigSchema` | Zod schema for `logging` config block (`level`, `file`, both optional) |
|
|
22
30
|
| `LoggingConfig` | Inferred TypeScript type from `loggingConfigSchema` |
|
|
23
|
-
| `jeevesConfigSchema` | Full server config Zod schema (includes `logging`, `oauth`, all other fields) |
|
|
31
|
+
| `jeevesConfigSchema` | Full server config Zod schema (includes `logging`, `oauth`, `publicUrl`, `trustProxyHeaders` and all other fields; requires `publicUrl` or `trustProxyHeaders: true` when email, Google or OAuth login is configured) |
|
|
24
32
|
|
|
25
33
|
### Endpoint Catalog
|
|
26
34
|
|
|
27
35
|
| Export | Description |
|
|
28
36
|
| --- | --- |
|
|
29
37
|
| `EndpointEntry` | Interface describing a single API operation (method, path, description, auth flags) |
|
|
30
|
-
| `serverEndpoints` | Complete declarative catalog of all jeeves-server API endpoints (
|
|
38
|
+
| `serverEndpoints` | Complete declarative catalog of all jeeves-server API endpoints (39 entries) |
|
|
31
39
|
|
|
32
40
|
### API Types
|
|
33
41
|
|
|
34
42
|
| Type | Description |
|
|
35
43
|
| --- | --- |
|
|
36
|
-
| `ShareRequest` / `ShareResponse` | `POST /api/share` payloads |
|
|
44
|
+
| `ShareRequest` / `ShareResponse` | `POST /api/share` payloads (`ShareResponse.isDirectory`, optional: whether the shared path is an existing directory; sent by servers from 3.15.0) |
|
|
37
45
|
| `ShareForRequest` / `ShareForResponse` | `POST /api/util/share-for` payloads (audience-based sharing) |
|
|
38
46
|
| `AuthStatusResponse` | `GET /api/auth/status` response |
|
|
39
47
|
| `RotateKeyResponse` | `POST /api/rotate-key` response |
|
package/dist/src/endpoints.js
CHANGED
|
@@ -19,6 +19,12 @@ const serverEndpoints = {
|
|
|
19
19
|
description: 'Server health: name, version, uptime, status, health details.',
|
|
20
20
|
unauthenticated: true,
|
|
21
21
|
},
|
|
22
|
+
health: {
|
|
23
|
+
method: 'GET',
|
|
24
|
+
path: '/health',
|
|
25
|
+
description: 'Liveness check: returns { ok: true }, no downstream checks.',
|
|
26
|
+
unauthenticated: true,
|
|
27
|
+
},
|
|
22
28
|
config: {
|
|
23
29
|
method: 'GET',
|
|
24
30
|
path: '/config',
|
|
@@ -122,7 +128,7 @@ const serverEndpoints = {
|
|
|
122
128
|
share: {
|
|
123
129
|
method: 'POST',
|
|
124
130
|
path: '/api/share',
|
|
125
|
-
description: 'Generate HMAC-signed share link for a path.',
|
|
131
|
+
description: 'Generate HMAC-signed share link for a path; the response reports whether the path is a directory (isDirectory).',
|
|
126
132
|
insiderOnly: true,
|
|
127
133
|
},
|
|
128
134
|
'share-for': {
|
|
@@ -148,6 +154,12 @@ const serverEndpoints = {
|
|
|
148
154
|
path: '/api/link-info/*',
|
|
149
155
|
description: 'Query available link types for a path (page, raw, PDF, DOCX, etc.).',
|
|
150
156
|
},
|
|
157
|
+
'resolve-path': {
|
|
158
|
+
method: 'GET',
|
|
159
|
+
path: '/api/resolve-path',
|
|
160
|
+
description: 'Map an absolute filesystem path to its browse path and URLs (?fsPath=).',
|
|
161
|
+
insiderOnly: true,
|
|
162
|
+
},
|
|
151
163
|
'rotate-key': {
|
|
152
164
|
method: 'POST',
|
|
153
165
|
path: '/api/rotate-key',
|
|
@@ -163,7 +175,8 @@ const serverEndpoints = {
|
|
|
163
175
|
events: {
|
|
164
176
|
method: 'GET',
|
|
165
177
|
path: '/api/events',
|
|
166
|
-
description: 'Query recent event log entries (limit capped at 100).',
|
|
178
|
+
description: 'Query recent event log entries (insiders with no scopes configured; limit capped at 100).',
|
|
179
|
+
insiderOnly: true,
|
|
167
180
|
},
|
|
168
181
|
// --- Search ---
|
|
169
182
|
search: {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -7,3 +7,4 @@ export { computeDeepShareKey, computeInsiderKey, computeOutsiderKeyWithExpiry, c
|
|
|
7
7
|
export { type EndpointEntry, serverEndpoints } from './endpoints.js';
|
|
8
8
|
export { type AuthMode, authModeSchema, authSchema, type Branding, brandingSchema, DEFAULT_BRANDING, DEPRECATED_CONFIG_PROPS, emailAuthSchema, eventConfigSchema, googleAuthSchema, insiderEntrySchema, isScopeName, type JeevesConfig, jeevesConfigSchema, keyEntrySchema, type LoggingConfig, loggingConfigSchema, oauthProviderSchema, oauthSchema, scopesObjectSchema, scopesSchema, themeOverridesSchema, } from './schema.js';
|
|
9
9
|
export type { AuthStatusResponse, DriveEntry, ExportCacheClearResponse, ExportLink, FileMutationAction, LinkInfoResponse, OAuthStartRequest, OAuthStartResponse, RotateKeyResponse, ShareForRequest, ShareForResponse, ShareRequest, ShareResponse, } from './types.js';
|
|
10
|
+
export { getUrlKey, LEGACY_URL_KEY_PARAM, URL_KEY_PARAM } from './urlKey.js';
|
package/dist/src/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { computeDeepShareKey, computeInsiderKey, computeOutsiderKeyWithExpiry, computePathKey, timingSafeEqual } from './crypto.js';
|
|
2
2
|
export { serverEndpoints } from './endpoints.js';
|
|
3
3
|
export { DEFAULT_BRANDING, DEPRECATED_CONFIG_PROPS, authModeSchema, authSchema, brandingSchema, emailAuthSchema, eventConfigSchema, googleAuthSchema, insiderEntrySchema, isScopeName, jeevesConfigSchema, keyEntrySchema, loggingConfigSchema, oauthProviderSchema, oauthSchema, scopesObjectSchema, scopesSchema, themeOverridesSchema } from './schema.js';
|
|
4
|
+
export { LEGACY_URL_KEY_PARAM, URL_KEY_PARAM, getUrlKey } from './urlKey.js';
|
package/dist/src/schema.d.ts
CHANGED
|
@@ -212,6 +212,7 @@ export declare const jeevesConfigSchema: z.ZodObject<{
|
|
|
212
212
|
eventQueue: z.ZodOptional<z.ZodString>;
|
|
213
213
|
eventQueueConcurrency: z.ZodDefault<z.ZodNumber>;
|
|
214
214
|
publicUrl: z.ZodOptional<z.ZodURL>;
|
|
215
|
+
trustProxyHeaders: z.ZodDefault<z.ZodBoolean>;
|
|
215
216
|
}, z.core.$strip>;
|
|
216
217
|
/** Inferred config type */
|
|
217
218
|
export type JeevesConfig = z.infer<typeof jeevesConfigSchema>;
|
package/dist/src/schema.js
CHANGED
|
@@ -239,6 +239,12 @@ const jeevesConfigSchema = z
|
|
|
239
239
|
eventQueueConcurrency: z.number().int().positive().default(3),
|
|
240
240
|
/** Public base URL (e.g. https://jeeves.johngalt.id). When set, API responses include full public URLs. */
|
|
241
241
|
publicUrl: z.url().optional(),
|
|
242
|
+
/**
|
|
243
|
+
* Trust `X-Forwarded-Proto` / `X-Forwarded-Host` / `Host` to build the
|
|
244
|
+
* public origin when `publicUrl` is unset. Enable only behind a proxy
|
|
245
|
+
* that sets or strips these headers itself. Default: false.
|
|
246
|
+
*/
|
|
247
|
+
trustProxyHeaders: z.boolean().default(false),
|
|
242
248
|
})
|
|
243
249
|
.superRefine((config, ctx) => {
|
|
244
250
|
// Google auth mode requires google config + sessionSecret
|
|
@@ -275,6 +281,22 @@ const jeevesConfigSchema = z
|
|
|
275
281
|
});
|
|
276
282
|
}
|
|
277
283
|
}
|
|
284
|
+
// Login links and OAuth redirects are absolute URLs on a trusted public
|
|
285
|
+
// origin: publicUrl, or forwarding headers only when explicitly trusted.
|
|
286
|
+
const loginFlows = [
|
|
287
|
+
config.auth.modes.includes('email') ? 'email login' : null,
|
|
288
|
+
config.auth.modes.includes('google') ? 'Google login' : null,
|
|
289
|
+
config.oauth ? 'OAuth (oauth)' : null,
|
|
290
|
+
].filter((flow) => flow !== null);
|
|
291
|
+
if (loginFlows.length > 0 &&
|
|
292
|
+
!config.publicUrl &&
|
|
293
|
+
!config.trustProxyHeaders) {
|
|
294
|
+
ctx.addIssue({
|
|
295
|
+
code: 'custom',
|
|
296
|
+
message: `publicUrl is required when ${loginFlows.join(', ')} is configured (or set trustProxyHeaders: true behind a proxy that sets X-Forwarded-* headers)`,
|
|
297
|
+
path: ['publicUrl'],
|
|
298
|
+
});
|
|
299
|
+
}
|
|
278
300
|
// Keys auth mode requires at least one key
|
|
279
301
|
if (config.auth.modes.includes('keys') &&
|
|
280
302
|
Object.keys(config.keys).length === 0) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ export interface ShareResponse {
|
|
|
17
17
|
exp: string | null;
|
|
18
18
|
depth?: number;
|
|
19
19
|
dirs?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the shared path is an existing directory. Sent by servers from
|
|
22
|
+
* 3.15.0; absent from older servers.
|
|
23
|
+
*/
|
|
24
|
+
isDirectory?: boolean;
|
|
20
25
|
}
|
|
21
26
|
/** POST /api/util/share-for request body. */
|
|
22
27
|
export interface ShareForRequest {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL auth-key query parameter names and a reader that accepts both: `k`
|
|
3
|
+
* (generated since 3.15.0) and the legacy `key`. Pure; no I/O.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* OpenClaw masks the value of any query parameter named `key` in
|
|
7
|
+
* model-visible tool output, so agents could not relay share links (#279).
|
|
8
|
+
* Generated URLs therefore carry the key as `k`. `key` is still accepted
|
|
9
|
+
* everywhere so existing links, bookmarks and webhook URLs keep working.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
/** Query parameter name used for auth keys in every generated URL. */
|
|
14
|
+
export declare const URL_KEY_PARAM = "k";
|
|
15
|
+
/** Legacy query parameter name, still accepted for backward compatibility. */
|
|
16
|
+
export declare const LEGACY_URL_KEY_PARAM = "key";
|
|
17
|
+
/**
|
|
18
|
+
* Read the auth key from a parsed query object or `URLSearchParams`.
|
|
19
|
+
* `k` wins when both names are present; empty values count as absent.
|
|
20
|
+
*
|
|
21
|
+
* @param query - Parsed query (e.g. Fastify `request.query`) or search params.
|
|
22
|
+
* @returns The key, or `undefined` when neither parameter carries one.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getUrlKey(query: unknown): string | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL auth-key query parameter names and a reader that accepts both: `k`
|
|
3
|
+
* (generated since 3.15.0) and the legacy `key`. Pure; no I/O.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* OpenClaw masks the value of any query parameter named `key` in
|
|
7
|
+
* model-visible tool output, so agents could not relay share links (#279).
|
|
8
|
+
* Generated URLs therefore carry the key as `k`. `key` is still accepted
|
|
9
|
+
* everywhere so existing links, bookmarks and webhook URLs keep working.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
/** Query parameter name used for auth keys in every generated URL. */
|
|
14
|
+
const URL_KEY_PARAM = 'k';
|
|
15
|
+
/** Legacy query parameter name, still accepted for backward compatibility. */
|
|
16
|
+
const LEGACY_URL_KEY_PARAM = 'key';
|
|
17
|
+
/** First non-empty string in a parsed query value (string or repeated). */
|
|
18
|
+
function firstString(value) {
|
|
19
|
+
const candidate = Array.isArray(value) ? value[0] : value;
|
|
20
|
+
return typeof candidate === 'string' && candidate !== ''
|
|
21
|
+
? candidate
|
|
22
|
+
: undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Read the auth key from a parsed query object or `URLSearchParams`.
|
|
26
|
+
* `k` wins when both names are present; empty values count as absent.
|
|
27
|
+
*
|
|
28
|
+
* @param query - Parsed query (e.g. Fastify `request.query`) or search params.
|
|
29
|
+
* @returns The key, or `undefined` when neither parameter carries one.
|
|
30
|
+
*/
|
|
31
|
+
function getUrlKey(query) {
|
|
32
|
+
if (query instanceof URLSearchParams) {
|
|
33
|
+
return (firstString(query.get(URL_KEY_PARAM)) ??
|
|
34
|
+
firstString(query.get(LEGACY_URL_KEY_PARAM)));
|
|
35
|
+
}
|
|
36
|
+
if (query === null || typeof query !== 'object')
|
|
37
|
+
return undefined;
|
|
38
|
+
const record = query;
|
|
39
|
+
return (firstString(record[URL_KEY_PARAM]) ??
|
|
40
|
+
firstString(record[LEGACY_URL_KEY_PARAM]));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { LEGACY_URL_KEY_PARAM, URL_KEY_PARAM, getUrlKey };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Jeeves",
|
|
3
3
|
"dependencies": {
|
|
4
|
-
"@karmaniverous/jeeves": "0.
|
|
5
|
-
"zod": "^4.6.
|
|
4
|
+
"@karmaniverous/jeeves": "0.7.0",
|
|
5
|
+
"zod": "^4.6.7"
|
|
6
6
|
},
|
|
7
7
|
"description": "Shared cryptographic utilities and API types for jeeves-server packages.",
|
|
8
8
|
"devDependencies": {
|
|
9
|
-
"@dotenvx/dotenvx": "^2.
|
|
9
|
+
"@dotenvx/dotenvx": "^2.35.0",
|
|
10
10
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
11
11
|
"@rollup/plugin-json": "^6.1.0",
|
|
12
12
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
13
13
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
14
14
|
"cross-env": "^10.1.0",
|
|
15
|
-
"release-it": "^21.1.
|
|
16
|
-
"rollup": "^4.
|
|
15
|
+
"release-it": "^21.1.1",
|
|
16
|
+
"rollup": "^4.64.6",
|
|
17
17
|
"tslib": "^2.8.1",
|
|
18
|
-
"vitest": "^5.0.
|
|
18
|
+
"vitest": "^5.0.4"
|
|
19
19
|
},
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=22"
|
|
@@ -44,10 +44,13 @@
|
|
|
44
44
|
"tagName": "core/${version}"
|
|
45
45
|
},
|
|
46
46
|
"github": {
|
|
47
|
-
"release": true
|
|
47
|
+
"release": true,
|
|
48
|
+
"releaseName": "${name.split('/').pop()}@${version}",
|
|
49
|
+
"releaseNotes": "npx git-cliff --tag core/${version} --unreleased --strip header"
|
|
48
50
|
},
|
|
49
51
|
"hooks": {
|
|
50
52
|
"after:bump": [
|
|
53
|
+
"npx git-cliff --tag core/${version} -o CHANGELOG.md",
|
|
51
54
|
"npm install --package-lock-only --ignore-scripts",
|
|
52
55
|
"git add ../../package-lock.json"
|
|
53
56
|
],
|
|
@@ -63,7 +66,6 @@
|
|
|
63
66
|
"git switch ${branchName}"
|
|
64
67
|
],
|
|
65
68
|
"before:npm:release": [
|
|
66
|
-
"npx git-cliff -o CHANGELOG.md",
|
|
67
69
|
"git add -A"
|
|
68
70
|
]
|
|
69
71
|
},
|
|
@@ -90,5 +92,5 @@
|
|
|
90
92
|
},
|
|
91
93
|
"type": "module",
|
|
92
94
|
"types": "dist/src/index.d.ts",
|
|
93
|
-
"version": "0.
|
|
95
|
+
"version": "0.4.0"
|
|
94
96
|
}
|