@h-ai/kit 0.1.0-alpha.13 → 0.1.0-alpha.16

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/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { defineCrud } from './chunk-FRYJMRTP.js';
2
- export { defineCrud, resolveOptions, resolveText } from './chunk-FRYJMRTP.js';
3
- import { createHandleFetch, createTokenStore, clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, createKitClient, configureAuth, getAccessToken } from './chunk-GRYHRXVC.js';
1
+ import { defineCrud } from './chunk-KJUUEH7I.js';
2
+ export { KitConfigSchema, defineCrud, resolveKitConfig, resolveKitTransportConfig, resolveOptions, resolveText } from './chunk-KJUUEH7I.js';
3
+ import { createTokenStore, clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitClient, configureAuth, getAccessToken } from './chunk-EMSCTFJJ.js';
4
4
  import { resolveA2AConfig, handleA2ARequest } from './chunk-475WECWK.js';
5
- import { transportEncryptionMiddleware } from './chunk-XTZUGWBY.js';
6
- import { kitM, setAllModulesLocale } from './chunk-BRZK7V5O.js';
5
+ import { transportEncryptionMiddleware } from './chunk-BM7IP4W5.js';
6
+ import { kitM, setAllModulesLocale } from './chunk-MI65L22O.js';
7
7
  import { core } from '@h-ai/core';
8
8
  import { z } from 'zod';
9
9
 
@@ -52,86 +52,6 @@ function requirePermission(session, permission) {
52
52
  }
53
53
  }
54
54
 
55
- // src/kit-response.ts
56
- function ok(data, requestId) {
57
- const response = {
58
- success: true,
59
- data,
60
- requestId
61
- };
62
- return new Response(JSON.stringify(response), {
63
- status: 200,
64
- headers: { "Content-Type": "application/json" }
65
- });
66
- }
67
- function created(data, requestId) {
68
- const response = {
69
- success: true,
70
- data,
71
- requestId
72
- };
73
- return new Response(JSON.stringify(response), {
74
- status: 201,
75
- headers: { "Content-Type": "application/json" }
76
- });
77
- }
78
- function noContent() {
79
- return new Response(null, { status: 204 });
80
- }
81
- function error(code, message, status = 400, requestId, details) {
82
- const response = {
83
- success: false,
84
- error: {
85
- code,
86
- message,
87
- details
88
- },
89
- requestId
90
- };
91
- return new Response(JSON.stringify(response), {
92
- status,
93
- headers: { "Content-Type": "application/json" }
94
- });
95
- }
96
- function badRequest(message, requestId, details) {
97
- return error("BAD_REQUEST", message, 400, requestId, details);
98
- }
99
- function unauthorized(message, requestId) {
100
- return error("UNAUTHORIZED", message ?? kitM("kit_authRequired"), 401, requestId);
101
- }
102
- function forbidden(message, requestId) {
103
- return error("FORBIDDEN", message ?? kitM("kit_accessDenied"), 403, requestId);
104
- }
105
- function notFound(message, requestId) {
106
- return error("NOT_FOUND", message ?? kitM("kit_resourceNotFound"), 404, requestId);
107
- }
108
- function conflict(message, requestId) {
109
- return error("CONFLICT", message, 409, requestId);
110
- }
111
- function validationError(errors, requestId) {
112
- return error("VALIDATION_ERROR", kitM("kit_validationFailed"), 422, requestId, { errors });
113
- }
114
- function internalError(message, requestId) {
115
- return error("INTERNAL_ERROR", message ?? kitM("kit_internalError"), 500, requestId);
116
- }
117
- function redirect(url, status = 302) {
118
- return new Response(null, {
119
- status,
120
- headers: { Location: url }
121
- });
122
- }
123
- function fromResult(result, httpStatusMap, requestId) {
124
- if (result.success) {
125
- return ok(result.data, requestId);
126
- }
127
- const { code, message } = result.error;
128
- const status = httpStatusMap?.[code] ?? 400;
129
- return error(String(code), message, status, requestId);
130
- }
131
- function fromError(haiError, requestId) {
132
- return error(String(haiError.code), haiError.message, haiError.httpStatus ?? 400, requestId);
133
- }
134
-
135
55
  // src/kit-utils.ts
136
56
  function isResponseLike(value) {
137
57
  if (value instanceof Response)
@@ -150,63 +70,6 @@ function isSvelteKitControlFlow(value) {
150
70
  }
151
71
  return false;
152
72
  }
153
-
154
- // src/kit-handler.ts
155
- function handler(fn) {
156
- return async (event) => {
157
- try {
158
- return await fn(event);
159
- } catch (error2) {
160
- if (isResponseLike(error2)) {
161
- return error2;
162
- }
163
- if (isSvelteKitControlFlow(error2)) {
164
- throw error2;
165
- }
166
- const normalizedError = error2 instanceof Error ? {
167
- name: error2.name,
168
- message: error2.message,
169
- stack: error2.stack,
170
- cause: error2.cause
171
- } : error2;
172
- core.logger.error("Request handler error", {
173
- error: normalizedError,
174
- path: event.url.pathname,
175
- method: event.request.method
176
- });
177
- return internalError();
178
- }
179
- };
180
- }
181
-
182
- // src/kit-contract.ts
183
- function defineEndpoint(def) {
184
- return def;
185
- }
186
- function fromContract(endpoint, fn) {
187
- return handler(async (event) => {
188
- let raw;
189
- if (endpoint.method === "GET") {
190
- raw = Object.fromEntries(event.url.searchParams);
191
- } else {
192
- try {
193
- raw = await event.request.json();
194
- } catch {
195
- raw = {};
196
- }
197
- }
198
- const parsed = endpoint.input.safeParse(raw);
199
- if (!parsed.success) {
200
- const errors = parsed.error.issues.map((issue) => ({
201
- field: issue.path.join(".") || "_",
202
- message: issue.message
203
- }));
204
- return validationError(errors);
205
- }
206
- const result = await fn(parsed.data, event);
207
- return ok(result);
208
- });
209
- }
210
73
  function loggingMiddleware(config = {}) {
211
74
  const { logBody = false, logResponse = false, redactFields = ["password", "token", "secret", "authorization", "apikey", "api_key", "creditcard", "credit_card"] } = config;
212
75
  return async (context, next) => {
@@ -293,6 +156,18 @@ var MemoryRateLimitStore = class {
293
156
  this.cleanupTimer.unref();
294
157
  }
295
158
  }
159
+ /**
160
+ * 停止定期清理并释放定时器资源
161
+ *
162
+ * 调用后可再次 startCleanup 重启。进程退出 / 热重载 / 测试拆装场景必须调用以
163
+ * 避免资源泄漏。
164
+ */
165
+ stopCleanup() {
166
+ if (this.cleanupTimer) {
167
+ clearInterval(this.cleanupTimer);
168
+ this.cleanupTimer = null;
169
+ }
170
+ }
296
171
  get(key) {
297
172
  return this.store.get(key);
298
173
  }
@@ -450,6 +325,11 @@ function generateId(prefix) {
450
325
  const random = crypto.randomUUID().replace(/-/g, "").substring(0, 8);
451
326
  return `${prefix}_${timestamp}${random}`;
452
327
  }
328
+ function applyDefaultSecurityHeaders(response) {
329
+ response.headers.set("X-Content-Type-Options", "nosniff");
330
+ response.headers.set("X-Frame-Options", "DENY");
331
+ response.headers.set("Referrer-Policy", "no-referrer");
332
+ }
453
333
  function createHandle(config = {}) {
454
334
  const {
455
335
  auth: authConfig,
@@ -486,10 +366,14 @@ function createHandle(config = {}) {
486
366
  }));
487
367
  }
488
368
  const allMiddleware = [...builtinMiddleware, ...customMiddleware];
489
- const finalMiddleware = buildTransportMiddleware(allMiddleware, cryptoConfig);
369
+ const transportMiddleware = buildTransportMiddleware(cryptoConfig);
490
370
  const cookieProxyConfig = buildCookieProxyConfig(cryptoConfig);
491
371
  return async ({ event, resolve }) => {
492
372
  const requestId = generateId("req");
373
+ const context = {
374
+ event,
375
+ requestId
376
+ };
493
377
  const locals = event.locals;
494
378
  locals.requestId = requestId;
495
379
  if (cookieProxyConfig) {
@@ -500,83 +384,84 @@ function createHandle(config = {}) {
500
384
  configurable: true
501
385
  });
502
386
  }
503
- try {
504
- if (a2aResolved) {
505
- const a2aResponse = await handleA2ARequest(event, requestId, a2aResolved);
506
- if (a2aResponse)
507
- return a2aResponse;
508
- }
509
- let session;
510
- if (authConfig) {
511
- const token = getAccessToken(event.request, event.cookies);
512
- if (token) {
513
- session = await authConfig.verifyToken(token) ?? void 0;
514
- locals.session = session;
515
- if (session) {
516
- locals.accessToken = token;
517
- }
387
+ const runRequest = async () => {
388
+ try {
389
+ if (a2aResolved) {
390
+ const a2aResponse = await handleA2ARequest(event, requestId, a2aResolved);
391
+ if (a2aResponse)
392
+ return a2aResponse;
518
393
  }
519
- }
520
- for (const guardConfig of guards) {
521
- const guardResult = await executeGuard(guardConfig, event, session);
522
- if (!guardResult.allowed) {
523
- if (guardResult.redirect) {
524
- return new Response(null, {
525
- status: 302,
526
- headers: { Location: guardResult.redirect }
527
- });
394
+ let session;
395
+ if (authConfig) {
396
+ const token = getAccessToken(event.request, event.cookies);
397
+ if (token) {
398
+ session = await authConfig.verifyToken(token) ?? void 0;
399
+ locals.session = session;
400
+ if (session) {
401
+ locals.accessToken = token;
402
+ }
528
403
  }
529
- return new Response(
530
- JSON.stringify({
531
- success: false,
532
- error: {
533
- code: "FORBIDDEN",
534
- message: guardResult.message ?? kitM("kit_accessDenied")
535
- },
536
- requestId
537
- }),
538
- {
539
- status: guardResult.status ?? 403,
540
- headers: { "Content-Type": "application/json" }
404
+ }
405
+ context.session = session;
406
+ for (const guardConfig of guards) {
407
+ const guardResult = await executeGuard(guardConfig, event, session);
408
+ if (!guardResult.allowed) {
409
+ if (guardResult.redirect) {
410
+ return new Response(null, {
411
+ status: 302,
412
+ headers: { Location: guardResult.redirect }
413
+ });
541
414
  }
542
- );
415
+ return new Response(
416
+ JSON.stringify({
417
+ success: false,
418
+ error: {
419
+ code: "FORBIDDEN",
420
+ message: guardResult.message ?? kitM("kit_accessDenied")
421
+ },
422
+ requestId
423
+ }),
424
+ {
425
+ status: guardResult.status ?? 403,
426
+ headers: { "Content-Type": "application/json" }
427
+ }
428
+ );
429
+ }
543
430
  }
544
- }
545
- const context = {
546
- event,
547
- session,
548
- requestId
549
- };
550
- const response = await executeMiddlewareChain(
551
- finalMiddleware,
552
- context,
553
- () => resolve(event)
554
- );
555
- response.headers.set("X-Request-Id", requestId);
556
- return response;
557
- } catch (error2) {
558
- if (isSvelteKitControlFlow(error2)) {
559
- throw error2;
560
- }
561
- core.logger.error("Request failed", { requestId, error: error2 instanceof Error ? error2.message : error2 });
562
- if (onError) {
563
- return onError(error2, event);
564
- }
565
- return new Response(
566
- JSON.stringify({
567
- success: false,
568
- error: {
569
- code: "INTERNAL_ERROR",
570
- message: kitM("kit_internalError")
571
- },
572
- requestId
573
- }),
574
- {
575
- status: 500,
576
- headers: { "Content-Type": "application/json" }
431
+ const response2 = await executeMiddlewareChain(
432
+ allMiddleware,
433
+ context,
434
+ () => resolve(event)
435
+ );
436
+ return response2;
437
+ } catch (error2) {
438
+ if (isSvelteKitControlFlow(error2)) {
439
+ throw error2;
577
440
  }
578
- );
579
- }
441
+ core.logger.error("Request failed", { requestId, error: error2 instanceof Error ? error2.message : error2 });
442
+ if (onError) {
443
+ return onError(error2, event);
444
+ }
445
+ return new Response(
446
+ JSON.stringify({
447
+ success: false,
448
+ error: {
449
+ code: "INTERNAL_ERROR",
450
+ message: kitM("kit_internalError")
451
+ },
452
+ requestId
453
+ }),
454
+ {
455
+ status: 500,
456
+ headers: { "Content-Type": "application/json" }
457
+ }
458
+ );
459
+ }
460
+ };
461
+ const response = transportMiddleware ? await transportMiddleware(context, runRequest) : await runRequest();
462
+ applyDefaultSecurityHeaders(response);
463
+ response.headers.set("X-Request-Id", requestId);
464
+ return response;
580
465
  };
581
466
  }
582
467
  function buildAuthGuard(verifyToken, loginUrl) {
@@ -635,19 +520,19 @@ function matchPath(pathname, pattern) {
635
520
  }
636
521
  return pathname === pattern;
637
522
  }
638
- function buildTransportMiddleware(userMiddleware, cryptoConfig) {
523
+ function buildTransportMiddleware(cryptoConfig) {
639
524
  if (!cryptoConfig?.transport)
640
- return userMiddleware;
525
+ return null;
641
526
  const transportOpts = typeof cryptoConfig.transport === "object" ? cryptoConfig.transport : {};
642
- const transportMw = transportEncryptionMiddleware({
527
+ return transportEncryptionMiddleware({
643
528
  enabled: true,
644
529
  crypto: cryptoConfig.crypto,
645
530
  keyExchangePath: transportOpts.keyExchangePath,
646
531
  excludePaths: transportOpts.excludePaths,
647
532
  encryptResponse: transportOpts.encryptResponse,
533
+ maxClients: transportOpts.maxClients,
648
534
  requireEncryption: transportOpts.requireEncryption
649
535
  });
650
- return [transportMw, ...userMiddleware];
651
536
  }
652
537
  function buildCookieProxyConfig(cryptoConfig) {
653
538
  if (!cryptoConfig?.encryptedCookies?.length)
@@ -678,22 +563,136 @@ function sequence(...handles) {
678
563
  )(event);
679
564
  };
680
565
  }
681
- function extractZodIssues(error2) {
682
- const zodError = error2;
683
- return zodError.issues ?? zodError.errors ?? [];
566
+
567
+ // src/kit-response.ts
568
+ function ok(data, requestId) {
569
+ const response = {
570
+ success: true,
571
+ data,
572
+ requestId
573
+ };
574
+ return new Response(JSON.stringify(response), {
575
+ status: 200,
576
+ headers: { "Content-Type": "application/json" }
577
+ });
578
+ }
579
+ function created(data, requestId) {
580
+ const response = {
581
+ success: true,
582
+ data,
583
+ requestId
584
+ };
585
+ return new Response(JSON.stringify(response), {
586
+ status: 201,
587
+ headers: { "Content-Type": "application/json" }
588
+ });
589
+ }
590
+ function noContent() {
591
+ return new Response(null, { status: 204 });
592
+ }
593
+ function error(code, message, status = 400, requestId, details) {
594
+ const response = {
595
+ success: false,
596
+ error: {
597
+ code,
598
+ message,
599
+ details
600
+ },
601
+ requestId
602
+ };
603
+ return new Response(JSON.stringify(response), {
604
+ status,
605
+ headers: { "Content-Type": "application/json" }
606
+ });
607
+ }
608
+ function badRequest(message, requestId, details) {
609
+ return error("BAD_REQUEST", message, 400, requestId, details);
610
+ }
611
+ function unauthorized(message, requestId) {
612
+ return error("UNAUTHORIZED", message ?? kitM("kit_authRequired"), 401, requestId);
613
+ }
614
+ function forbidden(message, requestId) {
615
+ return error("FORBIDDEN", message ?? kitM("kit_accessDenied"), 403, requestId);
616
+ }
617
+ function notFound(message, requestId) {
618
+ return error("NOT_FOUND", message ?? kitM("kit_resourceNotFound"), 404, requestId);
619
+ }
620
+ function conflict(message, requestId) {
621
+ return error("CONFLICT", message, 409, requestId);
622
+ }
623
+ function validationError(errors, requestId) {
624
+ return error("VALIDATION_ERROR", kitM("kit_validationFailed"), 422, requestId, { errors });
625
+ }
626
+ function internalError(message, requestId) {
627
+ return error("INTERNAL_ERROR", message ?? kitM("kit_internalError"), 500, requestId);
628
+ }
629
+ function redirect(url, status = 302) {
630
+ return new Response(null, {
631
+ status,
632
+ headers: { Location: url }
633
+ });
684
634
  }
685
- function zodIssuesToFormErrors(issues) {
686
- return issues.map((issue) => ({
687
- field: issue.path.join("."),
688
- message: issue.message
689
- }));
635
+ function fromResult(result, httpStatusMap, requestId) {
636
+ if (result.success) {
637
+ return ok(result.data, requestId);
638
+ }
639
+ const { code, message } = result.error;
640
+ const status = httpStatusMap?.[code] ?? 400;
641
+ return error(String(code), message, status, requestId);
642
+ }
643
+ function fromError(haiError, requestId) {
644
+ return error(String(haiError.code), haiError.message, haiError.httpStatus ?? 400, requestId);
645
+ }
646
+
647
+ // src/kit-handler.ts
648
+ function handler(fn) {
649
+ return async (event) => {
650
+ try {
651
+ return await fn(event);
652
+ } catch (error2) {
653
+ if (isResponseLike(error2)) {
654
+ return error2;
655
+ }
656
+ if (isSvelteKitControlFlow(error2)) {
657
+ throw error2;
658
+ }
659
+ const normalizedError = error2 instanceof Error ? {
660
+ name: error2.name,
661
+ message: error2.message,
662
+ stack: error2.stack,
663
+ cause: error2.cause
664
+ } : error2;
665
+ core.logger.error("Request handler error", {
666
+ error: normalizedError,
667
+ path: event.url.pathname,
668
+ method: event.request.method
669
+ });
670
+ return internalError();
671
+ }
672
+ };
690
673
  }
691
- function createValidationResult(error2) {
674
+ var getKitZodMessage = core.zodValidation.createPrefixedZodMessageGetter(
675
+ "kit",
676
+ (messageKey, params) => kitM(messageKey, { params })
677
+ );
678
+ function validateParsedData(data, schema) {
679
+ const result = schema.safeParse(data);
680
+ if (result.success)
681
+ return { valid: true, data: result.data, errors: [] };
692
682
  return {
693
683
  valid: false,
694
- errors: zodIssuesToFormErrors(extractZodIssues(error2))
684
+ errors: core.zodValidation.mapZodErrorToFormErrors(result.error, getKitZodMessage)
695
685
  };
696
686
  }
687
+ function unwrapValidationResultOrThrow(result) {
688
+ if (result.valid && result.data !== void 0)
689
+ return result.data;
690
+ throw badRequest(
691
+ result.errors[0]?.message ?? kitM("kit_validationFailed"),
692
+ void 0,
693
+ { errors: result.errors }
694
+ );
695
+ }
697
696
  async function validateForm(request, schema) {
698
697
  try {
699
698
  const contentType = request.headers.get("content-type") ?? "";
@@ -709,11 +708,7 @@ async function validateForm(request, schema) {
709
708
  errors: [{ field: "_", message: kitM("kit_unsupportedContentType") }]
710
709
  };
711
710
  }
712
- const result = schema.safeParse(data);
713
- if (result.success) {
714
- return { valid: true, data: result.data, errors: [] };
715
- }
716
- return createValidationResult(result.error);
711
+ return validateParsedData(data, schema);
717
712
  } catch {
718
713
  return {
719
714
  valid: false,
@@ -723,51 +718,19 @@ async function validateForm(request, schema) {
723
718
  }
724
719
  function validateQuery(url, schema) {
725
720
  const data = Object.fromEntries(url.searchParams);
726
- const result = schema.safeParse(data);
727
- if (result.success) {
728
- return { valid: true, data: result.data, errors: [] };
729
- }
730
- return createValidationResult(result.error);
721
+ return validateParsedData(data, schema);
731
722
  }
732
723
  function validateParams(params, schema) {
733
- const result = schema.safeParse(params);
734
- if (result.success) {
735
- return { valid: true, data: result.data, errors: [] };
736
- }
737
- return createValidationResult(result.error);
724
+ return validateParsedData(params, schema);
738
725
  }
739
726
  async function validateFormOrFail(request, schema) {
740
- const result = await validateForm(request, schema);
741
- if (!result.valid || !result.data) {
742
- throw badRequest(
743
- result.errors[0]?.message ?? kitM("kit_validationFailed"),
744
- void 0,
745
- { errors: result.errors }
746
- );
747
- }
748
- return result.data;
727
+ return unwrapValidationResultOrThrow(await validateForm(request, schema));
749
728
  }
750
729
  function validateQueryOrFail(url, schema) {
751
- const result = validateQuery(url, schema);
752
- if (!result.valid || !result.data) {
753
- throw badRequest(
754
- result.errors[0]?.message ?? kitM("kit_validationFailed"),
755
- void 0,
756
- { errors: result.errors }
757
- );
758
- }
759
- return result.data;
730
+ return unwrapValidationResultOrThrow(validateQuery(url, schema));
760
731
  }
761
732
  function validateParamsOrFail(params, schema) {
762
- const result = validateParams(params, schema);
763
- if (!result.valid || !result.data) {
764
- throw badRequest(
765
- result.errors[0]?.message ?? kitM("kit_validationFailed"),
766
- void 0,
767
- { errors: result.errors }
768
- );
769
- }
770
- return result.data;
733
+ return unwrapValidationResultOrThrow(validateParams(params, schema));
771
734
  }
772
735
  var IdParamSchema = z.object({
773
736
  id: z.string().min(1, kitM("kit_idRequired"))
@@ -788,8 +751,6 @@ var kit = {
788
751
  sequence,
789
752
  /** API Handler 包装器(自动错误边界) */
790
753
  handler,
791
- /** 基于 API 契约创建类型安全的路由 handler */
792
- fromContract,
793
754
  // ─── 路由守卫 ───
794
755
  guard: {
795
756
  /** 要求权限,不满足时 throw Response(SvelteKit 控制流) */
@@ -844,7 +805,14 @@ var kit = {
844
805
  // ─── 客户端工具 ───
845
806
  client: {
846
807
  /** 创建统一客户端(CSRF + 传输加密透明合并) */
847
- create: createKitClient
808
+ create: createKitClient,
809
+ /**
810
+ * 用解析后的 {@link KitConfig} 一键安装浏览器端传输加密
811
+ * (应用层推荐入口;内部预热 crypto 并调用 installBrowserTransportFetch)
812
+ */
813
+ installBrowserTransport,
814
+ /** 底层入口:直接传 transport 配置安装浏览器全局 fetch 包装 */
815
+ installBrowserTransportFetch
848
816
  },
849
817
  // ─── 认证工具 ───
850
818
  auth: {
@@ -865,9 +833,7 @@ var kit = {
865
833
  /** 清除浏览器端 Access Token(客户端 logout 用) */
866
834
  clearBrowserToken,
867
835
  /** 创建浏览器端 Token 存储器(自定义 key 时使用) */
868
- createTokenStore,
869
- /** 创建浏览器端同源请求自动附加 Authorization 的 HandleFetch */
870
- createHandleFetch
836
+ createTokenStore
871
837
  },
872
838
  // ─── CRUD ───
873
839
  crud: {
@@ -881,6 +847,6 @@ var kit = {
881
847
  }
882
848
  };
883
849
 
884
- export { IdParamSchema, PaginationQuerySchema, defineEndpoint, kit, matchPermission };
850
+ export { IdParamSchema, PaginationQuerySchema, kit, matchPermission };
885
851
  //# sourceMappingURL=index.js.map
886
852
  //# sourceMappingURL=index.js.map