@h-ai/kit 1.0.0-beta.2 → 1.0.0-beta.21

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.
Files changed (43) hide show
  1. package/README.en.md +190 -110
  2. package/README.ja.md +192 -112
  3. package/README.md +195 -114
  4. package/dist/adapter/index.d.ts +8 -7
  5. package/dist/adapter/index.js.map +1 -1
  6. package/dist/browser.d.ts +9 -26
  7. package/dist/browser.js +4 -4
  8. package/dist/browser.js.map +1 -1
  9. package/dist/{chunk-JRQPMPQC.js → chunk-BCEBXG4X.js} +2 -2
  10. package/dist/chunk-BCEBXG4X.js.map +1 -0
  11. package/dist/{chunk-7EH47MTW.js → chunk-BVGXHIXR.js} +30 -9
  12. package/dist/chunk-BVGXHIXR.js.map +1 -0
  13. package/dist/{chunk-5VWPH7DO.js → chunk-GQZCU6PC.js} +14 -6
  14. package/dist/chunk-GQZCU6PC.js.map +1 -0
  15. package/dist/{chunk-YKJRQCWR.js → chunk-JL2C5ZGQ.js} +54 -20
  16. package/dist/chunk-JL2C5ZGQ.js.map +1 -0
  17. package/dist/{chunk-3OHUSKHI.js → chunk-WYGIKXHE.js} +23 -8
  18. package/dist/chunk-WYGIKXHE.js.map +1 -0
  19. package/dist/client/index.d.ts +6 -5
  20. package/dist/client/index.js +5 -5
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/index.d.ts +18 -711
  23. package/dist/index.js +266 -149
  24. package/dist/index.js.map +1 -1
  25. package/dist/{kit-a2a-types-4dapztu2.d.ts → kit-a2a-types-sw7sI-ZT.d.ts} +3 -2
  26. package/dist/kit-config-BQKQnu8Y.d.ts +182 -0
  27. package/dist/kit-crypto-types-CqFENBqm.d.ts +47 -0
  28. package/dist/kit-types-Cr1cnB3M.d.ts +2051 -0
  29. package/dist/modules/a2a/index.d.ts +9 -5
  30. package/dist/modules/a2a/index.js +1 -1
  31. package/dist/modules/crypto/index.d.ts +8 -105
  32. package/dist/modules/crypto/index.js +3 -149
  33. package/dist/modules/crypto/index.js.map +1 -1
  34. package/package.json +22 -22
  35. package/dist/chunk-3OHUSKHI.js.map +0 -1
  36. package/dist/chunk-5VWPH7DO.js.map +0 -1
  37. package/dist/chunk-7EH47MTW.js.map +0 -1
  38. package/dist/chunk-JRQPMPQC.js.map +0 -1
  39. package/dist/chunk-YKJRQCWR.js.map +0 -1
  40. package/dist/kit-client-auth-BnhrkzZF.d.ts +0 -422
  41. package/dist/kit-crypto-types-CXr888wf.d.ts +0 -200
  42. package/dist/kit-i18n-EBzZKYN-.d.ts +0 -502
  43. package/dist/kit-types-BkNdyKj8.d.ts +0 -822
package/dist/index.js CHANGED
@@ -1,16 +1,18 @@
1
- import { defineCrud } from './chunk-5VWPH7DO.js';
2
- export { KitConfigSchema, defineCrud, resolveKitConfig, resolveKitTransportConfig, resolveOptions, resolveText } from './chunk-5VWPH7DO.js';
3
- import { clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient, getAccessToken, configureAuth } from './chunk-YKJRQCWR.js';
4
- import { resolveA2AConfig, handleA2ARequest } from './chunk-7EH47MTW.js';
5
- import { transportEncryptionMiddleware } from './chunk-3OHUSKHI.js';
6
- import './chunk-JRQPMPQC.js';
1
+ import { defineCrud } from './chunk-GQZCU6PC.js';
2
+ export { KitConfigSchema, defineCrud, resolveKitConfig, resolveKitTransportConfig, resolveOptions, resolveText } from './chunk-GQZCU6PC.js';
3
+ import { clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient, getAccessToken, configureAuth } from './chunk-JL2C5ZGQ.js';
4
+ import { resolveA2AConfig, handleA2ARequest } from './chunk-BVGXHIXR.js';
5
+ import { transportEncryptionMiddleware } from './chunk-WYGIKXHE.js';
6
+ import './chunk-BCEBXG4X.js';
7
7
  import { kitM, setAllModulesLocale } from './chunk-USFJN7IO.js';
8
8
  import { core, HaiCommonError, err } from '@h-ai/core';
9
+ import process from 'process';
9
10
  import { audit } from '@h-ai/audit';
10
11
  import { TRANSPORT_PROTOCOL } from '@h-ai/crypto';
11
- import { createHash } from 'crypto';
12
+ import { isHttpError, isRedirect } from '@sveltejs/kit';
13
+ import { createHash, hkdfSync, timingSafeEqual, createHmac } from 'crypto';
12
14
  import { isIP } from 'net';
13
- import process2 from 'process';
15
+ import { Buffer } from 'buffer';
14
16
  import { IamConfirmPasswordResetInputSchema, IamRequestPasswordResetInputSchema, IamSendOtpInputSchema, IamRegisterInputSchema, IamOtpLoginInputSchema, IamLdapLoginInputSchema, IamLoginInputSchema, IamRenewPasswordInputSchema, IamReauthenticateInputSchema, IamCreateCaptchaInputSchema, IamLogoutInputSchema, FeedbackSubmitInputSchema, FeedbackListInputSchema, FeedbackIdInputSchema, FeedbackEvidenceQuerySchema, FeedbackAppendEvidenceInputSchema, FeedbackSetStatusInputSchema, FeedbackRetryInputSchema, FeedbackCompleteInputSchema, FeedbackExportInputSchema, FeedbackUploadInputSchema, FeedbackAttachmentQuerySchema, FeedbackExportQuerySchema } from '@h-ai/api-contract';
15
17
  import { z } from 'zod';
16
18
 
@@ -40,14 +42,28 @@ function hasPermission(session, permission) {
40
42
  function assertPermission(session, permission) {
41
43
  if (!session) {
42
44
  return new Response(
43
- JSON.stringify({ success: false, error: kitM("kit_unauthorized") }),
44
- { status: 401, headers: { "Content-Type": "application/json" } }
45
+ JSON.stringify({
46
+ success: false,
47
+ error: kitM("kit_unauthorized")
48
+ }),
49
+ {
50
+ status: 401,
51
+ headers: { "Content-Type": "application/json" }
52
+ }
45
53
  );
46
54
  }
47
55
  if (!matchPermission(permission, session.permissions ?? [])) {
48
56
  return new Response(
49
- JSON.stringify({ success: false, error: kitM("kit_forbidden", { params: { permission } }) }),
50
- { status: 403, headers: { "Content-Type": "application/json" } }
57
+ JSON.stringify({
58
+ success: false,
59
+ error: kitM("kit_forbidden", {
60
+ params: { permission }
61
+ })
62
+ }),
63
+ {
64
+ status: 403,
65
+ headers: { "Content-Type": "application/json" }
66
+ }
51
67
  );
52
68
  }
53
69
  return void 0;
@@ -85,42 +101,57 @@ function noContent() {
85
101
  }
86
102
  function error(code, message, status = 400, requestId, details) {
87
103
  const safe = core.error.toPublic({ code, message, httpStatus: status }, requestId);
88
- core.logger.error("API request failed", { traceId: safe.traceId, error: { code, message, httpStatus: status, details } });
104
+ const safeStatus = safe.httpStatus ?? 500;
105
+ core.logger.error("API request failed", {
106
+ traceId: safe.traceId,
107
+ error: {
108
+ code,
109
+ message,
110
+ httpStatus: status,
111
+ details
112
+ }
113
+ });
89
114
  const response = {
90
115
  success: false,
91
116
  error: {
92
- code,
117
+ code: String(safe.code),
93
118
  message: safe.message,
94
119
  traceId: safe.traceId,
95
- details: status < 500 ? core.sanitize.sanitizeSensitiveFields(details) : void 0
120
+ httpStatus: safeStatus,
121
+ details: safeStatus < 500 ? core.sanitize.sanitizeSensitiveFields(details) : void 0
96
122
  },
97
- requestId: requestId ?? core.context.get().requestId ?? safe.traceId
123
+ requestId: safe.traceId
98
124
  };
99
125
  return new Response(JSON.stringify(response), {
100
- status,
126
+ status: safeStatus,
101
127
  headers: { "Content-Type": "application/json", "X-Trace-Id": safe.traceId }
102
128
  });
103
129
  }
104
130
  function badRequest(message, requestId, details) {
105
- return error("BAD_REQUEST", message, 400, requestId, details);
131
+ return error(HaiCommonError.INVALID_REQUEST.code, message, 400, requestId, details);
106
132
  }
107
133
  function unauthorized(message, requestId) {
108
- return error("UNAUTHORIZED", message ?? kitM("kit_authRequired"), 401, requestId);
134
+ return error(HaiCommonError.UNAUTHORIZED.code, message ?? kitM("kit_authRequired"), 401, requestId);
109
135
  }
110
136
  function forbidden(message, requestId) {
111
- return error("FORBIDDEN", message ?? kitM("kit_accessDenied"), 403, requestId);
137
+ return error(HaiCommonError.FORBIDDEN.code, message ?? kitM("kit_accessDenied"), 403, requestId);
112
138
  }
113
139
  function notFound(message, requestId) {
114
- return error("NOT_FOUND", message ?? kitM("kit_resourceNotFound"), 404, requestId);
140
+ return error(HaiCommonError.NOT_FOUND.code, message ?? kitM("kit_resourceNotFound"), 404, requestId);
115
141
  }
116
142
  function conflict(message, requestId) {
117
- return error("CONFLICT", message, 409, requestId);
143
+ return error(HaiCommonError.CONFLICT.code, message, 409, requestId);
118
144
  }
119
145
  function validationError(errors, requestId) {
120
- return error("VALIDATION_ERROR", kitM("kit_validationFailed"), 422, requestId, { errors });
146
+ return fromError({
147
+ ...HaiCommonError.VALIDATION_ERROR,
148
+ message: kitM("kit_validationFailed"),
149
+ httpStatus: 422,
150
+ cause: errors
151
+ }, requestId);
121
152
  }
122
153
  function internalError(message, requestId) {
123
- return error("INTERNAL_ERROR", message ?? kitM("kit_internalError"), 500, requestId);
154
+ return error(HaiCommonError.INTERNAL_ERROR.code, message ?? kitM("kit_internalError"), 500, requestId);
124
155
  }
125
156
  function redirect(url, status = 302) {
126
157
  return new Response(null, {
@@ -132,13 +163,25 @@ function fromResult(result, httpStatusMap, requestId) {
132
163
  if (result.success) {
133
164
  return ok(result.data, requestId);
134
165
  }
135
- const status = httpStatusMap?.[result.error.code] ?? (typeof result.error.httpStatus === "number" ? result.error.httpStatus : 400);
166
+ const status = httpStatusMap?.[result.error.code] ?? (typeof result.error.httpStatus === "number" ? result.error.httpStatus : 500);
136
167
  return fromError({ ...result.error, httpStatus: status }, requestId);
137
168
  }
138
169
  function fromError(haiError, requestId) {
139
170
  const safe = core.error.toPublic(haiError, requestId);
140
171
  core.logger.error("API operation failed", { traceId: safe.traceId, error: haiError });
141
- return error(String(safe.code), safe.message, safe.httpStatus ?? 400, safe.traceId);
172
+ const response = {
173
+ success: false,
174
+ error: {
175
+ ...safe,
176
+ code: String(safe.code),
177
+ httpStatus: safe.httpStatus ?? 500
178
+ },
179
+ requestId: safe.traceId
180
+ };
181
+ return new Response(JSON.stringify(response), {
182
+ status: safe.httpStatus ?? 500,
183
+ headers: { "Content-Type": "application/json", "X-Trace-Id": safe.traceId }
184
+ });
142
185
  }
143
186
 
144
187
  // src/guards/kit-sensitive.ts
@@ -150,8 +193,6 @@ async function requireSensitiveOperation(iam, event, operation) {
150
193
  if (!checked.success)
151
194
  throw fromError(checked.error);
152
195
  }
153
-
154
- // src/kit-utils.ts
155
196
  function isResponseLike(value) {
156
197
  if (value instanceof Response)
157
198
  return true;
@@ -161,16 +202,19 @@ function isResponseLike(value) {
161
202
  return false;
162
203
  }
163
204
  function isSvelteKitControlFlow(value) {
164
- if (isResponseLike(value))
165
- return false;
166
- if (typeof value === "object" && value !== null && "status" in value) {
167
- const status = value.status;
168
- return typeof status === "number";
169
- }
170
- return false;
205
+ return isHttpError(value) || isRedirect(value);
171
206
  }
172
207
  function loggingMiddleware(config = {}) {
173
- const { logBody = false, logResponse = false, redactFields = ["password", "token", "secret", "authorization", "apikey", "api_key", "creditcard", "credit_card"] } = config;
208
+ const { logBody = false, logResponse = false, redactFields = [
209
+ "password",
210
+ "token",
211
+ "secret",
212
+ "authorization",
213
+ "apikey",
214
+ "api_key",
215
+ "creditcard",
216
+ "credit_card"
217
+ ] } = config;
174
218
  return async (context, next) => {
175
219
  const { event, requestId } = context;
176
220
  const startTime = Date.now();
@@ -215,7 +259,7 @@ function redactObject(obj, fields) {
215
259
  return core.sanitize.sanitizeSensitiveFields(obj, { matcher: fields });
216
260
  }
217
261
  function permitsMemory() {
218
- return !core.module.requiresSharedState(process2.env);
262
+ return !core.module.requiresSharedState(process.env);
219
263
  }
220
264
  function createCacheRateLimitStore(backend, options) {
221
265
  if (!options.namespace || options.namespace.length > 128)
@@ -230,14 +274,14 @@ function createCacheRateLimitStore(backend, options) {
230
274
  for (let attempt = 0; attempt < 64; attempt++) {
231
275
  const read = await backend.kv.get(cacheKey);
232
276
  if (!read.success)
233
- throw new Error("Rate limit cache read failed");
277
+ throw new Error("Rate limit cache read failed", { cause: read.error });
234
278
  const old = read.data ?? void 0;
235
279
  if (old && (!Number.isSafeInteger(old.count) || old.count <= 0 || old.count >= Number.MAX_SAFE_INTEGER || !Number.isSafeInteger(old.resetAt)))
236
280
  throw new Error("Invalid rate limit state");
237
281
  const next = old ? { count: old.count + 1, resetAt: old.resetAt } : { count: 1, resetAt: Date.now() + windowMs };
238
282
  const written = await backend.kv.compareAndSwap(cacheKey, old, next, old ? { keepTtl: true } : { px: windowMs });
239
283
  if (!written.success)
240
- throw new Error("Rate limit cache commit failed");
284
+ throw new Error("Rate limit cache commit failed", { cause: written.error });
241
285
  if (written.data)
242
286
  return next;
243
287
  }
@@ -258,7 +302,12 @@ function clientKey(address) {
258
302
  if (!mapped)
259
303
  return normalized;
260
304
  const value = Number.parseInt(mapped[1], 16) * 65536 + Number.parseInt(mapped[2], 16);
261
- return [value >>> 24, value >>> 16 & 255, value >>> 8 & 255, value & 255].join(".");
305
+ return [
306
+ value >>> 24,
307
+ value >>> 16 & 255,
308
+ value >>> 8 & 255,
309
+ value & 255
310
+ ].join(".");
262
311
  }
263
312
  var MemoryRateLimitStore = class {
264
313
  scope = "memory";
@@ -331,37 +380,29 @@ function rateLimitMiddleware(config) {
331
380
  entry = await store.increment(keyGenerator(event), windowMs);
332
381
  if (!Number.isSafeInteger(entry.count) || entry.count <= 0 || !Number.isSafeInteger(entry.resetAt))
333
382
  throw new TypeError("Invalid atomic rate limit result");
334
- } catch {
335
- core.logger.error("Rate limit store unavailable", { requestId });
336
- return new Response(JSON.stringify({ success: false, error: { code: "RATE_LIMIT_UNAVAILABLE", message: kitM("kit_internalError") }, requestId }), { status: 503, headers: { "Content-Type": "application/json" } });
383
+ } catch (cause) {
384
+ return fromError({
385
+ ...HaiCommonError.SERVICE_UNAVAILABLE,
386
+ message: kitM("kit_internalError"),
387
+ cause
388
+ }, requestId);
337
389
  }
338
390
  const remaining = Math.max(0, maxRequests - entry.count);
339
391
  const resetTime = Math.ceil(entry.resetAt / 1e3);
340
392
  if (entry.count > maxRequests) {
341
- core.logger.warn("Rate limit exceeded", { requestId });
342
393
  if (onLimitReached) {
394
+ core.logger.warn("Rate limit exceeded", { requestId });
343
395
  return onLimitReached(event);
344
396
  }
345
- return new Response(
346
- JSON.stringify({
347
- success: false,
348
- error: {
349
- code: "RATE_LIMIT_EXCEEDED",
350
- message: kitM("kit_rateLimitExceeded")
351
- },
352
- requestId
353
- }),
354
- {
355
- status: 429,
356
- headers: {
357
- "Content-Type": "application/json",
358
- "X-RateLimit-Limit": String(maxRequests),
359
- "X-RateLimit-Remaining": "0",
360
- "X-RateLimit-Reset": String(resetTime),
361
- "Retry-After": String(Math.max(1, Math.ceil((entry.resetAt - now) / 1e3)))
362
- }
363
- }
364
- );
397
+ const response2 = fromError({
398
+ ...HaiCommonError.RATE_LIMIT_EXCEEDED,
399
+ message: kitM("kit_rateLimitExceeded")
400
+ }, requestId);
401
+ response2.headers.set("X-RateLimit-Limit", String(maxRequests));
402
+ response2.headers.set("X-RateLimit-Remaining", "0");
403
+ response2.headers.set("X-RateLimit-Reset", String(resetTime));
404
+ response2.headers.set("Retry-After", String(Math.max(1, Math.ceil((entry.resetAt - now) / 1e3))));
405
+ return response2;
365
406
  }
366
407
  const response = await next();
367
408
  response.headers.set("X-RateLimit-Limit", String(maxRequests));
@@ -370,10 +411,16 @@ function rateLimitMiddleware(config) {
370
411
  return response;
371
412
  };
372
413
  }
373
- var ENCRYPTED_PREFIX = "enc:";
414
+ var ENCRYPTED_PREFIX = "enc:v2:";
374
415
  function createEncryptedCookieProxy(cookies, config) {
375
416
  const { names, symmetric, encryptionKey } = config;
376
417
  const logger = core.logger.child({ module: "kit", scope: "cookie-proxy" });
418
+ if (!/^[\da-f]{32}$/i.test(encryptionKey))
419
+ throw new Error("Cookie encryption requires a 32-character hexadecimal key");
420
+ const keys = Buffer.from(hkdfSync("sha256", Buffer.from(encryptionKey, "hex"), Buffer.alloc(0), "hai:kit:cookie:v2", 48));
421
+ const cipherKey = keys.subarray(0, 16).toString("hex");
422
+ const macKey = keys.subarray(16);
423
+ const authenticate = (name, iv, ciphertext) => createHmac("sha256", macKey).update(JSON.stringify(["v2", name, iv, ciphertext])).digest();
377
424
  return new Proxy(cookies, {
378
425
  get(target, prop, receiver) {
379
426
  if (prop === "get") {
@@ -387,14 +434,17 @@ function createEncryptedCookieProxy(cookies, config) {
387
434
  }
388
435
  try {
389
436
  const ciphertext = raw.slice(ENCRYPTED_PREFIX.length);
390
- const separatorIndex = ciphertext.indexOf(":");
391
- if (separatorIndex === -1) {
437
+ const parts = ciphertext.split(":");
438
+ if (parts.length !== 3 || !/^[\da-f]{64}$/i.test(parts[2])) {
392
439
  logger.warn("Encrypted cookie has invalid format", { name });
393
440
  return void 0;
394
441
  }
395
- const iv = ciphertext.slice(0, separatorIndex);
396
- const encrypted = ciphertext.slice(separatorIndex + 1);
397
- const result = symmetric.decryptWithIV(encrypted, encryptionKey, iv);
442
+ const [iv, encrypted, signature] = parts;
443
+ if (!timingSafeEqual(authenticate(name, iv, encrypted), Buffer.from(signature, "hex"))) {
444
+ logger.warn("Cookie authentication failed", { name });
445
+ return void 0;
446
+ }
447
+ const result = symmetric.decryptWithIV(encrypted, cipherKey, iv);
398
448
  if (!result.success || typeof result.data !== "string") {
399
449
  logger.warn("Cookie decryption failed", { name });
400
450
  return void 0;
@@ -409,12 +459,13 @@ function createEncryptedCookieProxy(cookies, config) {
409
459
  if (prop === "set") {
410
460
  return (name, value, opts) => {
411
461
  if (names.has(name)) {
412
- const result = symmetric.encryptWithIV(value, encryptionKey);
462
+ const result = symmetric.encryptWithIV(value, cipherKey);
413
463
  if (!result.success || !result.data) {
414
464
  logger.error("Cookie encryption failed", { name });
415
465
  throw new Error("Cookie encryption failed");
416
466
  }
417
- value = `${ENCRYPTED_PREFIX}${result.data.iv}:${result.data.ciphertext}`;
467
+ const { iv, ciphertext } = result.data;
468
+ value = `${ENCRYPTED_PREFIX}${iv}:${ciphertext}:${authenticate(name, iv, ciphertext).toString("hex")}`;
418
469
  }
419
470
  return target.set(name, value, opts);
420
471
  };
@@ -475,7 +526,10 @@ function createHandle(config = {}) {
475
526
  maxRequests: rateLimitConfig.maxRequests ?? 100
476
527
  }));
477
528
  }
478
- const allMiddleware = [...builtinMiddleware, ...customMiddleware];
529
+ const allMiddleware = [
530
+ ...builtinMiddleware,
531
+ ...customMiddleware
532
+ ];
479
533
  const transportMiddleware = buildTransportMiddleware(cryptoConfig, checkAccess ? checkAccess.encryption : void 0);
480
534
  const cookieProxyConfig = buildCookieProxyConfig(cryptoConfig);
481
535
  return async ({ event, resolve }) => {
@@ -488,15 +542,23 @@ function createHandle(config = {}) {
488
542
  }
489
543
  const resolvedAddress = resolveIp(event.request, clientAddress);
490
544
  if (resolvedAddress !== clientAddress) {
491
- event.getClientAddress = () => {
492
- if (!resolvedAddress)
493
- throw new Error("Trusted client address is unavailable");
494
- return resolvedAddress;
545
+ event = {
546
+ ...event,
547
+ getClientAddress: () => {
548
+ if (!resolvedAddress)
549
+ throw new Error("Trusted client address is unavailable");
550
+ return resolvedAddress;
551
+ }
495
552
  };
496
553
  }
497
554
  clientAddress = resolvedAddress;
498
555
  const accessDecision = checkAccess ? checkAccess(event.url.pathname, event.request.method, clientAddress) : void 0;
499
- return core.context.run({ requestId, userId: void 0, scopeId: void 0, jobId: void 0 }, () => audit.withContext({
556
+ return core.context.run({
557
+ requestId,
558
+ userId: void 0,
559
+ scopeId: void 0,
560
+ jobId: void 0
561
+ }, () => audit.withContext({
500
562
  actor: null,
501
563
  requestId,
502
564
  traceId: requestId,
@@ -519,33 +581,49 @@ function createHandle(config = {}) {
519
581
  category: /\/(?:auth|iam|audit)(?:\/|$)/.test(resource) ? "system" : "business",
520
582
  outcome: guardDenied || [401, 403, 423, 429].includes(status) ? "denied" : requestFailed || status >= 400 ? "failure" : "success",
521
583
  details: { method: event.request.method, status }
522
- }, { read: ["GET", "HEAD", "OPTIONS"].includes(event.request.method) });
584
+ }, {
585
+ read: ["GET", "HEAD", "OPTIONS"].includes(event.request.method)
586
+ });
523
587
  if (!written.success)
524
588
  core.logger.error("Request audit failed", { requestId, resource, error: written.error });
525
589
  };
590
+ if (cookieProxyConfig) {
591
+ event = {
592
+ ...event,
593
+ cookies: createEncryptedCookieProxy(event.cookies, cookieProxyConfig)
594
+ };
595
+ }
526
596
  const context = {
527
597
  event,
528
598
  requestId
529
599
  };
530
600
  const locals = event.locals;
531
601
  locals.requestId = requestId;
532
- if (cookieProxyConfig) {
533
- const proxiedCookies = createEncryptedCookieProxy(event.cookies, cookieProxyConfig);
534
- Object.defineProperty(event, "cookies", {
535
- value: proxiedCookies,
536
- writable: true,
537
- configurable: true
538
- });
539
- }
540
602
  const runRequest = async () => {
541
603
  try {
542
604
  if (accessDecision && !accessDecision.allowed) {
543
605
  guardDenied = true;
544
- core.logger.info("Request access policy denied", { ruleId: accessDecision.ruleId, reason: accessDecision.reason, method: event.request.method, ipAddress: clientAddress });
545
- return Response.json({ success: false, error: { ...HaiCommonError.REQUEST_ACCESS_DENIED, message: core.i18n.coreM("core_requestAccessDenied"), traceId: requestId } }, { status: 403 });
606
+ core.logger.info("Request access policy denied", {
607
+ ruleId: accessDecision.ruleId,
608
+ reason: accessDecision.reason,
609
+ method: event.request.method,
610
+ ipAddress: clientAddress
611
+ });
612
+ return Response.json({
613
+ success: false,
614
+ error: {
615
+ ...HaiCommonError.REQUEST_ACCESS_DENIED,
616
+ message: core.i18n.coreM("core_requestAccessDenied"),
617
+ traceId: requestId
618
+ }
619
+ }, { status: 403 });
546
620
  }
547
621
  if (!transportMiddleware && event.request.method !== "OPTIONS" && (event.request.headers.has(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER) || event.request.headers.has(TRANSPORT_PROTOCOL.ENVELOPE_HEADER)) && checkAccess && checkAccess.encryption(event.url.pathname, event.request.method) === "disabled") {
548
- return Response.json(err({ ...HaiCommonError.VALIDATION_ERROR, message: kitM("kit_transportPlaintextRequired"), traceId: requestId }), { status: 400 });
622
+ return Response.json(err({
623
+ ...HaiCommonError.VALIDATION_ERROR,
624
+ message: kitM("kit_transportPlaintextRequired"),
625
+ traceId: requestId
626
+ }), { status: 400 });
549
627
  }
550
628
  if (a2aResolved) {
551
629
  const a2aResponse = await handleA2ARequest(event, requestId, a2aResolved);
@@ -576,20 +654,11 @@ function createHandle(config = {}) {
576
654
  headers: { Location: guardResult.redirect }
577
655
  });
578
656
  }
579
- return new Response(
580
- JSON.stringify({
581
- success: false,
582
- error: {
583
- code: "FORBIDDEN",
584
- message: guardResult.message ?? kitM("kit_accessDenied")
585
- },
586
- requestId
587
- }),
588
- {
589
- status: guardResult.status ?? 403,
590
- headers: { "Content-Type": "application/json" }
591
- }
592
- );
657
+ return fromError({
658
+ ...guardResult.status === 401 ? HaiCommonError.UNAUTHORIZED : HaiCommonError.FORBIDDEN,
659
+ message: guardResult.message ?? kitM("kit_accessDenied"),
660
+ httpStatus: guardResult.status ?? 403
661
+ }, requestId);
593
662
  }
594
663
  }
595
664
  const response2 = await executeMiddlewareChain(
@@ -606,25 +675,15 @@ function createHandle(config = {}) {
606
675
  throw error2;
607
676
  }
608
677
  requestFailed = true;
609
- core.logger.error("Request failed", { requestId, error: error2 });
610
678
  if (onError) {
679
+ core.logger.error("Request failed", { requestId, error: error2 });
611
680
  return onError(error2, event);
612
681
  }
613
- return new Response(
614
- JSON.stringify({
615
- success: false,
616
- error: {
617
- code: "INTERNAL_ERROR",
618
- message: core.error.formatMessage({ message: kitM("kit_internalError"), traceId: requestId }),
619
- traceId: requestId
620
- },
621
- requestId
622
- }),
623
- {
624
- status: 500,
625
- headers: { "Content-Type": "application/json" }
626
- }
627
- );
682
+ return fromError({
683
+ ...HaiCommonError.INTERNAL_ERROR,
684
+ message: kitM("kit_internalError"),
685
+ cause: error2
686
+ }, requestId);
628
687
  }
629
688
  };
630
689
  const keyExchange = cryptoConfig?.transport ? cryptoConfig.transport.keyExchangePath ?? "/api/_hai/key-exchange" : void 0;
@@ -708,16 +767,20 @@ function buildTransportMiddleware(cryptoConfig, encryption) {
708
767
  excludePaths: transportOpts.excludePaths,
709
768
  keyStore: transportOpts.keyStore,
710
769
  maxPlaintextBytes: transportOpts.maxPlaintextBytes,
770
+ maxFutureSkewSeconds: transportOpts.maxFutureSkewSeconds,
771
+ maxRequestAgeSeconds: transportOpts.maxRequestAgeSeconds,
711
772
  routePlaintextBytes: transportOpts.routePlaintextBytes
712
773
  }, encryption);
713
774
  }
714
775
  function buildCookieProxyConfig(cryptoConfig) {
715
776
  if (!cryptoConfig?.encryptedCookies?.length)
716
777
  return null;
717
- const key = cryptoConfig.cookieEncryptionKey ?? (typeof process !== "undefined" ? process.env?.HAI_KIT_COOKIE_KEY : void 0);
778
+ const key = cryptoConfig.cookieEncryptionKey ?? process.env.HAI_KIT_COOKIE_KEY;
718
779
  if (!key) {
719
780
  throw new Error("Cookie encryption requires crypto.cookieEncryptionKey or HAI_KIT_COOKIE_KEY");
720
781
  }
782
+ if (!/^[\da-f]{32}$/i.test(key))
783
+ throw new Error("Cookie encryption requires a 32-character hexadecimal key");
721
784
  return {
722
785
  names: new Set(cryptoConfig.encryptedCookies),
723
786
  symmetric: cryptoConfig.crypto.symmetric,
@@ -772,18 +835,13 @@ function handler(fn) {
772
835
  if (isSvelteKitControlFlow(error2)) {
773
836
  throw error2;
774
837
  }
775
- const normalizedError = error2 instanceof Error ? {
776
- name: error2.name,
777
- message: error2.message,
778
- stack: error2.stack,
779
- cause: error2.cause
780
- } : error2;
781
- core.logger.error("Request handler error", {
782
- error: normalizedError,
783
- path: event.url.pathname,
784
- method: event.request.method
838
+ return fromError({
839
+ ...HaiCommonError.INTERNAL_ERROR,
840
+ message: kitM("kit_internalError"),
841
+ // 由 Core 统一规范化原始异常,保留驱动码和 AggregateError 的子错误。
842
+ cause: error2,
843
+ ext: { path: event.url.pathname, method: event.request.method }
785
844
  });
786
- return internalError();
787
845
  }
788
846
  };
789
847
  }
@@ -821,14 +879,24 @@ async function validateForm(request, schema) {
821
879
  } else {
822
880
  return {
823
881
  valid: false,
824
- errors: [{ field: "_", message: kitM("kit_unsupportedContentType") }]
882
+ errors: [
883
+ {
884
+ field: "_",
885
+ message: kitM("kit_unsupportedContentType")
886
+ }
887
+ ]
825
888
  };
826
889
  }
827
890
  return validateParsedData(data, schema);
828
891
  } catch {
829
892
  return {
830
893
  valid: false,
831
- errors: [{ field: "_", message: kitM("kit_parseBodyFailed") }]
894
+ errors: [
895
+ {
896
+ field: "_",
897
+ message: kitM("kit_parseBodyFailed")
898
+ }
899
+ ]
832
900
  };
833
901
  }
834
902
  }
@@ -859,7 +927,20 @@ var PaginationQuerySchema = z.object({
859
927
  });
860
928
 
861
929
  // src/kit-auth-api.ts
862
- var authApiPublicPaths = ["/api/auth/session/close", "/api/auth/logout", "/api/auth/captcha", "/api/auth/config", "/api/auth/login", "/api/auth/login/ldap", "/api/auth/login/otp", "/api/auth/register", "/api/auth/otp/send", "/api/auth/password-reset/request", "/api/auth/password-reset/confirm", "/api/auth/password/renew"];
930
+ var authApiPublicPaths = [
931
+ "/api/auth/session/close",
932
+ "/api/auth/logout",
933
+ "/api/auth/captcha",
934
+ "/api/auth/config",
935
+ "/api/auth/login",
936
+ "/api/auth/login/ldap",
937
+ "/api/auth/login/otp",
938
+ "/api/auth/register",
939
+ "/api/auth/otp/send",
940
+ "/api/auth/password-reset/request",
941
+ "/api/auth/password-reset/confirm",
942
+ "/api/auth/password/renew"
943
+ ];
863
944
  function requestContext(event) {
864
945
  let ip;
865
946
  try {
@@ -867,7 +948,11 @@ function requestContext(event) {
867
948
  } catch {
868
949
  }
869
950
  const terminal = event.request.headers.get("x-hai-terminal");
870
- return { ip, userAgent: event.request.headers.get("user-agent") ?? void 0, terminalType: terminal === "app" || terminal === "desktop" || terminal === "api" ? terminal : "web" };
951
+ return {
952
+ ip,
953
+ userAgent: event.request.headers.get("user-agent") ?? void 0,
954
+ terminalType: terminal === "app" || terminal === "desktop" || terminal === "api" ? terminal : "web"
955
+ };
871
956
  }
872
957
  function createAuthApi(iam) {
873
958
  function response(result) {
@@ -930,18 +1015,33 @@ function createAuthApi(iam) {
930
1015
  };
931
1016
  }
932
1017
  function createFeedbackHandler(options) {
933
- const basePath = (options.basePath ?? "/api/feedback").replace(/\/+$/, "");
1018
+ const configuredPath = options.basePath ?? "/api/feedback";
1019
+ let pathEnd = configuredPath.length;
1020
+ while (pathEnd > 0 && configuredPath[pathEnd - 1] === "/")
1021
+ pathEnd--;
1022
+ const basePath = configuredPath.slice(0, pathEnd);
934
1023
  return async (event) => {
935
1024
  let actor;
936
1025
  try {
937
1026
  actor = await options.resolveContext(event);
938
1027
  } catch {
939
- return fromError({ ...HaiCommonError.INTERNAL_ERROR, message: kitM("kit_internalError") });
1028
+ return fromError({
1029
+ ...HaiCommonError.INTERNAL_ERROR,
1030
+ message: kitM("kit_internalError")
1031
+ });
1032
+ }
1033
+ if (!actor?.scopeId || !actor.userId) {
1034
+ return fromError({
1035
+ ...HaiCommonError.UNAUTHORIZED,
1036
+ message: kitM("kit_unauthorized")
1037
+ });
1038
+ }
1039
+ if (options.feedback.isInitialized === false) {
1040
+ return fromError({
1041
+ ...HaiCommonError.SERVICE_UNAVAILABLE,
1042
+ message: kitM("kit_feedbackUnavailable")
1043
+ });
940
1044
  }
941
- if (!actor?.scopeId || !actor.userId)
942
- return fromError({ ...HaiCommonError.UNAUTHORIZED, message: kitM("kit_unauthorized") });
943
- if (options.feedback.isInitialized === false)
944
- return fromError({ ...HaiCommonError.SERVICE_UNAVAILABLE, message: kitM("kit_feedbackUnavailable") });
945
1045
  const suffix = event.url.pathname.startsWith(`${basePath}/`) ? event.url.pathname.slice(basePath.length + 1) : "";
946
1046
  let parts;
947
1047
  try {
@@ -951,8 +1051,12 @@ function createFeedbackHandler(options) {
951
1051
  }
952
1052
  if (parts.length === 1 && parts[0] === "policy" && event.request.method === "GET")
953
1053
  return ok(options.feedback.budget);
954
- if (parts[0] !== "reports" || parts.length > 4)
955
- return fromError({ ...HaiCommonError.NOT_FOUND, message: core.i18n.coreM("core_errorNotFound") });
1054
+ if (parts[0] !== "reports" || parts.length > 4) {
1055
+ return fromError({
1056
+ ...HaiCommonError.NOT_FOUND,
1057
+ message: core.i18n.coreM("core_errorNotFound")
1058
+ });
1059
+ }
956
1060
  let body = {};
957
1061
  if (!["GET", "HEAD"].includes(event.request.method)) {
958
1062
  if (event.request.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "application/json")
@@ -968,7 +1072,11 @@ function createFeedbackHandler(options) {
968
1072
  const bodyRecord = body;
969
1073
  if (parts[1] && Object.hasOwn(bodyRecord, "id") && bodyRecord.id !== parts[1])
970
1074
  return invalid(400);
971
- const input = { ...Object.fromEntries(event.url.searchParams), ...bodyRecord, ...parts[1] ? { id: parts[1] } : {} };
1075
+ const input = {
1076
+ ...Object.fromEntries(event.url.searchParams),
1077
+ ...bodyRecord,
1078
+ ...parts[1] ? { id: parts[1] } : {}
1079
+ };
972
1080
  const method = event.request.method;
973
1081
  const service = options.feedback;
974
1082
  async function execute(schema, operation) {
@@ -979,7 +1087,10 @@ function createFeedbackHandler(options) {
979
1087
  const result = await core.context.run(actor, () => operation(parsed.data));
980
1088
  return result.success ? ok(result.data) : fromError(result.error);
981
1089
  } catch {
982
- return fromError({ ...HaiCommonError.INTERNAL_ERROR, message: kitM("kit_internalError") });
1090
+ return fromError({
1091
+ ...HaiCommonError.INTERNAL_ERROR,
1092
+ message: kitM("kit_internalError")
1093
+ });
983
1094
  }
984
1095
  }
985
1096
  if (parts.length === 1) {
@@ -1015,11 +1126,18 @@ function createFeedbackHandler(options) {
1015
1126
  Object.assign(input, { jobId: parts[3] });
1016
1127
  return execute(FeedbackExportQuerySchema, (value) => service.getExport(value, actor));
1017
1128
  }
1018
- return fromError({ ...HaiCommonError.NOT_FOUND, message: core.i18n.coreM("core_errorNotFound") });
1129
+ return fromError({
1130
+ ...HaiCommonError.NOT_FOUND,
1131
+ message: core.i18n.coreM("core_errorNotFound")
1132
+ });
1019
1133
  };
1020
1134
  }
1021
1135
  function invalid(status) {
1022
- return fromError({ ...HaiCommonError.INVALID_REQUEST, httpStatus: status, message: kitM("kit_validationFailed") });
1136
+ return fromError({
1137
+ ...HaiCommonError.INVALID_REQUEST,
1138
+ httpStatus: status,
1139
+ message: kitM("kit_validationFailed")
1140
+ });
1023
1141
  }
1024
1142
  async function readBoundedJson(request, maximum) {
1025
1143
  const reader = request.body?.getReader();
@@ -1153,7 +1271,6 @@ var kit = {
1153
1271
  setBrowserToken,
1154
1272
  /** 清除浏览器端 Access Token(客户端 logout 用) */
1155
1273
  clearBrowserToken
1156
- /** 创建浏览器端 Token 存储器(自定义 key 时使用) */
1157
1274
  },
1158
1275
  // ─── CRUD ───
1159
1276
  crud: {