@nilejs/nile 0.0.6 → 0.0.7
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.cjs +569 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +153 -3
- package/dist/index.d.ts +153 -3
- package/dist/index.js +549 -56
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
|
+
// auth/jwt-handler.ts
|
|
2
|
+
import { verify } from "hono/jwt";
|
|
3
|
+
import { Err, Ok } from "slang-ts";
|
|
4
|
+
function extractUserId(claims) {
|
|
5
|
+
const value = claims.userId ?? claims.id ?? claims.sub;
|
|
6
|
+
return typeof value === "string" ? value : null;
|
|
7
|
+
}
|
|
8
|
+
function extractOrganizationId(claims) {
|
|
9
|
+
const value = claims.organizationId ?? claims.organization_id ?? claims.orgId;
|
|
10
|
+
return typeof value === "string" ? value : null;
|
|
11
|
+
}
|
|
12
|
+
function extractTokenFromHeader(headers, headerName) {
|
|
13
|
+
if (!headers) {
|
|
14
|
+
return Ok(null);
|
|
15
|
+
}
|
|
16
|
+
const authHeader = headers.get(headerName);
|
|
17
|
+
if (!authHeader) {
|
|
18
|
+
return Ok(null);
|
|
19
|
+
}
|
|
20
|
+
if (!authHeader.startsWith("Bearer ")) {
|
|
21
|
+
return Err("Authorization header must use Bearer scheme");
|
|
22
|
+
}
|
|
23
|
+
return Ok(authHeader.substring(7));
|
|
24
|
+
}
|
|
25
|
+
function extractTokenFromCookie(cookies, cookieName) {
|
|
26
|
+
if (!cookies) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return cookies[cookieName] ?? null;
|
|
30
|
+
}
|
|
31
|
+
function extractToken(context, config) {
|
|
32
|
+
const method = config.method ?? "header";
|
|
33
|
+
if (method === "header") {
|
|
34
|
+
const headerName = config.headerName ?? "authorization";
|
|
35
|
+
return extractTokenFromHeader(context.headers, headerName);
|
|
36
|
+
}
|
|
37
|
+
const cookieName = config.cookieName ?? "auth_token";
|
|
38
|
+
return Ok(extractTokenFromCookie(context.cookies, cookieName));
|
|
39
|
+
}
|
|
40
|
+
async function verifyJWT(context, config) {
|
|
41
|
+
const tokenResult = extractToken(context, config);
|
|
42
|
+
if (tokenResult.isErr) {
|
|
43
|
+
return Err(tokenResult.error);
|
|
44
|
+
}
|
|
45
|
+
const token = tokenResult.value;
|
|
46
|
+
if (!token) {
|
|
47
|
+
return Err(`No JWT token found in ${config.method ?? "header"}`);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const claims = await verify(token, config.secret, "HS256");
|
|
51
|
+
if (!claims) {
|
|
52
|
+
return Err("Invalid JWT token");
|
|
53
|
+
}
|
|
54
|
+
const userId = extractUserId(claims);
|
|
55
|
+
const organizationId = extractOrganizationId(
|
|
56
|
+
claims
|
|
57
|
+
);
|
|
58
|
+
if (!(userId && organizationId)) {
|
|
59
|
+
return Err("Missing userId or organizationId in JWT token");
|
|
60
|
+
}
|
|
61
|
+
return Ok({
|
|
62
|
+
userId,
|
|
63
|
+
organizationId,
|
|
64
|
+
claims
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : "JWT verification failed";
|
|
68
|
+
return Err(`JWT authentication failed: ${message}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
1
72
|
// engine/create-action.ts
|
|
2
73
|
function createAction(config) {
|
|
3
74
|
return config;
|
|
@@ -276,14 +347,14 @@ var createLogger = (appName, config) => {
|
|
|
276
347
|
import { safeTry as safeTry4 } from "slang-ts";
|
|
277
348
|
|
|
278
349
|
// engine/engine.ts
|
|
279
|
-
import { Err as
|
|
350
|
+
import { Err as Err4, Ok as Ok4 } from "slang-ts";
|
|
280
351
|
|
|
281
352
|
// utils/db/create-model.ts
|
|
282
353
|
import { count, desc, eq, lt } from "drizzle-orm";
|
|
283
|
-
import { Ok, safeTry } from "slang-ts";
|
|
354
|
+
import { Ok as Ok2, safeTry } from "slang-ts";
|
|
284
355
|
|
|
285
356
|
// utils/handle-error.ts
|
|
286
|
-
import { Err } from "slang-ts";
|
|
357
|
+
import { Err as Err2 } from "slang-ts";
|
|
287
358
|
var CALLER_LINE_REGEX = /at\s+(\S+)\s+/;
|
|
288
359
|
function inferCallerName() {
|
|
289
360
|
const _err = new Error("capture stack trace");
|
|
@@ -315,7 +386,7 @@ function handleError(params) {
|
|
|
315
386
|
message: params.message,
|
|
316
387
|
data: params.data
|
|
317
388
|
});
|
|
318
|
-
return
|
|
389
|
+
return Err2(`[${logId}] ${params.message}`);
|
|
319
390
|
}
|
|
320
391
|
|
|
321
392
|
// utils/db/create-transaction-variant.ts
|
|
@@ -437,7 +508,7 @@ function createModel(table, options) {
|
|
|
437
508
|
atFunction: `${name}.create`
|
|
438
509
|
});
|
|
439
510
|
}
|
|
440
|
-
return
|
|
511
|
+
return Ok2(row);
|
|
441
512
|
};
|
|
442
513
|
const update = async ({ id, data, dbx }) => {
|
|
443
514
|
const parsed = schemas.update.safeParse(data);
|
|
@@ -468,7 +539,7 @@ function createModel(table, options) {
|
|
|
468
539
|
atFunction: `${name}.update`
|
|
469
540
|
});
|
|
470
541
|
}
|
|
471
|
-
return
|
|
542
|
+
return Ok2(row);
|
|
472
543
|
};
|
|
473
544
|
const createTx = createTransactionVariant(
|
|
474
545
|
create
|
|
@@ -497,7 +568,7 @@ function createModel(table, options) {
|
|
|
497
568
|
atFunction: `${name}.findById`
|
|
498
569
|
});
|
|
499
570
|
}
|
|
500
|
-
return
|
|
571
|
+
return Ok2(row);
|
|
501
572
|
};
|
|
502
573
|
const deleteFn = async (id) => {
|
|
503
574
|
const db = getDb();
|
|
@@ -520,7 +591,7 @@ function createModel(table, options) {
|
|
|
520
591
|
atFunction: `${name}.delete`
|
|
521
592
|
});
|
|
522
593
|
}
|
|
523
|
-
return
|
|
594
|
+
return Ok2(row);
|
|
524
595
|
};
|
|
525
596
|
const findAll = async () => {
|
|
526
597
|
const db = getDb();
|
|
@@ -539,7 +610,7 @@ function createModel(table, options) {
|
|
|
539
610
|
atFunction: `${name}.findAll`
|
|
540
611
|
});
|
|
541
612
|
}
|
|
542
|
-
return
|
|
613
|
+
return Ok2(result.value ?? []);
|
|
543
614
|
};
|
|
544
615
|
const findOffsetPage = async (limit, offset) => {
|
|
545
616
|
const db = getDb();
|
|
@@ -568,7 +639,7 @@ function createModel(table, options) {
|
|
|
568
639
|
}
|
|
569
640
|
const items = itemsResult.value ?? [];
|
|
570
641
|
const total = countResult.value?.[0]?.total ?? 0;
|
|
571
|
-
return
|
|
642
|
+
return Ok2({
|
|
572
643
|
items,
|
|
573
644
|
total,
|
|
574
645
|
hasMore: offset + items.length < total
|
|
@@ -599,7 +670,7 @@ function createModel(table, options) {
|
|
|
599
670
|
const items = hasMore ? rows.slice(0, limit) : rows;
|
|
600
671
|
const lastItem = items.at(-1);
|
|
601
672
|
const nextCursor = lastItem ? String(lastItem[colName] ?? "") || null : null;
|
|
602
|
-
return
|
|
673
|
+
return Ok2({
|
|
603
674
|
items,
|
|
604
675
|
nextCursor,
|
|
605
676
|
hasMore
|
|
@@ -656,7 +727,7 @@ function createDiagnosticsLog(prefix, params) {
|
|
|
656
727
|
}
|
|
657
728
|
|
|
658
729
|
// engine/pipeline.ts
|
|
659
|
-
import { Err as
|
|
730
|
+
import { Err as Err3, Ok as Ok3, safeTry as safeTry2 } from "slang-ts";
|
|
660
731
|
import { prettifyError } from "zod";
|
|
661
732
|
async function runHook(hookDef, hookAction, input, nileContext) {
|
|
662
733
|
const result = await safeTry2(
|
|
@@ -681,7 +752,7 @@ async function processHooks(hooks, initialValue, getAction, nileContext, logTarg
|
|
|
681
752
|
log(errorMsg);
|
|
682
753
|
if (hookDef.isCritical) {
|
|
683
754
|
nileContext.setHookError(errorMsg);
|
|
684
|
-
return
|
|
755
|
+
return Err3(errorMsg);
|
|
685
756
|
}
|
|
686
757
|
continue;
|
|
687
758
|
}
|
|
@@ -700,57 +771,57 @@ async function processHooks(hooks, initialValue, getAction, nileContext, logTarg
|
|
|
700
771
|
);
|
|
701
772
|
if (hookDef.isCritical) {
|
|
702
773
|
nileContext.setHookError(errorMsg);
|
|
703
|
-
return
|
|
774
|
+
return Err3(errorMsg);
|
|
704
775
|
}
|
|
705
776
|
continue;
|
|
706
777
|
}
|
|
707
778
|
currentValue = result.value;
|
|
708
779
|
}
|
|
709
|
-
return
|
|
780
|
+
return Ok3(currentValue);
|
|
710
781
|
}
|
|
711
782
|
async function runGlobalBeforeHook(handler, nileContext, action, payload, log) {
|
|
712
783
|
if (!handler) {
|
|
713
|
-
return
|
|
784
|
+
return Ok3(true);
|
|
714
785
|
}
|
|
715
786
|
const result = await safeTry2(() => handler({ nileContext, action, payload }));
|
|
716
787
|
if (result.isErr) {
|
|
717
788
|
log(`Global before hook failed for ${action.name}`);
|
|
718
789
|
nileContext.setHookError(result.error);
|
|
719
|
-
return
|
|
790
|
+
return Err3(result.error);
|
|
720
791
|
}
|
|
721
|
-
return
|
|
792
|
+
return Ok3(true);
|
|
722
793
|
}
|
|
723
794
|
async function runGlobalAfterHook(handler, nileContext, action, payload, currentResult, log) {
|
|
724
795
|
if (!handler) {
|
|
725
|
-
return
|
|
796
|
+
return Ok3(currentResult);
|
|
726
797
|
}
|
|
727
798
|
const result = await safeTry2(
|
|
728
799
|
() => handler({
|
|
729
800
|
nileContext,
|
|
730
801
|
action,
|
|
731
802
|
payload,
|
|
732
|
-
result:
|
|
803
|
+
result: Ok3(currentResult)
|
|
733
804
|
})
|
|
734
805
|
);
|
|
735
806
|
if (result.isErr) {
|
|
736
807
|
log(`Global after hook failed for ${action.name}`);
|
|
737
808
|
nileContext.setHookError(result.error);
|
|
738
|
-
return
|
|
809
|
+
return Err3(result.error);
|
|
739
810
|
}
|
|
740
|
-
return
|
|
811
|
+
return Ok3(result.value);
|
|
741
812
|
}
|
|
742
813
|
function validatePayload(action, payload, nileContext, log) {
|
|
743
814
|
if (!action.validation) {
|
|
744
|
-
return
|
|
815
|
+
return Ok3(payload);
|
|
745
816
|
}
|
|
746
817
|
const parseResult = action.validation.safeParse(payload);
|
|
747
818
|
if (!parseResult.success) {
|
|
748
819
|
const validationError = prettifyError(parseResult.error);
|
|
749
820
|
log(`Validation failed for ${action.name}`, validationError);
|
|
750
821
|
nileContext.setHookError(validationError);
|
|
751
|
-
return
|
|
822
|
+
return Err3(`Validation failed: ${validationError}`);
|
|
752
823
|
}
|
|
753
|
-
return
|
|
824
|
+
return Ok3(parseResult.data);
|
|
754
825
|
}
|
|
755
826
|
async function runHandler(action, payload, nileContext, log) {
|
|
756
827
|
const result = await safeTry2(
|
|
@@ -759,13 +830,31 @@ async function runHandler(action, payload, nileContext, log) {
|
|
|
759
830
|
if (result.isErr) {
|
|
760
831
|
log(`Handler failed for ${action.name}`, result.error);
|
|
761
832
|
nileContext.setHookError(result.error);
|
|
762
|
-
return
|
|
833
|
+
return Err3(result.error);
|
|
763
834
|
}
|
|
764
835
|
nileContext.setHookOutput(result.value);
|
|
765
|
-
return
|
|
836
|
+
return Ok3(result.value);
|
|
766
837
|
}
|
|
767
838
|
|
|
768
839
|
// engine/engine.ts
|
|
840
|
+
async function authenticateAction(action, auth, authContext, nileContext, serviceName, actionName, log) {
|
|
841
|
+
if (!(action.isProtected && auth)) {
|
|
842
|
+
return Ok4(void 0);
|
|
843
|
+
}
|
|
844
|
+
if (!authContext) {
|
|
845
|
+
return Err4("Authentication required: no auth context provided");
|
|
846
|
+
}
|
|
847
|
+
const authResult = await verifyJWT(authContext, auth);
|
|
848
|
+
if (authResult.isErr) {
|
|
849
|
+
log(`Auth failed for ${serviceName}.${actionName}: ${authResult.error}`);
|
|
850
|
+
return Err4(authResult.error);
|
|
851
|
+
}
|
|
852
|
+
nileContext.authResult = authResult.value;
|
|
853
|
+
log(
|
|
854
|
+
`Auth OK for ${serviceName}.${actionName} (user: ${authResult.value.userId})`
|
|
855
|
+
);
|
|
856
|
+
return Ok4(void 0);
|
|
857
|
+
}
|
|
769
858
|
function createEngine(options) {
|
|
770
859
|
const { diagnostics, services, logger } = options;
|
|
771
860
|
const log = createDiagnosticsLog("Engine", {
|
|
@@ -776,11 +865,25 @@ function createEngine(options) {
|
|
|
776
865
|
const serviceActionsStore = {};
|
|
777
866
|
const actionStore = {};
|
|
778
867
|
const initStartTime = performance.now();
|
|
868
|
+
const seenServiceNames = /* @__PURE__ */ new Set();
|
|
779
869
|
for (const service of services) {
|
|
870
|
+
if (seenServiceNames.has(service.name)) {
|
|
871
|
+
throw new Error(
|
|
872
|
+
`Duplicate service name '${service.name}'. Service names must be unique.`
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
seenServiceNames.add(service.name);
|
|
876
|
+
const seenActionNames = /* @__PURE__ */ new Set();
|
|
780
877
|
const actionNames = [];
|
|
781
878
|
serviceActionsStore[service.name] = [];
|
|
782
879
|
actionStore[service.name] = {};
|
|
783
880
|
for (const action of service.actions) {
|
|
881
|
+
if (seenActionNames.has(action.name)) {
|
|
882
|
+
throw new Error(
|
|
883
|
+
`Duplicate action name '${action.name}' in service '${service.name}'. Action names must be unique within a service.`
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
seenActionNames.add(action.name);
|
|
784
887
|
actionNames.push(action.name);
|
|
785
888
|
serviceActionsStore[service.name]?.push({
|
|
786
889
|
name: action.name,
|
|
@@ -804,27 +907,39 @@ function createEngine(options) {
|
|
|
804
907
|
log(
|
|
805
908
|
`Initialized in ${performance.now() - initStartTime}ms. Loaded ${services.length} services.`
|
|
806
909
|
);
|
|
807
|
-
const getServices = () =>
|
|
910
|
+
const getServices = () => Ok4(serviceSummaries);
|
|
808
911
|
const getServiceActions = (serviceName) => {
|
|
809
912
|
const actions = serviceActionsStore[serviceName];
|
|
810
|
-
return actions ?
|
|
913
|
+
return actions ? Ok4(actions) : Err4(`Service '${serviceName}' not found`);
|
|
811
914
|
};
|
|
812
915
|
const getAction = (serviceName, actionName) => {
|
|
813
916
|
const serviceMap = actionStore[serviceName];
|
|
814
917
|
if (!serviceMap) {
|
|
815
|
-
return
|
|
918
|
+
return Err4(`Service '${serviceName}' not found`);
|
|
816
919
|
}
|
|
817
920
|
const action = serviceMap[actionName];
|
|
818
|
-
return action ?
|
|
921
|
+
return action ? Ok4(action) : Err4(`Action '${actionName}' not found in service '${serviceName}'`);
|
|
819
922
|
};
|
|
820
|
-
const executeAction = async (serviceName, actionName, payload, nileContext) => {
|
|
923
|
+
const executeAction = async (serviceName, actionName, payload, nileContext, authContext) => {
|
|
821
924
|
const { onBeforeActionHandler, onAfterActionHandler } = options;
|
|
822
925
|
const actionResult = getAction(serviceName, actionName);
|
|
823
926
|
if (actionResult.isErr) {
|
|
824
|
-
return
|
|
927
|
+
return Err4(actionResult.error);
|
|
825
928
|
}
|
|
826
929
|
const action = actionResult.value;
|
|
827
930
|
nileContext.resetHookContext(`${serviceName}.${actionName}`, payload);
|
|
931
|
+
const authStep = await authenticateAction(
|
|
932
|
+
action,
|
|
933
|
+
options.auth,
|
|
934
|
+
authContext,
|
|
935
|
+
nileContext,
|
|
936
|
+
serviceName,
|
|
937
|
+
actionName,
|
|
938
|
+
log
|
|
939
|
+
);
|
|
940
|
+
if (authStep.isErr) {
|
|
941
|
+
return Err4(authStep.error);
|
|
942
|
+
}
|
|
828
943
|
const globalBeforeResult = await runGlobalBeforeHook(
|
|
829
944
|
onBeforeActionHandler,
|
|
830
945
|
nileContext,
|
|
@@ -833,7 +948,7 @@ function createEngine(options) {
|
|
|
833
948
|
log
|
|
834
949
|
);
|
|
835
950
|
if (globalBeforeResult.isErr) {
|
|
836
|
-
return
|
|
951
|
+
return Err4(globalBeforeResult.error);
|
|
837
952
|
}
|
|
838
953
|
const beforeHooksResult = await processHooks(
|
|
839
954
|
action.hooks?.before ?? [],
|
|
@@ -844,7 +959,7 @@ function createEngine(options) {
|
|
|
844
959
|
log
|
|
845
960
|
);
|
|
846
961
|
if (beforeHooksResult.isErr) {
|
|
847
|
-
return
|
|
962
|
+
return Err4(beforeHooksResult.error);
|
|
848
963
|
}
|
|
849
964
|
const validationResult = validatePayload(
|
|
850
965
|
action,
|
|
@@ -853,7 +968,7 @@ function createEngine(options) {
|
|
|
853
968
|
log
|
|
854
969
|
);
|
|
855
970
|
if (validationResult.isErr) {
|
|
856
|
-
return
|
|
971
|
+
return Err4(validationResult.error);
|
|
857
972
|
}
|
|
858
973
|
const handlerResult = await runHandler(
|
|
859
974
|
action,
|
|
@@ -862,7 +977,7 @@ function createEngine(options) {
|
|
|
862
977
|
log
|
|
863
978
|
);
|
|
864
979
|
if (handlerResult.isErr) {
|
|
865
|
-
return
|
|
980
|
+
return Err4(handlerResult.error);
|
|
866
981
|
}
|
|
867
982
|
const afterHooksResult = await processHooks(
|
|
868
983
|
action.hooks?.after ?? [],
|
|
@@ -873,7 +988,7 @@ function createEngine(options) {
|
|
|
873
988
|
log
|
|
874
989
|
);
|
|
875
990
|
if (afterHooksResult.isErr) {
|
|
876
|
-
return
|
|
991
|
+
return Err4(afterHooksResult.error);
|
|
877
992
|
}
|
|
878
993
|
const globalAfterResult = await runGlobalAfterHook(
|
|
879
994
|
onAfterActionHandler,
|
|
@@ -884,12 +999,12 @@ function createEngine(options) {
|
|
|
884
999
|
log
|
|
885
1000
|
);
|
|
886
1001
|
if (globalAfterResult.isErr) {
|
|
887
|
-
return
|
|
1002
|
+
return Err4(globalAfterResult.error);
|
|
888
1003
|
}
|
|
889
|
-
return action.result?.pipeline ?
|
|
1004
|
+
return action.result?.pipeline ? Ok4({
|
|
890
1005
|
data: globalAfterResult.value,
|
|
891
1006
|
pipeline: nileContext.hookContext.log
|
|
892
|
-
}) :
|
|
1007
|
+
}) : Ok4(globalAfterResult.value);
|
|
893
1008
|
};
|
|
894
1009
|
return {
|
|
895
1010
|
getServices,
|
|
@@ -901,6 +1016,7 @@ function createEngine(options) {
|
|
|
901
1016
|
|
|
902
1017
|
// rest/rest.ts
|
|
903
1018
|
import { Hono } from "hono";
|
|
1019
|
+
import { getCookie } from "hono/cookie";
|
|
904
1020
|
import z2 from "zod";
|
|
905
1021
|
|
|
906
1022
|
// cors/cors.ts
|
|
@@ -986,7 +1102,7 @@ var evaluateResolver = (resolver, origin, c, defaultOpts) => {
|
|
|
986
1102
|
};
|
|
987
1103
|
|
|
988
1104
|
// rest/intent-handlers.ts
|
|
989
|
-
import { Ok as
|
|
1105
|
+
import { Ok as Ok5 } from "slang-ts";
|
|
990
1106
|
import z from "zod";
|
|
991
1107
|
function toExternalResponse(result, successMessage) {
|
|
992
1108
|
if (result.isOk) {
|
|
@@ -1013,7 +1129,7 @@ function handleExplore(engine, request) {
|
|
|
1013
1129
|
}
|
|
1014
1130
|
const act = actionResult.value;
|
|
1015
1131
|
return toExternalResponse(
|
|
1016
|
-
|
|
1132
|
+
Ok5({
|
|
1017
1133
|
name: act.name,
|
|
1018
1134
|
description: act.description,
|
|
1019
1135
|
isProtected: act.isProtected ?? false,
|
|
@@ -1024,7 +1140,7 @@ function handleExplore(engine, request) {
|
|
|
1024
1140
|
`Details for '${service}.${action}'`
|
|
1025
1141
|
);
|
|
1026
1142
|
}
|
|
1027
|
-
async function handleExecute(engine, request, nileContext) {
|
|
1143
|
+
async function handleExecute(engine, request, nileContext, authContext) {
|
|
1028
1144
|
const { service, action, payload } = request;
|
|
1029
1145
|
if (service === "*" || action === "*") {
|
|
1030
1146
|
return {
|
|
@@ -1037,7 +1153,8 @@ async function handleExecute(engine, request, nileContext) {
|
|
|
1037
1153
|
service,
|
|
1038
1154
|
action,
|
|
1039
1155
|
payload,
|
|
1040
|
-
nileContext
|
|
1156
|
+
nileContext,
|
|
1157
|
+
authContext
|
|
1041
1158
|
);
|
|
1042
1159
|
return toExternalResponse(result, `Action '${service}.${action}' executed`);
|
|
1043
1160
|
}
|
|
@@ -1060,7 +1177,7 @@ function handleSchema(engine, request) {
|
|
|
1060
1177
|
actionsResult.value.map((a) => a.name)
|
|
1061
1178
|
);
|
|
1062
1179
|
}
|
|
1063
|
-
return toExternalResponse(
|
|
1180
|
+
return toExternalResponse(Ok5(schemas), "All service schemas");
|
|
1064
1181
|
}
|
|
1065
1182
|
if (action === "*") {
|
|
1066
1183
|
const actionsResult = engine.getServiceActions(service);
|
|
@@ -1072,7 +1189,7 @@ function handleSchema(engine, request) {
|
|
|
1072
1189
|
service,
|
|
1073
1190
|
actionsResult.value.map((a) => a.name)
|
|
1074
1191
|
);
|
|
1075
|
-
return toExternalResponse(
|
|
1192
|
+
return toExternalResponse(Ok5(schemas), `Schemas for '${service}'`);
|
|
1076
1193
|
}
|
|
1077
1194
|
const actionResult = engine.getAction(service, action);
|
|
1078
1195
|
if (actionResult.isErr) {
|
|
@@ -1080,7 +1197,7 @@ function handleSchema(engine, request) {
|
|
|
1080
1197
|
}
|
|
1081
1198
|
const schema = extractActionSchema(actionResult.value);
|
|
1082
1199
|
return toExternalResponse(
|
|
1083
|
-
|
|
1200
|
+
Ok5({ [action]: schema }),
|
|
1084
1201
|
`Schema for '${service}.${action}'`
|
|
1085
1202
|
);
|
|
1086
1203
|
}
|
|
@@ -1114,7 +1231,7 @@ function safeTrySync(fn) {
|
|
|
1114
1231
|
}
|
|
1115
1232
|
var intentHandlers = {
|
|
1116
1233
|
explore: (engine, request) => handleExplore(engine, request),
|
|
1117
|
-
execute: (engine, request, nileContext) => handleExecute(engine, request, nileContext),
|
|
1234
|
+
execute: (engine, request, nileContext, authContext) => handleExecute(engine, request, nileContext, authContext),
|
|
1118
1235
|
schema: (engine, request) => handleSchema(engine, request)
|
|
1119
1236
|
};
|
|
1120
1237
|
|
|
@@ -1152,12 +1269,17 @@ function applyRateLimiting(app, config, log) {
|
|
|
1152
1269
|
`Rate limiting enabled: ${rateLimiting.limit ?? DEFAULT_RATE_LIMIT_MAX} requests per ${rateLimiting.windowMs ?? DEFAULT_RATE_LIMIT_WINDOW_MS}ms window`
|
|
1153
1270
|
);
|
|
1154
1271
|
}
|
|
1272
|
+
var STATIC_ADAPTER_MODULES = {
|
|
1273
|
+
bun: "hono/bun",
|
|
1274
|
+
node: "@hono/node-server/serve-static"
|
|
1275
|
+
};
|
|
1155
1276
|
function applyStaticServing(app, config, runtime, log) {
|
|
1156
1277
|
if (!config.enableStatic) {
|
|
1157
1278
|
return;
|
|
1158
1279
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1280
|
+
const adapterModule = STATIC_ADAPTER_MODULES[runtime];
|
|
1281
|
+
if (!adapterModule) {
|
|
1282
|
+
log(`Static file serving not supported for runtime: ${runtime}`);
|
|
1161
1283
|
return;
|
|
1162
1284
|
}
|
|
1163
1285
|
let cachedHandler = null;
|
|
@@ -1168,14 +1290,17 @@ function applyStaticServing(app, config, runtime, log) {
|
|
|
1168
1290
|
}
|
|
1169
1291
|
if (!cachedHandler) {
|
|
1170
1292
|
const importResult = await safeTry3(async () => {
|
|
1171
|
-
const mod = await import(
|
|
1293
|
+
const mod = await import(adapterModule);
|
|
1172
1294
|
return mod.serveStatic({
|
|
1173
1295
|
root: "./assets",
|
|
1174
1296
|
rewriteRequestPath: (path) => path.replace(ASSETS_REGEX, "")
|
|
1175
1297
|
});
|
|
1176
1298
|
});
|
|
1177
1299
|
if (importResult.isErr) {
|
|
1178
|
-
log(
|
|
1300
|
+
log(
|
|
1301
|
+
`Failed to load static file adapter for ${runtime}`,
|
|
1302
|
+
importResult.error
|
|
1303
|
+
);
|
|
1179
1304
|
importFailed = true;
|
|
1180
1305
|
return next();
|
|
1181
1306
|
}
|
|
@@ -1185,7 +1310,255 @@ function applyStaticServing(app, config, runtime, log) {
|
|
|
1185
1310
|
return cachedHandler(c, next);
|
|
1186
1311
|
}
|
|
1187
1312
|
});
|
|
1188
|
-
log(
|
|
1313
|
+
log(`Static file serving enabled at /assets/* (runtime: ${runtime})`);
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// rest/uploads/validate-files.ts
|
|
1317
|
+
var DEFAULT_MAX_FILES = 10;
|
|
1318
|
+
var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
1319
|
+
var DEFAULT_MIN_FILE_SIZE = 1;
|
|
1320
|
+
var DEFAULT_MAX_TOTAL_SIZE = 20 * 1024 * 1024;
|
|
1321
|
+
var DEFAULT_MAX_FILENAME_LENGTH = 128;
|
|
1322
|
+
var DEFAULT_ALLOWED_MIMES = ["image/png", "image/jpeg", "application/pdf"];
|
|
1323
|
+
var DEFAULT_ALLOWED_EXTENSIONS = [".png", ".jpg", ".jpeg", ".pdf"];
|
|
1324
|
+
var PASS = { status: true };
|
|
1325
|
+
function validateFilenameLength(files, maxLength) {
|
|
1326
|
+
const tooLong = files.filter((file) => file.name.length > maxLength);
|
|
1327
|
+
if (tooLong.length === 0) {
|
|
1328
|
+
return PASS;
|
|
1329
|
+
}
|
|
1330
|
+
return {
|
|
1331
|
+
status: false,
|
|
1332
|
+
message: "file name too long",
|
|
1333
|
+
data: {
|
|
1334
|
+
error_category: "validation",
|
|
1335
|
+
files: tooLong.map((f) => f.name),
|
|
1336
|
+
maxLength
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
function validateZeroByteFiles(files) {
|
|
1341
|
+
const emptyFiles = files.filter((file) => file.size === 0);
|
|
1342
|
+
if (emptyFiles.length === 0) {
|
|
1343
|
+
return PASS;
|
|
1344
|
+
}
|
|
1345
|
+
return {
|
|
1346
|
+
status: false,
|
|
1347
|
+
message: "empty file not allowed",
|
|
1348
|
+
data: {
|
|
1349
|
+
error_category: "validation",
|
|
1350
|
+
files: emptyFiles.map((f) => f.name)
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
function validateMinFileSize(files, minFileSize) {
|
|
1355
|
+
const tooSmall = files.filter((file) => file.size < minFileSize);
|
|
1356
|
+
if (tooSmall.length === 0) {
|
|
1357
|
+
return PASS;
|
|
1358
|
+
}
|
|
1359
|
+
return {
|
|
1360
|
+
status: false,
|
|
1361
|
+
message: "file too small",
|
|
1362
|
+
data: {
|
|
1363
|
+
error_category: "validation",
|
|
1364
|
+
limit: "minFileSize",
|
|
1365
|
+
min: minFileSize,
|
|
1366
|
+
files: tooSmall.map((f) => ({ name: f.name, size: f.size }))
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
function validateFileCount(files, maxFiles) {
|
|
1371
|
+
if (files.length <= maxFiles) {
|
|
1372
|
+
return PASS;
|
|
1373
|
+
}
|
|
1374
|
+
return {
|
|
1375
|
+
status: false,
|
|
1376
|
+
message: "upload limit exceeded",
|
|
1377
|
+
data: {
|
|
1378
|
+
error_category: "validation",
|
|
1379
|
+
limit: "maxFiles",
|
|
1380
|
+
max: maxFiles,
|
|
1381
|
+
received: files.length
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
function validateFileSize(files, maxFileSize) {
|
|
1386
|
+
const oversized = files.filter((file) => file.size > maxFileSize);
|
|
1387
|
+
if (oversized.length === 0) {
|
|
1388
|
+
return PASS;
|
|
1389
|
+
}
|
|
1390
|
+
return {
|
|
1391
|
+
status: false,
|
|
1392
|
+
message: "upload limit exceeded",
|
|
1393
|
+
data: {
|
|
1394
|
+
error_category: "validation",
|
|
1395
|
+
limit: "maxFileSize",
|
|
1396
|
+
max: maxFileSize,
|
|
1397
|
+
files: oversized.map((f) => ({ name: f.name, size: f.size }))
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1401
|
+
function validateTotalSize(files, maxTotalSize) {
|
|
1402
|
+
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
|
1403
|
+
if (totalSize <= maxTotalSize) {
|
|
1404
|
+
return PASS;
|
|
1405
|
+
}
|
|
1406
|
+
return {
|
|
1407
|
+
status: false,
|
|
1408
|
+
message: "upload limit exceeded",
|
|
1409
|
+
data: {
|
|
1410
|
+
error_category: "validation",
|
|
1411
|
+
limit: "maxTotalSize",
|
|
1412
|
+
max: maxTotalSize,
|
|
1413
|
+
total: totalSize
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
function validateAllowlist(files, allowedMimes, allowedExtensions) {
|
|
1418
|
+
const rejected = files.filter((file) => {
|
|
1419
|
+
const matchesMime = allowedMimes.includes(file.type);
|
|
1420
|
+
const matchesExt = allowedExtensions.some(
|
|
1421
|
+
(ext) => file.name.toLowerCase().endsWith(ext.toLowerCase())
|
|
1422
|
+
);
|
|
1423
|
+
return !(matchesMime && matchesExt);
|
|
1424
|
+
});
|
|
1425
|
+
if (rejected.length === 0) {
|
|
1426
|
+
return PASS;
|
|
1427
|
+
}
|
|
1428
|
+
return {
|
|
1429
|
+
status: false,
|
|
1430
|
+
message: "file type not allowed",
|
|
1431
|
+
data: {
|
|
1432
|
+
error_category: "validation",
|
|
1433
|
+
rejected: rejected.map((f) => ({ name: f.name, type: f.type })),
|
|
1434
|
+
allowed: { mimeTypes: allowedMimes, extensions: allowedExtensions }
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
function validateFiles(files, config) {
|
|
1439
|
+
if (files.length === 0) {
|
|
1440
|
+
return PASS;
|
|
1441
|
+
}
|
|
1442
|
+
const maxFiles = config.limits?.maxFiles ?? DEFAULT_MAX_FILES;
|
|
1443
|
+
const maxFileSize = config.limits?.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
1444
|
+
const minFileSize = config.limits?.minFileSize ?? DEFAULT_MIN_FILE_SIZE;
|
|
1445
|
+
const maxTotalSize = config.limits?.maxTotalSize ?? DEFAULT_MAX_TOTAL_SIZE;
|
|
1446
|
+
const maxFilenameLength = config.limits?.maxFilenameLength ?? DEFAULT_MAX_FILENAME_LENGTH;
|
|
1447
|
+
const allowedMimes = config.allow?.mimeTypes ?? DEFAULT_ALLOWED_MIMES;
|
|
1448
|
+
const allowedExtensions = config.allow?.extensions ?? DEFAULT_ALLOWED_EXTENSIONS;
|
|
1449
|
+
const checks = [
|
|
1450
|
+
validateFilenameLength(files, maxFilenameLength),
|
|
1451
|
+
validateZeroByteFiles(files),
|
|
1452
|
+
validateMinFileSize(files, minFileSize),
|
|
1453
|
+
validateFileCount(files, maxFiles),
|
|
1454
|
+
validateFileSize(files, maxFileSize),
|
|
1455
|
+
validateTotalSize(files, maxTotalSize),
|
|
1456
|
+
validateAllowlist(files, allowedMimes, allowedExtensions)
|
|
1457
|
+
];
|
|
1458
|
+
for (const check of checks) {
|
|
1459
|
+
if (!check.status) {
|
|
1460
|
+
return check;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
return PASS;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// rest/uploads/parse-formdata.ts
|
|
1467
|
+
async function parseBodyToStructured(c) {
|
|
1468
|
+
try {
|
|
1469
|
+
const body = await c.req.parseBody({ all: true });
|
|
1470
|
+
const fields = {};
|
|
1471
|
+
const files = {};
|
|
1472
|
+
const conflicts = [];
|
|
1473
|
+
for (const [key, value] of Object.entries(body)) {
|
|
1474
|
+
if (key === "action") {
|
|
1475
|
+
continue;
|
|
1476
|
+
}
|
|
1477
|
+
if (Array.isArray(value)) {
|
|
1478
|
+
const hasFiles = value.some((v) => v instanceof File);
|
|
1479
|
+
const hasStrings = value.some((v) => typeof v === "string");
|
|
1480
|
+
if (hasFiles && hasStrings) {
|
|
1481
|
+
conflicts.push(key);
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
if (hasFiles) {
|
|
1485
|
+
files[key] = value.filter((v) => v instanceof File);
|
|
1486
|
+
} else {
|
|
1487
|
+
fields[key] = value.map((v) => String(v));
|
|
1488
|
+
}
|
|
1489
|
+
} else if (value instanceof File) {
|
|
1490
|
+
files[key] = value;
|
|
1491
|
+
} else {
|
|
1492
|
+
fields[key] = String(value);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (conflicts.length > 0) {
|
|
1496
|
+
return {
|
|
1497
|
+
status: false,
|
|
1498
|
+
message: "mixed key types not allowed",
|
|
1499
|
+
errorData: {
|
|
1500
|
+
error_category: "validation",
|
|
1501
|
+
conflicts,
|
|
1502
|
+
hint: "Same key cannot be used for both files and fields"
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
return { status: true, data: { fields, files } };
|
|
1507
|
+
} catch (error) {
|
|
1508
|
+
return {
|
|
1509
|
+
status: false,
|
|
1510
|
+
message: "failed to parse request body",
|
|
1511
|
+
errorData: {
|
|
1512
|
+
error_category: "parsing",
|
|
1513
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
function enforceActionContentType(action, contentType, enforceContentType) {
|
|
1519
|
+
if (!(enforceContentType && action.isSpecial?.contentType)) {
|
|
1520
|
+
return { status: true };
|
|
1521
|
+
}
|
|
1522
|
+
const expected = action.isSpecial.contentType;
|
|
1523
|
+
const matches = contentType.toLowerCase().includes(expected.toLowerCase());
|
|
1524
|
+
if (!matches) {
|
|
1525
|
+
return {
|
|
1526
|
+
status: false,
|
|
1527
|
+
statusCode: 415,
|
|
1528
|
+
message: "unsupported content type",
|
|
1529
|
+
data: {
|
|
1530
|
+
error_category: "validation",
|
|
1531
|
+
expected,
|
|
1532
|
+
received: contentType
|
|
1533
|
+
}
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
return { status: true };
|
|
1537
|
+
}
|
|
1538
|
+
async function handleFormDataRequest(c, config, _uploadMode = "flat") {
|
|
1539
|
+
const parseResult = await parseBodyToStructured(c);
|
|
1540
|
+
if (!(parseResult.status && parseResult.data)) {
|
|
1541
|
+
return parseResult;
|
|
1542
|
+
}
|
|
1543
|
+
const payload = parseResult.data;
|
|
1544
|
+
const allFiles = [];
|
|
1545
|
+
for (const value of Object.values(payload.files)) {
|
|
1546
|
+
if (Array.isArray(value)) {
|
|
1547
|
+
allFiles.push(...value);
|
|
1548
|
+
} else {
|
|
1549
|
+
allFiles.push(value);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
const validationResult = validateFiles(allFiles, config);
|
|
1553
|
+
if (!validationResult.status) {
|
|
1554
|
+
return {
|
|
1555
|
+
status: false,
|
|
1556
|
+
message: validationResult.message,
|
|
1557
|
+
errorData: validationResult.data,
|
|
1558
|
+
statusCode: validationResult.statusCode
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
return { status: true, data: payload };
|
|
1189
1562
|
}
|
|
1190
1563
|
|
|
1191
1564
|
// rest/rest.ts
|
|
@@ -1195,6 +1568,87 @@ var externalRequestSchema = z2.object({
|
|
|
1195
1568
|
action: z2.string().min(1),
|
|
1196
1569
|
payload: z2.record(z2.string(), z2.unknown())
|
|
1197
1570
|
});
|
|
1571
|
+
var formDataRoutingSchema = z2.object({
|
|
1572
|
+
intent: z2.enum(["explore", "execute", "schema"]),
|
|
1573
|
+
service: z2.string().min(1),
|
|
1574
|
+
action: z2.string().min(1)
|
|
1575
|
+
});
|
|
1576
|
+
async function handleFormDataPath(c, config, engine, nileContext, authContext, log) {
|
|
1577
|
+
const rawBody = await c.req.parseBody({ all: true }).catch(() => null);
|
|
1578
|
+
if (!rawBody) {
|
|
1579
|
+
return c.json(
|
|
1580
|
+
{
|
|
1581
|
+
status: false,
|
|
1582
|
+
message: "Failed to parse multipart form data",
|
|
1583
|
+
data: {}
|
|
1584
|
+
},
|
|
1585
|
+
400
|
|
1586
|
+
);
|
|
1587
|
+
}
|
|
1588
|
+
const routing = formDataRoutingSchema.safeParse({
|
|
1589
|
+
intent: rawBody.intent,
|
|
1590
|
+
service: rawBody.service,
|
|
1591
|
+
action: rawBody.action
|
|
1592
|
+
});
|
|
1593
|
+
if (!routing.success) {
|
|
1594
|
+
return c.json(
|
|
1595
|
+
{
|
|
1596
|
+
status: false,
|
|
1597
|
+
message: "Form-data must include 'intent', 'service', and 'action' fields",
|
|
1598
|
+
data: { errors: routing.error.issues }
|
|
1599
|
+
},
|
|
1600
|
+
400
|
|
1601
|
+
);
|
|
1602
|
+
}
|
|
1603
|
+
const { intent, service, action } = routing.data;
|
|
1604
|
+
log(`${intent} -> ${service}.${action} (form-data)`);
|
|
1605
|
+
const actionResult = engine.getAction(service, action);
|
|
1606
|
+
if (actionResult.isOk && config.uploads?.enforceContentType) {
|
|
1607
|
+
const contentTypeCheck = enforceActionContentType(
|
|
1608
|
+
actionResult.value,
|
|
1609
|
+
"multipart/form-data",
|
|
1610
|
+
true
|
|
1611
|
+
);
|
|
1612
|
+
if (!contentTypeCheck.status) {
|
|
1613
|
+
return c.json(
|
|
1614
|
+
{
|
|
1615
|
+
status: false,
|
|
1616
|
+
message: contentTypeCheck.message ?? "Unsupported content type",
|
|
1617
|
+
data: contentTypeCheck.data ?? {}
|
|
1618
|
+
},
|
|
1619
|
+
contentTypeCheck.statusCode ?? 415
|
|
1620
|
+
);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
const uploadConfig = config.uploads ?? {};
|
|
1624
|
+
const uploadMode = actionResult.isOk ? actionResult.value.isSpecial?.uploadMode ?? "flat" : "flat";
|
|
1625
|
+
const uploadResult = await handleFormDataRequest(c, uploadConfig, uploadMode);
|
|
1626
|
+
if (!(uploadResult.status && uploadResult.data)) {
|
|
1627
|
+
return c.json(
|
|
1628
|
+
{
|
|
1629
|
+
status: false,
|
|
1630
|
+
message: uploadResult.message ?? "Upload validation failed",
|
|
1631
|
+
data: uploadResult.errorData ?? {}
|
|
1632
|
+
},
|
|
1633
|
+
uploadResult.statusCode ?? 400
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
const request = {
|
|
1637
|
+
intent,
|
|
1638
|
+
service,
|
|
1639
|
+
action,
|
|
1640
|
+
payload: uploadResult.data
|
|
1641
|
+
};
|
|
1642
|
+
const handler = intentHandlers[request.intent];
|
|
1643
|
+
const response = await handler(
|
|
1644
|
+
engine,
|
|
1645
|
+
request,
|
|
1646
|
+
nileContext,
|
|
1647
|
+
authContext
|
|
1648
|
+
);
|
|
1649
|
+
const statusCode = response.status ? 200 : 400;
|
|
1650
|
+
return c.json(response, statusCode);
|
|
1651
|
+
}
|
|
1198
1652
|
function createRestApp(params) {
|
|
1199
1653
|
const { config, engine, nileContext, serverName, runtime } = params;
|
|
1200
1654
|
const app = new Hono();
|
|
@@ -1207,6 +1661,22 @@ function createRestApp(params) {
|
|
|
1207
1661
|
applyStaticServing(app, config, runtime, log);
|
|
1208
1662
|
const servicesPath = `${config.baseUrl}/services`;
|
|
1209
1663
|
app.post(servicesPath, async (c) => {
|
|
1664
|
+
const contentType = c.req.header("content-type") ?? "";
|
|
1665
|
+
const isFormData = contentType.includes("multipart/form-data");
|
|
1666
|
+
const authContext = {
|
|
1667
|
+
headers: c.req.raw.headers,
|
|
1668
|
+
cookies: getCookie(c)
|
|
1669
|
+
};
|
|
1670
|
+
if (isFormData) {
|
|
1671
|
+
return handleFormDataPath(
|
|
1672
|
+
c,
|
|
1673
|
+
config,
|
|
1674
|
+
engine,
|
|
1675
|
+
nileContext,
|
|
1676
|
+
authContext,
|
|
1677
|
+
log
|
|
1678
|
+
);
|
|
1679
|
+
}
|
|
1210
1680
|
const body = await c.req.json().catch(() => null);
|
|
1211
1681
|
if (!body) {
|
|
1212
1682
|
return c.json(
|
|
@@ -1232,7 +1702,12 @@ function createRestApp(params) {
|
|
|
1232
1702
|
const request = parsed.data;
|
|
1233
1703
|
log(`${request.intent} -> ${request.service}.${request.action}`);
|
|
1234
1704
|
const handler = intentHandlers[request.intent];
|
|
1235
|
-
const response = await handler(
|
|
1705
|
+
const response = await handler(
|
|
1706
|
+
engine,
|
|
1707
|
+
request,
|
|
1708
|
+
nileContext,
|
|
1709
|
+
authContext
|
|
1710
|
+
);
|
|
1236
1711
|
const statusCode = response.status ? 200 : 400;
|
|
1237
1712
|
return c.json(response, statusCode);
|
|
1238
1713
|
});
|
|
@@ -1283,6 +1758,20 @@ function createNileContext(params) {
|
|
|
1283
1758
|
setSession(name, data) {
|
|
1284
1759
|
sessions[name] = data;
|
|
1285
1760
|
},
|
|
1761
|
+
authResult: void 0,
|
|
1762
|
+
getAuth() {
|
|
1763
|
+
return context.authResult;
|
|
1764
|
+
},
|
|
1765
|
+
getUser() {
|
|
1766
|
+
if (!context.authResult) {
|
|
1767
|
+
return void 0;
|
|
1768
|
+
}
|
|
1769
|
+
return {
|
|
1770
|
+
userId: context.authResult.userId,
|
|
1771
|
+
organizationId: context.authResult.organizationId,
|
|
1772
|
+
...context.authResult.claims
|
|
1773
|
+
};
|
|
1774
|
+
},
|
|
1286
1775
|
hookContext: {
|
|
1287
1776
|
actionName: "",
|
|
1288
1777
|
input: null,
|
|
@@ -1341,6 +1830,7 @@ function createNileServer(config) {
|
|
|
1341
1830
|
services: config.services,
|
|
1342
1831
|
diagnostics: config.diagnostics,
|
|
1343
1832
|
logger: config.resources?.logger,
|
|
1833
|
+
auth: config.auth,
|
|
1344
1834
|
onBeforeActionHandler: config.onBeforeActionHandler,
|
|
1345
1835
|
onAfterActionHandler: config.onAfterActionHandler
|
|
1346
1836
|
});
|
|
@@ -1406,6 +1896,9 @@ export {
|
|
|
1406
1896
|
getContext,
|
|
1407
1897
|
getLogs,
|
|
1408
1898
|
getZodSchema,
|
|
1409
|
-
handleError
|
|
1899
|
+
handleError,
|
|
1900
|
+
handleFormDataRequest,
|
|
1901
|
+
validateFiles,
|
|
1902
|
+
verifyJWT
|
|
1410
1903
|
};
|
|
1411
1904
|
//# sourceMappingURL=index.js.map
|