@h-ai/kit 0.1.0-alpha.72 → 0.1.0-alpha.74

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,15 +1,16 @@
1
- import { defineCrud } from './chunk-Y2YUA3VR.js';
2
- export { KitConfigSchema, defineCrud, resolveKitConfig, resolveKitTransportConfig, resolveOptions, resolveText } from './chunk-Y2YUA3VR.js';
3
- import { clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient, configureAuth, getAccessToken } from './chunk-YX2IFLPE.js';
1
+ import { defineCrud } from './chunk-5O43CLW3.js';
2
+ export { KitConfigSchema, defineCrud, resolveKitConfig, resolveKitTransportConfig, resolveOptions, resolveText } from './chunk-5O43CLW3.js';
3
+ import { clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient, getAccessToken, configureAuth } from './chunk-6UCUIS35.js';
4
4
  import { resolveA2AConfig, handleA2ARequest } from './chunk-2PWGJCWX.js';
5
5
  import { transportEncryptionMiddleware } from './chunk-UTCS6FR7.js';
6
6
  import './chunk-XC7I2L3G.js';
7
7
  import { kitM, setAllModulesLocale } from './chunk-OVRZIDCD.js';
8
8
  import { core, HaiCommonError } from '@h-ai/core';
9
+ import { audit } from '@h-ai/audit';
9
10
  import { createHash } from 'crypto';
10
11
  import { isIP } from 'net';
11
12
  import process2 from 'process';
12
- import { IamConfirmPasswordResetInputSchema, IamRequestPasswordResetInputSchema, IamSendOtpInputSchema, IamRegisterInputSchema, IamOtpLoginInputSchema, IamLdapLoginInputSchema, IamLoginInputSchema, FeedbackSubmitInputSchema, FeedbackListInputSchema, FeedbackIdInputSchema, FeedbackEvidenceQuerySchema, FeedbackAppendEvidenceInputSchema, FeedbackSetStatusInputSchema, FeedbackRetryInputSchema, FeedbackCompleteInputSchema, FeedbackExportInputSchema, FeedbackUploadInputSchema, FeedbackAttachmentQuerySchema, FeedbackExportQuerySchema } from '@h-ai/api-contract';
13
+ 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';
13
14
  import { z } from 'zod';
14
15
 
15
16
  // src/guards/kit-permission.ts
@@ -56,6 +57,98 @@ function requirePermission(session, permission) {
56
57
  throw denied;
57
58
  }
58
59
  }
60
+ function ok(data, requestId) {
61
+ const response = {
62
+ success: true,
63
+ data,
64
+ requestId
65
+ };
66
+ return new Response(JSON.stringify(response), {
67
+ status: 200,
68
+ headers: { "Content-Type": "application/json" }
69
+ });
70
+ }
71
+ function created(data, requestId) {
72
+ const response = {
73
+ success: true,
74
+ data,
75
+ requestId
76
+ };
77
+ return new Response(JSON.stringify(response), {
78
+ status: 201,
79
+ headers: { "Content-Type": "application/json" }
80
+ });
81
+ }
82
+ function noContent() {
83
+ return new Response(null, { status: 204 });
84
+ }
85
+ function error(code, message, status = 400, requestId, details) {
86
+ const safe = core.error.toPublic({ code, message, httpStatus: status }, requestId);
87
+ core.logger.error("API request failed", { traceId: safe.traceId, error: { code, message, httpStatus: status, details } });
88
+ const response = {
89
+ success: false,
90
+ error: {
91
+ code,
92
+ message: safe.message,
93
+ traceId: safe.traceId,
94
+ details: status < 500 ? core.sanitize.sanitizeSensitiveFields(details) : void 0
95
+ },
96
+ requestId: requestId ?? core.context.get().requestId ?? safe.traceId
97
+ };
98
+ return new Response(JSON.stringify(response), {
99
+ status,
100
+ headers: { "Content-Type": "application/json", "X-Trace-Id": safe.traceId }
101
+ });
102
+ }
103
+ function badRequest(message, requestId, details) {
104
+ return error("BAD_REQUEST", message, 400, requestId, details);
105
+ }
106
+ function unauthorized(message, requestId) {
107
+ return error("UNAUTHORIZED", message ?? kitM("kit_authRequired"), 401, requestId);
108
+ }
109
+ function forbidden(message, requestId) {
110
+ return error("FORBIDDEN", message ?? kitM("kit_accessDenied"), 403, requestId);
111
+ }
112
+ function notFound(message, requestId) {
113
+ return error("NOT_FOUND", message ?? kitM("kit_resourceNotFound"), 404, requestId);
114
+ }
115
+ function conflict(message, requestId) {
116
+ return error("CONFLICT", message, 409, requestId);
117
+ }
118
+ function validationError(errors, requestId) {
119
+ return error("VALIDATION_ERROR", kitM("kit_validationFailed"), 422, requestId, { errors });
120
+ }
121
+ function internalError(message, requestId) {
122
+ return error("INTERNAL_ERROR", message ?? kitM("kit_internalError"), 500, requestId);
123
+ }
124
+ function redirect(url, status = 302) {
125
+ return new Response(null, {
126
+ status,
127
+ headers: { Location: url }
128
+ });
129
+ }
130
+ function fromResult(result, httpStatusMap, requestId) {
131
+ if (result.success) {
132
+ return ok(result.data, requestId);
133
+ }
134
+ const status = httpStatusMap?.[result.error.code] ?? (typeof result.error.httpStatus === "number" ? result.error.httpStatus : 400);
135
+ return fromError({ ...result.error, httpStatus: status }, requestId);
136
+ }
137
+ function fromError(haiError, requestId) {
138
+ const safe = core.error.toPublic(haiError, requestId);
139
+ core.logger.error("API operation failed", { traceId: safe.traceId, error: haiError });
140
+ return error(String(safe.code), safe.message, safe.httpStatus ?? 400, safe.traceId);
141
+ }
142
+
143
+ // src/guards/kit-sensitive.ts
144
+ async function requireSensitiveOperation(iam, event, operation) {
145
+ const policy = iam.publicConfig?.reauthentication;
146
+ if (!policy?.enabled)
147
+ return;
148
+ const checked = await iam.auth.checkSensitiveOperation(getAccessToken(event.request, event.cookies) ?? "", operation, event.request.headers.get("x-hai-reauthentication") ?? void 0);
149
+ if (!checked.success)
150
+ throw fromError(checked.error);
151
+ }
59
152
 
60
153
  // src/kit-utils.ts
61
154
  function isResponseLike(value) {
@@ -382,7 +475,36 @@ function createHandle(config = {}) {
382
475
  return async ({ event, resolve }) => {
383
476
  const suppliedRequestId = event.request.headers.get("x-request-id");
384
477
  const requestId = suppliedRequestId && /^[\w.:-]{1,128}$/.test(suppliedRequestId) ? suppliedRequestId : generateId("req");
385
- return core.context.run({ requestId, userId: void 0, scopeId: void 0, jobId: void 0 }, async () => {
478
+ let clientAddress;
479
+ try {
480
+ clientAddress = event.getClientAddress();
481
+ } catch {
482
+ }
483
+ return core.context.run({ requestId, userId: void 0, scopeId: void 0, jobId: void 0 }, () => audit.withContext({
484
+ actor: null,
485
+ requestId,
486
+ traceId: requestId,
487
+ scopeId: void 0,
488
+ ipAddress: clientAddress,
489
+ userAgent: event.request.headers.get("user-agent")?.slice(0, 4096)
490
+ }, async () => {
491
+ let actor = null;
492
+ let guardDenied = false;
493
+ let requestFailed = false;
494
+ const captureRequest = async (status) => {
495
+ const resource = event.route.id ?? "unmatched";
496
+ const written = await audit.capture({
497
+ action: "request.execute",
498
+ resource,
499
+ userId: actor?.id ?? null,
500
+ actorSnapshot: actor,
501
+ category: /\/(?:auth|iam|audit)(?:\/|$)/.test(resource) ? "system" : "business",
502
+ outcome: guardDenied || [401, 403, 423, 429].includes(status) ? "denied" : requestFailed || status >= 400 ? "failure" : "success",
503
+ details: { method: event.request.method, status }
504
+ }, { read: ["GET", "HEAD", "OPTIONS"].includes(event.request.method) });
505
+ if (!written.success)
506
+ core.logger.error("Request audit failed", { requestId, resource, error: written.error });
507
+ };
386
508
  const context = {
387
509
  event,
388
510
  requestId
@@ -416,10 +538,12 @@ function createHandle(config = {}) {
416
538
  }
417
539
  }
418
540
  context.session = session;
419
- return await core.context.run({ userId: session?.userId }, async () => {
541
+ actor = session ? { id: session.userId, username: session.username, roles: session.roles } : null;
542
+ return await audit.withContext({ actor }, () => core.context.run({ userId: session?.userId }, async () => {
420
543
  for (const guardConfig of guards) {
421
544
  const guardResult = await executeGuard(guardConfig, event, session);
422
545
  if (!guardResult.allowed) {
546
+ guardDenied = true;
423
547
  if (guardResult.redirect) {
424
548
  return new Response(null, {
425
549
  status: 302,
@@ -448,11 +572,14 @@ function createHandle(config = {}) {
448
572
  () => resolve(event)
449
573
  );
450
574
  return response2;
451
- });
575
+ }));
452
576
  } catch (error2) {
453
577
  if (isSvelteKitControlFlow(error2)) {
578
+ if (typeof error2 === "object" && error2 !== null && "status" in error2 && typeof error2.status === "number")
579
+ await captureRequest(error2.status);
454
580
  throw error2;
455
581
  }
582
+ requestFailed = true;
456
583
  core.logger.error("Request failed", { requestId, error: error2 });
457
584
  if (onError) {
458
585
  return onError(error2, event);
@@ -475,11 +602,12 @@ function createHandle(config = {}) {
475
602
  }
476
603
  };
477
604
  const response = transportMiddleware ? await transportMiddleware(context, runRequest) : await runRequest();
605
+ await captureRequest(response.status);
478
606
  applyDefaultSecurityHeaders(response);
479
607
  response.headers.set("X-Request-Id", requestId);
480
608
  response.headers.set("X-Trace-Id", requestId);
481
609
  return response;
482
- });
610
+ }));
483
611
  };
484
612
  }
485
613
  function buildAuthGuard(verifyToken, loginUrl) {
@@ -602,90 +730,6 @@ function sequence(...handles) {
602
730
  return applyHandle(0, event);
603
731
  };
604
732
  }
605
- function ok(data, requestId) {
606
- const response = {
607
- success: true,
608
- data,
609
- requestId
610
- };
611
- return new Response(JSON.stringify(response), {
612
- status: 200,
613
- headers: { "Content-Type": "application/json" }
614
- });
615
- }
616
- function created(data, requestId) {
617
- const response = {
618
- success: true,
619
- data,
620
- requestId
621
- };
622
- return new Response(JSON.stringify(response), {
623
- status: 201,
624
- headers: { "Content-Type": "application/json" }
625
- });
626
- }
627
- function noContent() {
628
- return new Response(null, { status: 204 });
629
- }
630
- function error(code, message, status = 400, requestId, details) {
631
- const safe = core.error.toPublic({ code, message, httpStatus: status }, requestId);
632
- core.logger.error("API request failed", { traceId: safe.traceId, error: { code, message, httpStatus: status, details } });
633
- const response = {
634
- success: false,
635
- error: {
636
- code,
637
- message: safe.message,
638
- traceId: safe.traceId,
639
- details: status < 500 ? core.sanitize.sanitizeSensitiveFields(details) : void 0
640
- },
641
- requestId: requestId ?? core.context.get().requestId ?? safe.traceId
642
- };
643
- return new Response(JSON.stringify(response), {
644
- status,
645
- headers: { "Content-Type": "application/json", "X-Trace-Id": safe.traceId }
646
- });
647
- }
648
- function badRequest(message, requestId, details) {
649
- return error("BAD_REQUEST", message, 400, requestId, details);
650
- }
651
- function unauthorized(message, requestId) {
652
- return error("UNAUTHORIZED", message ?? kitM("kit_authRequired"), 401, requestId);
653
- }
654
- function forbidden(message, requestId) {
655
- return error("FORBIDDEN", message ?? kitM("kit_accessDenied"), 403, requestId);
656
- }
657
- function notFound(message, requestId) {
658
- return error("NOT_FOUND", message ?? kitM("kit_resourceNotFound"), 404, requestId);
659
- }
660
- function conflict(message, requestId) {
661
- return error("CONFLICT", message, 409, requestId);
662
- }
663
- function validationError(errors, requestId) {
664
- return error("VALIDATION_ERROR", kitM("kit_validationFailed"), 422, requestId, { errors });
665
- }
666
- function internalError(message, requestId) {
667
- return error("INTERNAL_ERROR", message ?? kitM("kit_internalError"), 500, requestId);
668
- }
669
- function redirect(url, status = 302) {
670
- return new Response(null, {
671
- status,
672
- headers: { Location: url }
673
- });
674
- }
675
- function fromResult(result, httpStatusMap, requestId) {
676
- if (result.success) {
677
- return ok(result.data, requestId);
678
- }
679
- const status = httpStatusMap?.[result.error.code] ?? (typeof result.error.httpStatus === "number" ? result.error.httpStatus : 400);
680
- return fromError({ ...result.error, httpStatus: status }, requestId);
681
- }
682
- function fromError(haiError, requestId) {
683
- const safe = core.error.toPublic(haiError, requestId);
684
- core.logger.error("API operation failed", { traceId: safe.traceId, error: haiError });
685
- return error(String(safe.code), safe.message, safe.httpStatus ?? 400, safe.traceId);
686
- }
687
-
688
- // src/kit-handler.ts
689
733
  function handler(fn) {
690
734
  return async (event) => {
691
735
  try {
@@ -784,40 +828,69 @@ var PaginationQuerySchema = z.object({
784
828
  });
785
829
 
786
830
  // src/kit-auth-api.ts
787
- var authApiPublicPaths = ["/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"];
831
+ 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"];
832
+ function requestContext(event) {
833
+ let ip;
834
+ try {
835
+ ip = event.getClientAddress();
836
+ } catch {
837
+ }
838
+ const terminal = event.request.headers.get("x-hai-terminal");
839
+ return { ip, userAgent: event.request.headers.get("user-agent") ?? void 0, terminalType: terminal === "app" || terminal === "desktop" || terminal === "api" ? terminal : "web" };
840
+ }
788
841
  function createAuthApi(iam) {
789
842
  function response(result) {
790
843
  return result.success ? ok(result.data) : fromError(result.error);
791
844
  }
792
845
  return {
793
- publicConfig: handler(() => ok(iam.publicConfig)),
794
- login: handler(async ({ request, cookies }) => {
846
+ closeSession: handler(async ({ request, cookies }) => {
847
+ const input = await validateFormOrFail(request, IamLogoutInputSchema);
848
+ return response(await iam.auth.logout(input.accessToken ?? getAccessToken(request, cookies) ?? ""));
849
+ }),
850
+ createCaptcha: handler(async ({ request }) => {
851
+ const input = await validateFormOrFail(request, IamCreateCaptchaInputSchema);
852
+ return response(await iam.auth.createCaptcha(input));
853
+ }),
854
+ reauthenticate: handler(async ({ request, cookies }) => {
855
+ const input = await validateFormOrFail(request, IamReauthenticateInputSchema);
856
+ return response(await iam.auth.reauthenticate(getAccessToken(request, cookies) ?? "", input.password, input.operation));
857
+ }),
858
+ publicConfig: handler(async () => response(await iam.getPublicConfig())),
859
+ renewPassword: handler(async ({ request }) => {
860
+ const input = await validateFormOrFail(request, IamRenewPasswordInputSchema);
861
+ return response(await iam.user.renewPassword(input));
862
+ }),
863
+ login: handler(async (event) => {
864
+ const { request, cookies } = event;
795
865
  const input = await validateFormOrFail(request, IamLoginInputSchema);
796
- const result = await login(cookies, input);
866
+ const result = await login(cookies, input, requestContext(event));
797
867
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
798
868
  }),
799
- loginWithLdap: handler(async ({ request, cookies }) => {
869
+ loginWithLdap: handler(async (event) => {
870
+ const { request, cookies } = event;
800
871
  const input = await validateFormOrFail(request, IamLdapLoginInputSchema);
801
- const result = await loginWithLdap(cookies, input);
872
+ const result = await loginWithLdap(cookies, input, requestContext(event));
802
873
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
803
874
  }),
804
- loginWithOtp: handler(async ({ request, cookies }) => {
875
+ loginWithOtp: handler(async (event) => {
876
+ const { request, cookies } = event;
805
877
  const input = await validateFormOrFail(request, IamOtpLoginInputSchema);
806
- const result = await loginWithOtp(cookies, input);
878
+ const result = await loginWithOtp(cookies, input, requestContext(event));
807
879
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
808
880
  }),
809
- register: handler(async ({ request, cookies }) => {
881
+ register: handler(async (event) => {
882
+ const { request, cookies } = event;
810
883
  const input = await validateFormOrFail(request, IamRegisterInputSchema);
811
- const result = await registerAndLogin(cookies, input);
884
+ const result = await registerAndLogin(cookies, input, requestContext(event));
812
885
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
813
886
  }),
814
887
  sendOtp: handler(async ({ request }) => {
815
888
  const input = await validateFormOrFail(request, IamSendOtpInputSchema);
816
- return response(await iam.auth.sendOtp(input.identifier));
889
+ return response(await iam.auth.sendOtp(input.identifier, input));
817
890
  }),
818
891
  requestPasswordReset: handler(async ({ request }) => {
819
892
  const input = await validateFormOrFail(request, IamRequestPasswordResetInputSchema);
820
- return response(await iam.user.requestPasswordReset(input.identifier));
893
+ return response(await iam.user.requestPasswordReset(input.identifier, input));
821
894
  }),
822
895
  confirmPasswordReset: handler(async ({ request }) => {
823
896
  const input = await validateFormOrFail(request, IamConfirmPasswordResetInputSchema);
@@ -960,6 +1033,8 @@ var kit = {
960
1033
  handler,
961
1034
  // ─── 路由守卫 ───
962
1035
  guard: {
1036
+ /** 选定敏感操作要求单次再鉴别;先调用现有权限与资源守卫。 */
1037
+ requireSensitive: requireSensitiveOperation,
963
1038
  /** 要求权限,不满足时 throw Response(SvelteKit 控制流) */
964
1039
  require: requirePermission,
965
1040
  /** 检查会话是否具有指定权限(布尔) */