@karmaniverous/jeeves-server-core 0.1.1 → 0.1.3

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.
@@ -34,4 +34,3 @@ export declare function computeDeepShareKey(seed: string, urlPath: string, param
34
34
  * Timing-safe string comparison
35
35
  */
36
36
  export declare function timingSafeEqual(a: string, b: string): boolean;
37
- //# sourceMappingURL=crypto.d.ts.map
@@ -1,13 +1,14 @@
1
+ import crypto from 'node:crypto';
2
+
1
3
  /**
2
4
  * Cryptographic utilities for HMAC key computation and verification.
3
5
  *
4
6
  * @packageDocumentation
5
7
  */
6
- import crypto from 'node:crypto';
7
8
  /**
8
9
  * Compute path-specific key: HMAC-SHA256(apiKey, normalizedPath)
9
10
  */
10
- export function computePathKey(apiKey, urlPath) {
11
+ function computePathKey(apiKey, urlPath) {
11
12
  const normalized = urlPath.toLowerCase().replace(/^\/+|\/+$/g, '');
12
13
  const hash = crypto
13
14
  .createHmac('sha256', apiKey)
@@ -19,7 +20,7 @@ export function computePathKey(apiKey, urlPath) {
19
20
  * Compute insider key: HMAC-SHA256(apiKey, "insider")
20
21
  * Works for any path, grants full navigation
21
22
  */
22
- export function computeInsiderKey(apiKey) {
23
+ function computeInsiderKey(apiKey) {
23
24
  const hash = crypto
24
25
  .createHmac('sha256', apiKey)
25
26
  .update('insider')
@@ -29,7 +30,7 @@ export function computeInsiderKey(apiKey) {
29
30
  /**
30
31
  * Compute outsider key with expiry: HMAC-SHA256(apiKey, path + "|" + expiry)
31
32
  */
32
- export function computeOutsiderKeyWithExpiry(apiKey, urlPath, expiry) {
33
+ function computeOutsiderKeyWithExpiry(apiKey, urlPath, expiry) {
33
34
  const normalized = urlPath.toLowerCase().replace(/^\/+|\/+$/g, '');
34
35
  const data = `${normalized}|${String(expiry)}`;
35
36
  const hash = crypto.createHmac('sha256', apiKey).update(data).digest('hex');
@@ -39,7 +40,7 @@ export function computeOutsiderKeyWithExpiry(apiKey, urlPath, expiry) {
39
40
  * Compute deep share key: HMAC-SHA256(seed, path + "|" + d + "|" + dirs + "|" + stack + "|" + exp)
40
41
  * Used for share links with depth \> 0 or dirs enabled.
41
42
  */
42
- export function computeDeepShareKey(seed, urlPath, params) {
43
+ function computeDeepShareKey(seed, urlPath, params) {
43
44
  const normalized = urlPath.toLowerCase().replace(/^\/+|\/+$/g, '');
44
45
  const data = `${normalized}|${String(params.depth)}|${params.dirs ? '1' : '0'}|${params.stack}|${params.exp ?? ''}`;
45
46
  const hash = crypto.createHmac('sha256', seed).update(data).digest('hex');
@@ -48,7 +49,7 @@ export function computeDeepShareKey(seed, urlPath, params) {
48
49
  /**
49
50
  * Timing-safe string comparison
50
51
  */
51
- export function timingSafeEqual(a, b) {
52
+ function timingSafeEqual(a, b) {
52
53
  try {
53
54
  return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
54
55
  }
@@ -56,3 +57,5 @@ export function timingSafeEqual(a, b) {
56
57
  return false;
57
58
  }
58
59
  }
60
+
61
+ export { computeDeepShareKey, computeInsiderKey, computeOutsiderKeyWithExpiry, computePathKey, timingSafeEqual };
@@ -4,5 +4,5 @@
4
4
  * @packageDocumentation
5
5
  */
6
6
  export { computeDeepShareKey, computeInsiderKey, computeOutsiderKeyWithExpiry, computePathKey, type DeepShareParams, timingSafeEqual, } from './crypto.js';
7
+ export { type AuthMode, authModeSchema, authSchema, DEPRECATED_CONFIG_PROPS, eventConfigSchema, googleAuthSchema, insiderEntrySchema, isScopeName, type JeevesConfig, jeevesConfigSchema, keyEntrySchema, oauthProviderSchema, oauthSchema, scopesObjectSchema, scopesSchema, } from './schema.js';
7
8
  export type { AuthStatusResponse, DriveEntry, ExportCacheClearResponse, ExportLink, FileMutationAction, LinkInfoResponse, OAuthStartRequest, OAuthStartResponse, RotateKeyResponse, ShareForRequest, ShareForResponse, ShareRequest, ShareResponse, } from './types.js';
8
- //# sourceMappingURL=index.d.ts.map
package/dist/src/index.js CHANGED
@@ -1,6 +1,2 @@
1
- /**
2
- * Shared utilities and types for jeeves-server packages.
3
- *
4
- * @packageDocumentation
5
- */
6
- export { computeDeepShareKey, computeInsiderKey, computeOutsiderKeyWithExpiry, computePathKey, timingSafeEqual, } from './crypto.js';
1
+ export { computeDeepShareKey, computeInsiderKey, computeOutsiderKeyWithExpiry, computePathKey, timingSafeEqual } from './crypto.js';
2
+ export { DEPRECATED_CONFIG_PROPS, authModeSchema, authSchema, eventConfigSchema, googleAuthSchema, insiderEntrySchema, isScopeName, jeevesConfigSchema, keyEntrySchema, oauthProviderSchema, oauthSchema, scopesObjectSchema, scopesSchema } from './schema.js';
@@ -0,0 +1,168 @@
1
+ import { z } from 'zod';
2
+ /** Config properties deprecated in v3.6.0 (now resolved via core services). */
3
+ export declare const DEPRECATED_CONFIG_PROPS: readonly ["host", "runnerUrl", "watcherUrl", "metaUrl"];
4
+ /** Supported authentication methods */
5
+ export declare const authModeSchema: z.ZodEnum<{
6
+ google: "google";
7
+ keys: "keys";
8
+ }>;
9
+ /** Google OAuth configuration */
10
+ export declare const googleAuthSchema: z.ZodObject<{
11
+ clientId: z.ZodString;
12
+ clientSecret: z.ZodString;
13
+ }, z.core.$strip>;
14
+ /** Auth configuration */
15
+ export declare const authSchema: z.ZodObject<{
16
+ modes: z.ZodArray<z.ZodEnum<{
17
+ google: "google";
18
+ keys: "keys";
19
+ }>>;
20
+ google: z.ZodOptional<z.ZodObject<{
21
+ clientId: z.ZodString;
22
+ clientSecret: z.ZodString;
23
+ }, z.core.$strip>>;
24
+ sessionSecret: z.ZodOptional<z.ZodString>;
25
+ }, z.core.$strip>;
26
+ /** Event webhook configuration */
27
+ export declare const eventConfigSchema: z.ZodObject<{
28
+ schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
29
+ cmd: z.ZodString;
30
+ map: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
31
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
32
+ }, z.core.$strip>;
33
+ /**
34
+ * Scopes configuration — controls which paths a user/key can access.
35
+ *
36
+ * Three forms:
37
+ * - `string` — single allow pattern (e.g. '/d/*')
38
+ * - `string[]` — array of allow patterns (shorthand for \{ allow: [...] \})
39
+ * - `\{ allow?: string[], deny?: string[] \}` — explicit allow/deny rules
40
+ *
41
+ * Semantics:
42
+ * - Path must match at least one allow rule AND NOT match any deny rule
43
+ * - Omitting `allow` = implicit ['/*'] (allow everything)
44
+ * - Omitting `deny` = no exclusions
45
+ * - Omitting scopes entirely = unrestricted access
46
+ */
47
+ export declare const scopesObjectSchema: z.ZodObject<{
48
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
49
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
50
+ }, z.core.$strip>;
51
+ export declare const scopesSchema: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodObject<{
52
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
53
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
54
+ }, z.core.$strip>]>;
55
+ /** Insider entry (identity + scopes + optional persisted seed) */
56
+ export declare const insiderEntrySchema: z.ZodObject<{
57
+ scopes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodObject<{
58
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
59
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
60
+ }, z.core.$strip>]>>;
61
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
62
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
63
+ seed: z.ZodOptional<z.ZodString>;
64
+ keyCreatedAt: z.ZodOptional<z.ZodString>;
65
+ }, z.core.$strip>;
66
+ /** Key entry — plain string (seed, no scopes) or object with key + optional scopes */
67
+ export declare const keyEntrySchema: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
68
+ key: z.ZodString;
69
+ scopes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodObject<{
70
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
71
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
72
+ }, z.core.$strip>]>>;
73
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
74
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
75
+ }, z.core.$strip>]>;
76
+ /** Check if a string is a named scope identifier (not a path glob). */
77
+ export declare function isScopeName(v: string): boolean;
78
+ /** OAuth provider configuration */
79
+ export declare const oauthProviderSchema: z.ZodObject<{
80
+ authUrl: z.ZodPipe<z.ZodString, z.ZodURL>;
81
+ tokenUrl: z.ZodPipe<z.ZodString, z.ZodURL>;
82
+ pkce: z.ZodDefault<z.ZodBoolean>;
83
+ defaultScopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
84
+ }, z.core.$strip>;
85
+ /** OAuth configuration */
86
+ export declare const oauthSchema: z.ZodObject<{
87
+ credentialDir: z.ZodString;
88
+ providers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
89
+ authUrl: z.ZodPipe<z.ZodString, z.ZodURL>;
90
+ tokenUrl: z.ZodPipe<z.ZodString, z.ZodURL>;
91
+ pkce: z.ZodDefault<z.ZodBoolean>;
92
+ defaultScopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
93
+ }, z.core.$strip>>>;
94
+ }, z.core.$strip>;
95
+ /** Top-level Jeeves Server configuration */
96
+ export declare const jeevesConfigSchema: z.ZodObject<{
97
+ port: z.ZodDefault<z.ZodNumber>;
98
+ chromePath: z.ZodString;
99
+ auth: z.ZodObject<{
100
+ modes: z.ZodArray<z.ZodEnum<{
101
+ google: "google";
102
+ keys: "keys";
103
+ }>>;
104
+ google: z.ZodOptional<z.ZodObject<{
105
+ clientId: z.ZodString;
106
+ clientSecret: z.ZodString;
107
+ }, z.core.$strip>>;
108
+ sessionSecret: z.ZodOptional<z.ZodString>;
109
+ }, z.core.$strip>;
110
+ scopes: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
111
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
112
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
113
+ }, z.core.$strip>>>;
114
+ insiders: z.ZodDefault<z.ZodRecord<z.ZodEmail, z.ZodObject<{
115
+ scopes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodObject<{
116
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
117
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
118
+ }, z.core.$strip>]>>;
119
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
120
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
121
+ seed: z.ZodOptional<z.ZodString>;
122
+ keyCreatedAt: z.ZodOptional<z.ZodString>;
123
+ }, z.core.$strip>>>;
124
+ keys: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
125
+ key: z.ZodString;
126
+ scopes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodObject<{
127
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
128
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
129
+ }, z.core.$strip>]>>;
130
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
131
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
132
+ }, z.core.$strip>]>>>;
133
+ events: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
134
+ schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
135
+ cmd: z.ZodString;
136
+ map: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
137
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
138
+ }, z.core.$strip>>>;
139
+ eventTimeoutMs: z.ZodDefault<z.ZodNumber>;
140
+ eventLogPurgeMs: z.ZodDefault<z.ZodNumber>;
141
+ maxZipSizeMb: z.ZodDefault<z.ZodNumber>;
142
+ roots: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
143
+ mermaidCliPath: z.ZodOptional<z.ZodString>;
144
+ plantuml: z.ZodOptional<z.ZodObject<{
145
+ jarPath: z.ZodOptional<z.ZodString>;
146
+ javaPath: z.ZodOptional<z.ZodString>;
147
+ servers: z.ZodOptional<z.ZodArray<z.ZodURL>>;
148
+ }, z.core.$strip>>;
149
+ diagramCachePath: z.ZodOptional<z.ZodString>;
150
+ outsiderPolicy: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodObject<{
151
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
152
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
153
+ }, z.core.$strip>]>>;
154
+ oauth: z.ZodOptional<z.ZodObject<{
155
+ credentialDir: z.ZodString;
156
+ providers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
157
+ authUrl: z.ZodPipe<z.ZodString, z.ZodURL>;
158
+ tokenUrl: z.ZodPipe<z.ZodString, z.ZodURL>;
159
+ pkce: z.ZodDefault<z.ZodBoolean>;
160
+ defaultScopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
161
+ }, z.core.$strip>>>;
162
+ }, z.core.$strip>>;
163
+ go: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
164
+ }, z.core.$strip>;
165
+ /** Inferred config type */
166
+ export type JeevesConfig = z.infer<typeof jeevesConfigSchema>;
167
+ /** Auth mode type */
168
+ export type AuthMode = z.infer<typeof authModeSchema>;
@@ -0,0 +1,252 @@
1
+ import { SERVER_PORT } from '@karmaniverous/jeeves';
2
+ import { z } from 'zod';
3
+
4
+ /** Config properties deprecated in v3.6.0 (now resolved via core services). */
5
+ const DEPRECATED_CONFIG_PROPS = [
6
+ 'host',
7
+ 'runnerUrl',
8
+ 'watcherUrl',
9
+ 'metaUrl',
10
+ ];
11
+ /** Supported authentication methods */
12
+ const authModeSchema = z.enum(['google', 'keys']);
13
+ /** Google OAuth configuration */
14
+ const googleAuthSchema = z.object({
15
+ clientId: z.string().min(1),
16
+ clientSecret: z.string().min(1),
17
+ });
18
+ /** Auth configuration */
19
+ const authSchema = z.object({
20
+ /** Active authentication methods. Order determines priority. */
21
+ modes: z
22
+ .array(authModeSchema)
23
+ .min(1, { message: 'At least one auth mode is required' }),
24
+ /** Google OAuth config. Required if modes includes "google". */
25
+ google: googleAuthSchema.optional(),
26
+ /** Session cookie signing secret. Required if modes includes "google". */
27
+ sessionSecret: z.string().min(1).optional(),
28
+ });
29
+ /** Event webhook configuration */
30
+ const eventConfigSchema = z.object({
31
+ schema: z.record(z.string(), z.unknown()),
32
+ cmd: z.string(),
33
+ map: z.record(z.string(), z.unknown()).optional(),
34
+ timeoutMs: z.number().positive().optional(),
35
+ });
36
+ /**
37
+ * Scopes configuration — controls which paths a user/key can access.
38
+ *
39
+ * Three forms:
40
+ * - `string` — single allow pattern (e.g. '/d/*')
41
+ * - `string[]` — array of allow patterns (shorthand for \{ allow: [...] \})
42
+ * - `\{ allow?: string[], deny?: string[] \}` — explicit allow/deny rules
43
+ *
44
+ * Semantics:
45
+ * - Path must match at least one allow rule AND NOT match any deny rule
46
+ * - Omitting `allow` = implicit ['/*'] (allow everything)
47
+ * - Omitting `deny` = no exclusions
48
+ * - Omitting scopes entirely = unrestricted access
49
+ */
50
+ const scopesObjectSchema = z.object({
51
+ allow: z.array(z.string()).optional(),
52
+ deny: z.array(z.string()).optional(),
53
+ });
54
+ const scopesSchema = z.union([
55
+ z.string(),
56
+ z.array(z.string()),
57
+ scopesObjectSchema,
58
+ ]);
59
+ /** Insider entry (identity + scopes + optional persisted seed) */
60
+ const insiderEntrySchema = z.object({
61
+ scopes: scopesSchema.optional(),
62
+ /** Extra allow patterns merged on top of named scope references */
63
+ allow: z.array(z.string()).optional(),
64
+ /** Extra deny patterns merged on top of named scope references */
65
+ deny: z.array(z.string()).optional(),
66
+ /** Auto-generated insider seed, persisted in config.json */
67
+ seed: z.string().min(1).optional(),
68
+ /** ISO timestamp of when the seed was created */
69
+ keyCreatedAt: z.string().optional(),
70
+ });
71
+ /** Key entry — plain string (seed, no scopes) or object with key + optional scopes */
72
+ const keyEntrySchema = z.union([
73
+ z.string().min(1),
74
+ z.object({
75
+ key: z.string().min(1),
76
+ scopes: scopesSchema.optional(),
77
+ /** Extra allow patterns merged on top of named scope references */
78
+ allow: z.array(z.string()).optional(),
79
+ /** Extra deny patterns merged on top of named scope references */
80
+ deny: z.array(z.string()).optional(),
81
+ }),
82
+ ]);
83
+ /** Check if a string is a named scope identifier (not a path glob). */
84
+ function isScopeName(v) {
85
+ return /^[A-Za-z0-9_-]+$/.test(v);
86
+ }
87
+ /** Helper: collect named scope references from a scopes field value.
88
+ *
89
+ * Backward-compat note: `scopes` has historically accepted path globs like "/**" or ["/a","/b"].
90
+ * We only treat values as *named scope references* if they look like identifiers
91
+ * (e.g. "restricted", "no-vc") rather than path globs.
92
+ */
93
+ function getScopeRefs(scopes) {
94
+ if (typeof scopes === 'string')
95
+ return isScopeName(scopes) ? [scopes] : [];
96
+ if (Array.isArray(scopes) && scopes.length > 0) {
97
+ const strs = scopes.filter((v) => typeof v === 'string');
98
+ if (strs.length !== scopes.length)
99
+ return [];
100
+ return strs.filter((v) => isScopeName(v));
101
+ }
102
+ return [];
103
+ }
104
+ /** OAuth provider configuration */
105
+ const oauthProviderSchema = z.object({
106
+ authUrl: z.string().pipe(z.url()),
107
+ tokenUrl: z.string().pipe(z.url()),
108
+ pkce: z.boolean().default(false),
109
+ defaultScopes: z.array(z.string()).default([]),
110
+ });
111
+ /** OAuth configuration */
112
+ const oauthSchema = z.object({
113
+ credentialDir: z.string(),
114
+ providers: z.record(z.string(), oauthProviderSchema).default({}),
115
+ });
116
+ /** Top-level Jeeves Server configuration */
117
+ const jeevesConfigSchema = z
118
+ .object({
119
+ port: z.number().int().positive().default(SERVER_PORT),
120
+ chromePath: z.string().min(1),
121
+ auth: authSchema,
122
+ /** Named scope definitions, referenced by insiders/keys/outsiderPolicy */
123
+ scopes: z.record(z.string(), scopesObjectSchema).default({}),
124
+ insiders: z.record(z.email(), insiderEntrySchema).default({}),
125
+ keys: z.record(z.string(), keyEntrySchema).default({}),
126
+ events: z.record(z.string(), eventConfigSchema).default({}),
127
+ eventTimeoutMs: z.number().positive().default(30_000),
128
+ eventLogPurgeMs: z.number().positive().default(2_592_000_000),
129
+ /** Maximum directory size in MB for ZIP export. Directories exceeding this are refused. */
130
+ maxZipSizeMb: z.number().positive().default(100),
131
+ /**
132
+ * Filesystem roots for the file browser (Linux only).
133
+ * Map of id → filesystem path. On Windows this is ignored (drives are auto-discovered).
134
+ * Example: \{ home: '/home/user', projects: '/opt/projects' \}
135
+ * Default: \{ root: '/' \}
136
+ */
137
+ roots: z.record(z.string(), z.string()).optional(),
138
+ /** @deprecated Mermaid is now bundled. This field is ignored but kept for backward compatibility. */
139
+ mermaidCliPath: z.string().optional(),
140
+ /**
141
+ * PlantUML rendering configuration.
142
+ * - jarPath: local PlantUML jar (requires Java). Tried first — supports !include.
143
+ * - servers: fallback PlantUML server URLs, tried in order.
144
+ * The public community server (https://www.plantuml.com/plantuml) is always
145
+ * appended as the last resort unless explicitly listed.
146
+ * If omitted entirely, only the community server is used.
147
+ */
148
+ plantuml: z
149
+ .object({
150
+ jarPath: z.string().optional(),
151
+ javaPath: z.string().optional(),
152
+ servers: z.array(z.url()).optional(),
153
+ })
154
+ .optional(),
155
+ /**
156
+ * Directory for cached rendered diagrams (content-addressed by source hash).
157
+ * Defaults to `.diagram-cache` in the server working directory.
158
+ */
159
+ diagramCachePath: z.string().optional(),
160
+ /**
161
+ * Global outsider policy — constrains which paths are eligible for outsider sharing.
162
+ * Uses the same allow/deny model as insider scopes.
163
+ * If omitted, all paths are shareable with outsiders.
164
+ */
165
+ outsiderPolicy: scopesSchema.optional(),
166
+ /** OAuth2 credential management configuration */
167
+ oauth: oauthSchema.optional(),
168
+ /**
169
+ * Shortlink redirects. Keys are slug identifiers (`[a-zA-Z0-9_-]+`),
170
+ * values are redirect targets — either relative paths (e.g. `/browse/...`)
171
+ * or absolute URLs (e.g. `https://example.com`).
172
+ *
173
+ * Accessible at `GET /go/:slug` without authentication.
174
+ */
175
+ go: z
176
+ .record(z.string().regex(/^[a-zA-Z0-9_-]+$/), z
177
+ .string()
178
+ .min(1)
179
+ .refine((v) => v.startsWith('/') || /^[a-z]+:\/\//i.test(v), {
180
+ message: 'Target must be a relative path starting with / or an absolute URL',
181
+ }))
182
+ .default({}),
183
+ })
184
+ .superRefine((config, ctx) => {
185
+ // Google auth mode requires google config + sessionSecret
186
+ if (config.auth.modes.includes('google')) {
187
+ if (!config.auth.google) {
188
+ ctx.addIssue({
189
+ code: 'custom',
190
+ message: 'auth.google is required when auth.modes includes "google"',
191
+ path: ['auth', 'google'],
192
+ });
193
+ }
194
+ if (!config.auth.sessionSecret) {
195
+ ctx.addIssue({
196
+ code: 'custom',
197
+ message: 'auth.sessionSecret is required when auth.modes includes "google"',
198
+ path: ['auth', 'sessionSecret'],
199
+ });
200
+ }
201
+ }
202
+ // Keys auth mode requires at least one key
203
+ if (config.auth.modes.includes('keys') &&
204
+ Object.keys(config.keys).length === 0) {
205
+ ctx.addIssue({
206
+ code: 'custom',
207
+ message: 'At least one key is required when auth.modes includes "keys"',
208
+ path: ['keys'],
209
+ });
210
+ }
211
+ // _internal and _plugin keys must not have scopes
212
+ for (const reserved of ['_internal', '_plugin']) {
213
+ const key = config.keys[reserved];
214
+ if (key && typeof key === 'object' && 'scopes' in key && key.scopes) {
215
+ ctx.addIssue({
216
+ code: 'custom',
217
+ message: `${reserved} key must not have scopes (it is always unscoped)`,
218
+ path: ['keys', reserved],
219
+ });
220
+ }
221
+ }
222
+ // Validate all scope name references resolve to the top-level scopes map
223
+ const scopeNames = new Set(Object.keys(config.scopes));
224
+ const validateRefs = (refs, refPath) => {
225
+ for (const ref of refs) {
226
+ if (!scopeNames.has(ref)) {
227
+ ctx.addIssue({
228
+ code: 'custom',
229
+ message: `Scope "${ref}" is not defined in the top-level scopes map`,
230
+ path: refPath,
231
+ });
232
+ }
233
+ }
234
+ };
235
+ for (const [email, entry] of Object.entries(config.insiders)) {
236
+ const refs = getScopeRefs(entry.scopes);
237
+ if (refs.length > 0)
238
+ validateRefs(refs, ['insiders', email, 'scopes']);
239
+ }
240
+ for (const [name, entry] of Object.entries(config.keys)) {
241
+ if (typeof entry === 'object') {
242
+ const refs = getScopeRefs(entry.scopes);
243
+ if (refs.length > 0)
244
+ validateRefs(refs, ['keys', name, 'scopes']);
245
+ }
246
+ }
247
+ const outsiderRefs = getScopeRefs(config.outsiderPolicy);
248
+ if (outsiderRefs.length > 0)
249
+ validateRefs(outsiderRefs, ['outsiderPolicy']);
250
+ });
251
+
252
+ export { DEPRECATED_CONFIG_PROPS, authModeSchema, authSchema, eventConfigSchema, googleAuthSchema, insiderEntrySchema, isScopeName, jeevesConfigSchema, keyEntrySchema, oauthProviderSchema, oauthSchema, scopesObjectSchema, scopesSchema };
@@ -88,4 +88,3 @@ export interface DriveEntry {
88
88
  letter: string;
89
89
  label: string;
90
90
  }
91
- //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "@karmaniverous/jeeves-server-core",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
+ "author": "Jeeves",
5
+ "description": "Shared cryptographic utilities and API types for jeeves-server packages.",
6
+ "license": "MIT",
4
7
  "type": "module",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/karmaniverous/jeeves-server.git",
11
+ "directory": "packages/core"
12
+ },
5
13
  "files": [
6
14
  "dist"
7
15
  ],
@@ -10,14 +18,15 @@
10
18
  },
11
19
  "scripts": {
12
20
  "prebuild": "npx rimraf dist",
13
- "build": "tsc",
21
+ "build": "cross-env NO_COLOR=1 rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript",
14
22
  "lint": "eslint .",
15
23
  "lint:fix": "eslint --fix .",
16
24
  "test": "vitest run --passWithNoTests",
17
25
  "typecheck": "tsc --noEmit",
18
26
  "changelog": "git-cliff -o CHANGELOG.md",
19
27
  "release": "dotenvx run -f .env.local -- release-it",
20
- "release:pre": "dotenvx run -f .env.local -- release-it --no-git.requireBranch --github.prerelease --preRelease"
28
+ "release:pre": "dotenvx run -f .env.local -- release-it --no-git.requireBranch --github.prerelease --preRelease",
29
+ "postbuild": "npx rimraf dist/rollup.config.d.ts dist/rollup.config.d.ts.map"
21
30
  },
22
31
  "exports": {
23
32
  ".": {
@@ -28,10 +37,21 @@
28
37
  }
29
38
  },
30
39
  "types": "dist/src/index.d.ts",
40
+ "dependencies": {
41
+ "@karmaniverous/jeeves": "^0.5.11",
42
+ "zod": "^4.4.3"
43
+ },
31
44
  "devDependencies": {
32
- "vitest": "^4.1.2",
45
+ "@dotenvx/dotenvx": "^1.69.1",
46
+ "@rollup/plugin-commonjs": "^29.0.2",
47
+ "@rollup/plugin-json": "^6.1.0",
48
+ "@rollup/plugin-node-resolve": "^16.0.3",
49
+ "@rollup/plugin-typescript": "^12.3.0",
50
+ "cross-env": "^10.1.0",
33
51
  "release-it": "^19.2.4",
34
- "@dotenvx/dotenvx": "^1.59.1"
52
+ "rollup": "^4.60.4",
53
+ "tslib": "^2.8.1",
54
+ "vitest": "^4.1.7"
35
55
  },
36
56
  "engines": {
37
57
  "node": ">=22"
@@ -1 +0,0 @@
1
- {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAOtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMxD;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,CAKR;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,eAAe,GACtB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAM7D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,4BAA4B,EAC5B,cAAc,EACd,KAAK,eAAe,EACpB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,kBAAkB,EAClB,UAAU,EACV,wBAAwB,EACxB,UAAU,EACV,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,aAAa,GACd,MAAM,YAAY,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,gCAAgC;AAChC,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,yCAAyC;AACzC,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,SAAS,GAAG,gBAAgB,GAAG,SAAS,GAAG,eAAe,CAAC;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,sCAAsC;AACtC,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B;AAED,+CAA+C;AAC/C,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,6CAA6C;AAC7C,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,kCAAkC;AAClC,MAAM,MAAM,kBAAkB,GAC1B,YAAY,GACZ,cAAc,GACd,cAAc,GACd,WAAW,GACX,iBAAiB,CAAC;AAEtB,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,qCAAqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,sCAAsC;AACtC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf"}
package/dist/src/types.js DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Shared API request/response types between service and plugin.
3
- *
4
- * @packageDocumentation
5
- */
6
- export {};