@h-ai/kit 0.1.0-alpha.71 → 0.1.0-alpha.73

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
1
  import { defineCrud } from './chunk-Y2YUA3VR.js';
2
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';
3
+ import { clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient, getAccessToken, configureAuth } from './chunk-3L5QSJ3E.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 || !policy.operations.includes(operation))
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,68 @@ 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
+ return { ip, userAgent: event.request.headers.get("user-agent") ?? void 0 };
839
+ }
788
840
  function createAuthApi(iam) {
789
841
  function response(result) {
790
842
  return result.success ? ok(result.data) : fromError(result.error);
791
843
  }
792
844
  return {
845
+ closeSession: handler(async ({ request, cookies }) => {
846
+ const input = await validateFormOrFail(request, IamLogoutInputSchema);
847
+ return response(await iam.auth.logout(input.accessToken ?? getAccessToken(request, cookies) ?? ""));
848
+ }),
849
+ createCaptcha: handler(async ({ request }) => {
850
+ const input = await validateFormOrFail(request, IamCreateCaptchaInputSchema);
851
+ return response(await iam.auth.createCaptcha(input));
852
+ }),
853
+ reauthenticate: handler(async ({ request, cookies }) => {
854
+ const input = await validateFormOrFail(request, IamReauthenticateInputSchema);
855
+ return response(await iam.auth.reauthenticate(getAccessToken(request, cookies) ?? "", input.password, input.operation));
856
+ }),
793
857
  publicConfig: handler(() => ok(iam.publicConfig)),
794
- login: handler(async ({ request, cookies }) => {
858
+ renewPassword: handler(async ({ request }) => {
859
+ const input = await validateFormOrFail(request, IamRenewPasswordInputSchema);
860
+ return response(await iam.user.renewPassword(input));
861
+ }),
862
+ login: handler(async (event) => {
863
+ const { request, cookies } = event;
795
864
  const input = await validateFormOrFail(request, IamLoginInputSchema);
796
- const result = await login(cookies, input);
865
+ const result = await login(cookies, input, requestContext(event));
797
866
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
798
867
  }),
799
- loginWithLdap: handler(async ({ request, cookies }) => {
868
+ loginWithLdap: handler(async (event) => {
869
+ const { request, cookies } = event;
800
870
  const input = await validateFormOrFail(request, IamLdapLoginInputSchema);
801
- const result = await loginWithLdap(cookies, input);
871
+ const result = await loginWithLdap(cookies, input, requestContext(event));
802
872
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
803
873
  }),
804
- loginWithOtp: handler(async ({ request, cookies }) => {
874
+ loginWithOtp: handler(async (event) => {
875
+ const { request, cookies } = event;
805
876
  const input = await validateFormOrFail(request, IamOtpLoginInputSchema);
806
- const result = await loginWithOtp(cookies, input);
877
+ const result = await loginWithOtp(cookies, input, requestContext(event));
807
878
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
808
879
  }),
809
- register: handler(async ({ request, cookies }) => {
880
+ register: handler(async (event) => {
881
+ const { request, cookies } = event;
810
882
  const input = await validateFormOrFail(request, IamRegisterInputSchema);
811
- const result = await registerAndLogin(cookies, input);
883
+ const result = await registerAndLogin(cookies, input, requestContext(event));
812
884
  return result.success ? ok({ user: result.data.user }) : fromError(result.error);
813
885
  }),
814
886
  sendOtp: handler(async ({ request }) => {
815
887
  const input = await validateFormOrFail(request, IamSendOtpInputSchema);
816
- return response(await iam.auth.sendOtp(input.identifier));
888
+ return response(await iam.auth.sendOtp(input.identifier, input));
817
889
  }),
818
890
  requestPasswordReset: handler(async ({ request }) => {
819
891
  const input = await validateFormOrFail(request, IamRequestPasswordResetInputSchema);
820
- return response(await iam.user.requestPasswordReset(input.identifier));
892
+ return response(await iam.user.requestPasswordReset(input.identifier, input));
821
893
  }),
822
894
  confirmPasswordReset: handler(async ({ request }) => {
823
895
  const input = await validateFormOrFail(request, IamConfirmPasswordResetInputSchema);
@@ -960,6 +1032,8 @@ var kit = {
960
1032
  handler,
961
1033
  // ─── 路由守卫 ───
962
1034
  guard: {
1035
+ /** 选定敏感操作要求单次再鉴别;先调用现有权限与资源守卫。 */
1036
+ requireSensitive: requireSensitiveOperation,
963
1037
  /** 要求权限,不满足时 throw Response(SvelteKit 控制流) */
964
1038
  require: requirePermission,
965
1039
  /** 检查会话是否具有指定权限(布尔) */