@shivaedev/server 0.9.1 → 0.9.3
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/CHANGELOG.md +178 -0
- package/dist/RedactionPolicy.d.ts +5 -1
- package/dist/RedactionPolicy.d.ts.map +1 -1
- package/dist/RedactionPolicy.js +3 -0
- package/dist/RedactionPolicy.js.map +1 -1
- package/dist/hostChanges.js +1 -1
- package/dist/hostChanges.js.map +1 -1
- package/dist/hostRpcRoutes.d.ts.map +1 -1
- package/dist/hostRpcRoutes.js +4 -4
- package/dist/hostRpcRoutes.js.map +1 -1
- package/dist/redactingDiagnostics.d.ts +2 -1
- package/dist/redactingDiagnostics.d.ts.map +1 -1
- package/dist/redactingDiagnostics.js +15 -3
- package/dist/redactingDiagnostics.js.map +1 -1
- package/dist/redactingRpcSerialization.d.ts +1 -1
- package/dist/redactingRpcSerialization.d.ts.map +1 -1
- package/dist/redactingRpcSerialization.js +3 -3
- package/dist/redactingRpcSerialization.js.map +1 -1
- package/dist/redactingTracer.d.ts +2 -2
- package/dist/redactingTracer.d.ts.map +1 -1
- package/dist/redactingTracer.js +17 -3
- package/dist/redactingTracer.js.map +1 -1
- package/dist/rpcRequestTracing.d.ts +5 -0
- package/dist/rpcRequestTracing.d.ts.map +1 -0
- package/dist/rpcRequestTracing.js +8 -0
- package/dist/rpcRequestTracing.js.map +1 -0
- package/dist/safeOtlpSerialization.d.ts.map +1 -1
- package/dist/safeOtlpSerialization.js +20 -15
- package/dist/safeOtlpSerialization.js.map +1 -1
- package/dist/schemaSensitiveAst.d.ts +7 -0
- package/dist/schemaSensitiveAst.d.ts.map +1 -0
- package/dist/schemaSensitiveAst.js +102 -0
- package/dist/schemaSensitiveAst.js.map +1 -0
- package/dist/schemaSensitiveKeys.d.ts +1 -0
- package/dist/schemaSensitiveKeys.d.ts.map +1 -1
- package/dist/schemaSensitiveKeys.js +27 -123
- package/dist/schemaSensitiveKeys.js.map +1 -1
- package/package.json +11 -9
- package/src/RedactionPolicy.ts +7 -1
- package/src/hostChanges.ts +4 -2
- package/src/hostRpcRoutes.ts +4 -4
- package/src/redactingDiagnostics.ts +15 -3
- package/src/redactingRpcSerialization.ts +3 -2
- package/src/redactingTracer.ts +18 -4
- package/src/rpcRequestTracing.ts +12 -0
- package/src/safeOtlpSerialization.ts +20 -15
- package/src/schemaSensitiveAst.ts +106 -0
- package/src/schemaSensitiveKeys.ts +28 -127
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safeOtlpSerialization.js","sourceRoot":"","sources":["../src/safeOtlpSerialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAqB,MAAM,gCAAgC,CAAC;AACzG,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"safeOtlpSerialization.js","sourceRoot":"","sources":["../src/safeOtlpSerialization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type SchemaAST } from "effect";
|
|
2
|
+
export declare function marked(ast: SchemaAST.AST, seen?: Set<SchemaAST.AST>): boolean;
|
|
3
|
+
export declare function collectEncodedKeys(ast: SchemaAST.AST, keys: Set<string>): void;
|
|
4
|
+
export declare function maskedValue(ast: SchemaAST.AST, keys: ReadonlySet<string>, seen?: Set<SchemaAST.AST>): boolean;
|
|
5
|
+
export declare function collect(ast: SchemaAST.AST, nodes: Set<SchemaAST.AST>, encodings?: boolean): void;
|
|
6
|
+
export declare function collectFieldKeys(properties: SchemaAST.Objects["propertySignatures"], keys: Set<string>, sensitive: (ast: SchemaAST.AST) => boolean): void;
|
|
7
|
+
//# sourceMappingURL=schemaSensitiveAst.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaSensitiveAst.d.ts","sourceRoot":"","sources":["../src/schemaSensitiveAst.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAsBnD,wBAAgB,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,qBAA2B,GAAG,OAAO,CAenF;AAOD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,QAcvE;AAOD,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,qBAA2B,GAAG,OAAO,CAmBnH;AACD,wBAAgB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,SAAS,UAAO,QAQtF;AAMD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,KAAK,OAAO,QAMlJ"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Predicate } from "effect";
|
|
2
|
+
import { isSensitiveKey } from "@shivaedev/errors/sensitive.ts";
|
|
3
|
+
function children(ast) {
|
|
4
|
+
switch (ast._tag) {
|
|
5
|
+
case "Objects":
|
|
6
|
+
return [...ast.propertySignatures.map((property) => property.type), ...ast.indexSignatures.flatMap((index) => [index.parameter, index.type])];
|
|
7
|
+
case "Arrays":
|
|
8
|
+
return [...ast.elements, ...ast.rest];
|
|
9
|
+
case "Union":
|
|
10
|
+
return ast.types;
|
|
11
|
+
case "Declaration":
|
|
12
|
+
return ast.typeParameters;
|
|
13
|
+
case "Suspend":
|
|
14
|
+
return [ast.thunk()];
|
|
15
|
+
default:
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function sensitiveCheck(check) {
|
|
20
|
+
return check.annotations?.sensitive === true || (check._tag === "FilterGroup" && check.checks.some(sensitiveCheck));
|
|
21
|
+
}
|
|
22
|
+
export function marked(ast, seen = new Set()) {
|
|
23
|
+
if (seen.has(ast)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
seen.add(ast);
|
|
27
|
+
if (ast.annotations?.sensitive === true
|
|
28
|
+
|| ast.context?.annotations?.sensitive === true
|
|
29
|
+
|| ast.checks?.some(sensitiveCheck)
|
|
30
|
+
|| (Predicate.hasProperty(ast.annotations?.representation, "id") && ast.annotations.representation.id === "effect/schema/Redacted")) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
|
|
34
|
+
return (ast.encoding?.some((link) => marked(link.to, seen)) ?? false) || nested.some((type) => marked(type, seen));
|
|
35
|
+
}
|
|
36
|
+
function containsSensitive(ast, keys) {
|
|
37
|
+
return (marked(ast)
|
|
38
|
+
|| propertiesOf(ast).some((property) => typeof property.name === "string" && (keys.has(property.name) || isSensitiveKey(property.name))));
|
|
39
|
+
}
|
|
40
|
+
export function collectEncodedKeys(ast, keys) {
|
|
41
|
+
let source = ast;
|
|
42
|
+
let sensitive = false;
|
|
43
|
+
for (const link of ast.encoding ?? []) {
|
|
44
|
+
sensitive ||= containsSensitive(source, keys);
|
|
45
|
+
if (sensitive) {
|
|
46
|
+
for (const property of propertiesOf(link.to)) {
|
|
47
|
+
if (typeof property.name === "string") {
|
|
48
|
+
keys.add(property.name);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
source = link.to;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function fixedOutput(ast) {
|
|
56
|
+
if (ast._tag === "Union") {
|
|
57
|
+
return ast.types.every(fixedOutput);
|
|
58
|
+
}
|
|
59
|
+
return ast._tag === "Objects" && ast.indexSignatures.length === 0;
|
|
60
|
+
}
|
|
61
|
+
export function maskedValue(ast, keys, seen = new Set()) {
|
|
62
|
+
if (seen.has(ast)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
seen.add(ast);
|
|
66
|
+
if (marked(ast)) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
let source = ast;
|
|
70
|
+
let sensitive = false;
|
|
71
|
+
for (const link of ast.encoding ?? []) {
|
|
72
|
+
sensitive ||= containsSensitive(source, keys);
|
|
73
|
+
if (sensitive && !fixedOutput(link.to)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
source = link.to;
|
|
77
|
+
}
|
|
78
|
+
const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
|
|
79
|
+
return nested.some((type) => maskedValue(type, keys, seen));
|
|
80
|
+
}
|
|
81
|
+
export function collect(ast, nodes, encodings = true) {
|
|
82
|
+
if (nodes.has(ast)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
nodes.add(ast);
|
|
86
|
+
for (const child of [...children(ast), ...(encodings ? (ast.encoding?.map((link) => link.to) ?? []) : [])]) {
|
|
87
|
+
collect(child, nodes, encodings);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function propertiesOf(ast) {
|
|
91
|
+
const nodes = new Set();
|
|
92
|
+
collect(ast, nodes, false);
|
|
93
|
+
return [...nodes].flatMap((node) => (node._tag === "Objects" ? node.propertySignatures : []));
|
|
94
|
+
}
|
|
95
|
+
export function collectFieldKeys(properties, keys, sensitive) {
|
|
96
|
+
for (const property of properties) {
|
|
97
|
+
if (typeof property.name === "string" && sensitive(property.type)) {
|
|
98
|
+
keys.add(property.name);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=schemaSensitiveAst.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaSensitiveAst.js","sourceRoot":"","sources":["../src/schemaSensitiveAst.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Rpc, type RpcGroup } from "effect/rpc";
|
|
2
2
|
export declare function schemaSensitiveKeys<R extends Rpc.Any>(group: RpcGroup.RpcGroup<R>, extra?: readonly string[]): ((key: string) => boolean) & {
|
|
3
|
+
forRpc: (tag: string | undefined) => (key: string) => boolean;
|
|
3
4
|
maskFailure: (tag: string | undefined, reason: "Fail" | "Die") => boolean;
|
|
4
5
|
};
|
|
5
6
|
//# sourceMappingURL=schemaSensitiveKeys.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaSensitiveKeys.d.ts","sourceRoot":"","sources":["../src/schemaSensitiveKeys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"schemaSensitiveKeys.d.ts","sourceRoot":"","sources":["../src/schemaSensitiveKeys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAgChD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,SAAS,MAAM,EAAO,UAOxF,MAAM;kBAIf,MAAM,GAAG,SAAS,WAJT,MAAM;uBAKV,MAAM,GAAG,SAAS,UAAU,MAAM,GAAG,KAAK;EAG9D"}
|
|
@@ -1,125 +1,18 @@
|
|
|
1
|
-
import { Predicate } from "effect";
|
|
2
1
|
import { Rpc } from "effect/rpc";
|
|
3
2
|
import { isSensitiveKey } from "@shivaedev/errors/sensitive.ts";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
case "Objects":
|
|
7
|
-
return [...ast.propertySignatures.map((property) => property.type), ...ast.indexSignatures.flatMap((index) => [index.parameter, index.type])];
|
|
8
|
-
case "Arrays":
|
|
9
|
-
return [...ast.elements, ...ast.rest];
|
|
10
|
-
case "Union":
|
|
11
|
-
return ast.types;
|
|
12
|
-
case "Declaration":
|
|
13
|
-
return ast.typeParameters;
|
|
14
|
-
case "Suspend":
|
|
15
|
-
return [ast.thunk()];
|
|
16
|
-
default:
|
|
17
|
-
return [];
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function sensitiveCheck(check) {
|
|
21
|
-
return check.annotations?.sensitive === true || (check._tag === "FilterGroup" && check.checks.some(sensitiveCheck));
|
|
22
|
-
}
|
|
23
|
-
function marked(ast, seen = new Set()) {
|
|
24
|
-
if (seen.has(ast)) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
seen.add(ast);
|
|
28
|
-
if (ast.annotations?.sensitive === true
|
|
29
|
-
|| ast.context?.annotations?.sensitive === true
|
|
30
|
-
|| ast.checks?.some(sensitiveCheck)
|
|
31
|
-
|| (Predicate.hasProperty(ast.annotations?.representation, "id") && ast.annotations.representation.id === "effect/schema/Redacted")) {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
|
|
35
|
-
return (ast.encoding?.some((link) => marked(link.to, seen)) ?? false) || nested.some((type) => marked(type, seen));
|
|
36
|
-
}
|
|
37
|
-
function containsSensitive(ast, keys) {
|
|
38
|
-
return (marked(ast)
|
|
39
|
-
|| propertiesOf(ast).some((property) => typeof property.name === "string" && (keys.has(property.name) || isSensitiveKey(property.name))));
|
|
40
|
-
}
|
|
41
|
-
function collectEncodedKeys(ast, keys) {
|
|
42
|
-
let source = ast;
|
|
43
|
-
let sensitive = false;
|
|
44
|
-
for (const link of ast.encoding ?? []) {
|
|
45
|
-
sensitive ||= containsSensitive(source, keys);
|
|
46
|
-
if (sensitive) {
|
|
47
|
-
for (const property of propertiesOf(link.to)) {
|
|
48
|
-
if (typeof property.name === "string") {
|
|
49
|
-
keys.add(property.name);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
source = link.to;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function fixedOutput(ast) {
|
|
57
|
-
if (ast._tag === "Union") {
|
|
58
|
-
return ast.types.every(fixedOutput);
|
|
59
|
-
}
|
|
60
|
-
return ast._tag === "Objects" && ast.indexSignatures.length === 0;
|
|
61
|
-
}
|
|
62
|
-
function maskedValue(ast, keys, seen = new Set()) {
|
|
63
|
-
if (seen.has(ast)) {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
seen.add(ast);
|
|
67
|
-
if (marked(ast)) {
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
let source = ast;
|
|
71
|
-
let sensitive = false;
|
|
72
|
-
for (const link of ast.encoding ?? []) {
|
|
73
|
-
sensitive ||= containsSensitive(source, keys);
|
|
74
|
-
if (sensitive && !fixedOutput(link.to)) {
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
source = link.to;
|
|
78
|
-
}
|
|
79
|
-
const nested = ast._tag === "Objects" ? ast.indexSignatures.map((index) => index.type) : children(ast);
|
|
80
|
-
return nested.some((type) => maskedValue(type, keys, seen));
|
|
81
|
-
}
|
|
82
|
-
function collect(ast, nodes, encodings = true) {
|
|
83
|
-
if (nodes.has(ast)) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
nodes.add(ast);
|
|
87
|
-
for (const child of [...children(ast), ...(encodings ? (ast.encoding?.map((link) => link.to) ?? []) : [])]) {
|
|
88
|
-
collect(child, nodes, encodings);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function propertiesOf(ast) {
|
|
92
|
-
const nodes = new Set();
|
|
93
|
-
collect(ast, nodes, false);
|
|
94
|
-
return [...nodes].flatMap((node) => (node._tag === "Objects" ? node.propertySignatures : []));
|
|
95
|
-
}
|
|
96
|
-
function collectFieldKeys(properties, keys, sensitive) {
|
|
97
|
-
for (const property of properties) {
|
|
98
|
-
if (typeof property.name === "string" && sensitive(property.type)) {
|
|
99
|
-
keys.add(property.name);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
export function schemaSensitiveKeys(group, extra = []) {
|
|
3
|
+
import { collect, collectEncodedKeys, collectFieldKeys, marked, maskedValue } from "#schemaSensitiveAst.ts";
|
|
4
|
+
function rpcSensitiveKeys(rpc, extra) {
|
|
104
5
|
const keys = new Set(extra);
|
|
105
6
|
const nodes = new Set();
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
rpc.successSchema,
|
|
116
|
-
rpc.errorSchema,
|
|
117
|
-
rpc.defectSchema,
|
|
118
|
-
...[...rpc.middlewares].map((m) => m.error),
|
|
119
|
-
];
|
|
120
|
-
for (const schema of schemas) {
|
|
121
|
-
collect(schema.ast, nodes);
|
|
122
|
-
}
|
|
7
|
+
const schemas = [
|
|
8
|
+
rpc.payloadSchema,
|
|
9
|
+
rpc.successSchema,
|
|
10
|
+
rpc.errorSchema,
|
|
11
|
+
rpc.defectSchema,
|
|
12
|
+
...[...rpc.middlewares].map((m) => m.error),
|
|
13
|
+
];
|
|
14
|
+
for (const schema of schemas) {
|
|
15
|
+
collect(schema.ast, nodes);
|
|
123
16
|
}
|
|
124
17
|
const properties = [...nodes].flatMap((ast) => (ast._tag === "Objects" ? ast.propertySignatures : []));
|
|
125
18
|
collectFieldKeys(properties, keys, marked);
|
|
@@ -131,13 +24,24 @@ export function schemaSensitiveKeys(group, extra = []) {
|
|
|
131
24
|
collectEncodedKeys(ast, keys);
|
|
132
25
|
}
|
|
133
26
|
} while (keys.size !== previousSize);
|
|
134
|
-
|
|
27
|
+
return Object.assign((key) => keys.has(key) || isSensitiveKey(key), {
|
|
135
28
|
die: maskedValue(rpc.defectSchema.ast, keys),
|
|
136
29
|
fail: [rpc.errorSchema, ...[...rpc.middlewares].map((m) => m.error)].some((schema) => maskedValue(schema.ast, keys)),
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function schemaSensitiveKeys(group, extra = []) {
|
|
33
|
+
const policies = new Map();
|
|
34
|
+
for (const rpc of group.requests.values()) {
|
|
35
|
+
if (Rpc.isRpc(rpc)) {
|
|
36
|
+
policies.set(rpc._tag, rpcSensitiveKeys(rpc, extra));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function sensitive(key) {
|
|
40
|
+
return extra.includes(key) || isSensitiveKey(key) || [...policies.values()].some((policy) => policy(key));
|
|
41
|
+
}
|
|
42
|
+
return Object.assign(sensitive, {
|
|
43
|
+
forRpc: (tag) => (tag === undefined ? sensitive : (policies.get(tag) ?? sensitive)),
|
|
44
|
+
maskFailure: (tag, reason) => [...policies].some(([method, policy]) => (tag === undefined || tag === method) && (reason === "Fail" ? policy.fail : policy.die)),
|
|
141
45
|
});
|
|
142
46
|
}
|
|
143
47
|
//# sourceMappingURL=schemaSensitiveKeys.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemaSensitiveKeys.js","sourceRoot":"","sources":["../src/schemaSensitiveKeys.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schemaSensitiveKeys.js","sourceRoot":"","sources":["../src/schemaSensitiveKeys.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "The Effect application host: HTTP and RPC serving, health, OTLP export, database and migrations, and development mode",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect"
|
|
@@ -41,14 +41,15 @@
|
|
|
41
41
|
"!src/**/*.spec.ts",
|
|
42
42
|
"!src/**/*.spec.tsx",
|
|
43
43
|
"!src/**/test-support",
|
|
44
|
+
"CHANGELOG.md",
|
|
44
45
|
"README.md"
|
|
45
46
|
],
|
|
46
47
|
"dependencies": {
|
|
47
48
|
"@shivaedev/changes": "0.6.0",
|
|
48
|
-
"@shivaedev/contract": "0.
|
|
49
|
-
"@shivaedev/errors": "0.1.
|
|
50
|
-
"@shivaedev/http": "0.3.
|
|
51
|
-
"@shivaedev/identity": "0.
|
|
49
|
+
"@shivaedev/contract": "0.26.0",
|
|
50
|
+
"@shivaedev/errors": "0.1.3",
|
|
51
|
+
"@shivaedev/http": "0.3.1",
|
|
52
|
+
"@shivaedev/identity": "0.10.0",
|
|
52
53
|
"@shivaedev/local-postgres": "0.7.0",
|
|
53
54
|
"@shivaedev/sql": "0.27.0"
|
|
54
55
|
},
|
|
@@ -56,12 +57,13 @@
|
|
|
56
57
|
"@effect/platform-node": "4.0.6",
|
|
57
58
|
"@effect/sql-pg": "4.0.6",
|
|
58
59
|
"@effect/vitest": "4.0.6",
|
|
59
|
-
"@shivaedev/access": "0.3.
|
|
60
|
-
"@shivaedev/
|
|
61
|
-
"@shivaedev/
|
|
60
|
+
"@shivaedev/access": "0.3.1",
|
|
61
|
+
"@shivaedev/admin": "0.12.2",
|
|
62
|
+
"@shivaedev/jobs": "0.24.0",
|
|
63
|
+
"@shivaedev/quality": "0.48.1",
|
|
62
64
|
"@shivaedev/test": "0.12.0",
|
|
63
65
|
"@shivaedev/test-sql": "0.15.0",
|
|
64
|
-
"@shivaedev/test-story": "0.
|
|
66
|
+
"@shivaedev/test-story": "0.27.0",
|
|
65
67
|
"@types/node": "24.19.2",
|
|
66
68
|
"@types/pg": "8.20.0",
|
|
67
69
|
"better-auth": "1.7.12",
|
package/src/RedactionPolicy.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import { isSensitiveKey, type SensitiveKey } from "@shivaedev/errors/sensitive.ts";
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export interface HostRedactionPolicy extends SensitiveKey {
|
|
5
|
+
readonly forRpc?: (tag: string | undefined) => SensitiveKey;
|
|
6
|
+
}
|
|
7
|
+
export function redactionForRpc(policy: HostRedactionPolicy, tag: unknown): SensitiveKey {
|
|
8
|
+
return policy.forRpc?.(typeof tag === "string" ? tag : undefined) ?? policy;
|
|
9
|
+
}
|
|
10
|
+
export const RedactionPolicy = Context.Reference<HostRedactionPolicy>("@shivaedev/server/RedactionPolicy", { defaultValue: () => isSensitiveKey });
|
package/src/hostChanges.ts
CHANGED
|
@@ -69,8 +69,10 @@ function authorizeSession<TSession extends SessionShape, E, R>(
|
|
|
69
69
|
}
|
|
70
70
|
return recheckSession(sessions, Headers.empty, tag).pipe(
|
|
71
71
|
Effect.map((current) => Option.isNone(viewer) || (Option.isSome(current) && current.value.user.id === viewer.value.id)),
|
|
72
|
-
Effect.
|
|
73
|
-
|
|
72
|
+
Effect.flatMap(
|
|
73
|
+
(allowed): Effect.Effect<boolean, E | Unauthorized, R> =>
|
|
74
|
+
allowed ? policy : Effect.fail(new Unauthorized({ message: "Authentication required" })),
|
|
75
|
+
),
|
|
74
76
|
);
|
|
75
77
|
}
|
|
76
78
|
|
package/src/hostRpcRoutes.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { type Rpc, type RpcGroup, RpcSerialization } from "effect/rpc";
|
|
|
5
5
|
import type { Authenticated, MaybeAuthenticated, RequestTracing } from "@shivaedev/identity/middleware.ts";
|
|
6
6
|
import { localRpcGuard } from "@shivaedev/identity/server/local.ts";
|
|
7
7
|
import { authenticatedLayer, maybeAuthenticatedLayer, type SessionShape } from "@shivaedev/identity/server/session.ts";
|
|
8
|
-
import { requestTracingLayer } from "@shivaedev/identity/server/tracing.ts";
|
|
9
8
|
import type { AppChanges } from "#appHost.ts";
|
|
10
9
|
import { boundedRpcRequest } from "#boundedRpcRequest.ts";
|
|
11
10
|
import { hostChanges } from "#hostChanges.ts";
|
|
@@ -13,6 +12,7 @@ import type { HostPolicy } from "#hostOptions.ts";
|
|
|
13
12
|
import { hostRpc, rpcCacheControl } from "#hostRpc.ts";
|
|
14
13
|
import type { hostTransport } from "#hostTransport.ts";
|
|
15
14
|
import { redactingRpcSerialization } from "#redactingRpcSerialization.ts";
|
|
15
|
+
import { rpcRequestTracing } from "#rpcRequestTracing.ts";
|
|
16
16
|
import type { schemaSensitiveKeys } from "#schemaSensitiveKeys.ts";
|
|
17
17
|
import { socketRpc } from "#socketRpc.ts";
|
|
18
18
|
|
|
@@ -28,11 +28,11 @@ export function hostRpcRoutes<TRpcs extends Rpc.Any, THandlers, TError, TRequire
|
|
|
28
28
|
) {
|
|
29
29
|
const middleware: Layer.Layer<RequestTracing> | Layer.Layer<Authenticated | MaybeAuthenticated | RequestTracing> =
|
|
30
30
|
options.policy === "loopback"
|
|
31
|
-
?
|
|
32
|
-
: Layer.mergeAll(authenticatedLayer(options.sessions), maybeAuthenticatedLayer(options.sessions),
|
|
31
|
+
? rpcRequestTracing(sensitive)
|
|
32
|
+
: Layer.mergeAll(authenticatedLayer(options.sessions), maybeAuthenticatedLayer(options.sessions), rpcRequestTracing(sensitive));
|
|
33
33
|
return HttpRouter.use((router) =>
|
|
34
34
|
Effect.gen(function* () {
|
|
35
|
-
const wire = redactingRpcSerialization(yield* RpcSerialization.RpcSerialization, sensitive, sensitive.maskFailure);
|
|
35
|
+
const wire = redactingRpcSerialization(yield* RpcSerialization.RpcSerialization, sensitive, sensitive.maskFailure, sensitive.forRpc);
|
|
36
36
|
const httpGroup = options.group.omit(...[...options.group.requests.keys()].filter((tag) => tag.endsWith(".$changes")));
|
|
37
37
|
const handler = yield* hostRpc(httpGroup).pipe(Effect.provideService(RpcSerialization.RpcSerialization, wire));
|
|
38
38
|
const guarded = localRpcGuard(handler, trustedProxy, nativeOrigins);
|
|
@@ -2,11 +2,21 @@ import { Context, Effect, ErrorReporter, Layer, Logger, References } from "effec
|
|
|
2
2
|
import { redact } from "@shivaedev/errors/redact.ts";
|
|
3
3
|
import { redactDiagnosticCause, redactingErrorReporter } from "@shivaedev/errors/redactCause.ts";
|
|
4
4
|
import type { SensitiveKey } from "@shivaedev/errors/sensitive.ts";
|
|
5
|
+
import { type HostRedactionPolicy, redactionForRpc } from "#RedactionPolicy.ts";
|
|
5
6
|
|
|
6
7
|
export function redactRecord(values: Readonly<Record<string, unknown>>, sensitive: SensitiveKey): Record<string, unknown> {
|
|
7
8
|
return Object.fromEntries(Object.entries(values).map(([key, value]) => [key, sensitive(key) ? "<redacted>" : redact(value, sensitive)]));
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
+
function requestErrorReporter(reporter: ErrorReporter.ErrorReporter, policy: HostRedactionPolicy): ErrorReporter.ErrorReporter {
|
|
11
|
+
return {
|
|
12
|
+
[ErrorReporter.TypeId]: ErrorReporter.TypeId,
|
|
13
|
+
report: (options) => {
|
|
14
|
+
const sensitive = redactionForRpc(policy, options.fiber.getRef(References.CurrentLogAnnotations)["rpc.method"]);
|
|
15
|
+
return redactingErrorReporter(reporter, sensitive).report(options);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function redactingDiagnostics(policy: HostRedactionPolicy) {
|
|
10
20
|
return Layer.effectContext(
|
|
11
21
|
Effect.gen(function* () {
|
|
12
22
|
const loggers = yield* Logger.CurrentLoggers;
|
|
@@ -15,7 +25,9 @@ export function redactingDiagnostics(sensitive: SensitiveKey) {
|
|
|
15
25
|
[...loggers].map((logger) =>
|
|
16
26
|
Logger.make((options) => {
|
|
17
27
|
const context = options.fiber.context;
|
|
18
|
-
const
|
|
28
|
+
const raw = options.fiber.getRef(References.CurrentLogAnnotations);
|
|
29
|
+
const sensitive = redactionForRpc(policy, raw["rpc.method"]);
|
|
30
|
+
const annotations = redactRecord(raw, sensitive);
|
|
19
31
|
options.fiber.setContext(Context.add(context, References.CurrentLogAnnotations, annotations));
|
|
20
32
|
try {
|
|
21
33
|
return logger.log({ ...options, cause: redactDiagnosticCause(options.cause, sensitive), message: redact(options.message, sensitive) });
|
|
@@ -26,7 +38,7 @@ export function redactingDiagnostics(sensitive: SensitiveKey) {
|
|
|
26
38
|
),
|
|
27
39
|
);
|
|
28
40
|
return Context.make(Logger.CurrentLoggers, safeLoggers).pipe(
|
|
29
|
-
Context.add(ErrorReporter.CurrentErrorReporters, new Set([...reporters].map((reporter) =>
|
|
41
|
+
Context.add(ErrorReporter.CurrentErrorReporters, new Set([...reporters].map((reporter) => requestErrorReporter(reporter, policy)))),
|
|
30
42
|
);
|
|
31
43
|
}),
|
|
32
44
|
);
|
|
@@ -10,9 +10,10 @@ export function redactingRpcSerialization(
|
|
|
10
10
|
wire: RpcSerialization.RpcSerialization["Service"],
|
|
11
11
|
sensitive: SensitiveKey,
|
|
12
12
|
maskFailure: (tag: string | undefined, reason: "Fail" | "Die") => boolean = () => false,
|
|
13
|
+
sensitiveForRpc: (tag: string | undefined) => SensitiveKey = () => sensitive,
|
|
13
14
|
): typeof wire {
|
|
14
15
|
function reason(value: unknown, tag: string | undefined): unknown {
|
|
15
|
-
const redacted = redactWire(value,
|
|
16
|
+
const redacted = redactWire(value, sensitiveForRpc(tag));
|
|
16
17
|
if (Predicate.isObjectOrArray(redacted)) {
|
|
17
18
|
if (Predicate.isTagged(value, "Fail") && maskFailure(tag, "Fail")) {
|
|
18
19
|
return { ...redacted, _tag: "Fail", error: REDACTED };
|
|
@@ -31,7 +32,7 @@ export function redactingRpcSerialization(
|
|
|
31
32
|
}
|
|
32
33
|
function exit(value: unknown, tag: string | undefined): unknown {
|
|
33
34
|
if (Predicate.isTagged(value, "Failure") && Predicate.hasProperty(value, "cause")) {
|
|
34
|
-
const cause = Array.isArray(value.cause) ? value.cause.map((item) => reason(item, tag)) : redactWire(value.cause,
|
|
35
|
+
const cause = Array.isArray(value.cause) ? value.cause.map((item) => reason(item, tag)) : redactWire(value.cause, sensitiveForRpc(tag));
|
|
35
36
|
return { ...value, cause };
|
|
36
37
|
}
|
|
37
38
|
return value;
|
package/src/redactingTracer.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import { Effect, Exit, Layer, Tracer } from "effect";
|
|
1
|
+
import { Effect, Exit, Layer, Option, Tracer } from "effect";
|
|
2
2
|
import { redact } from "@shivaedev/errors/redact.ts";
|
|
3
3
|
import { redactDiagnosticCause } from "@shivaedev/errors/redactCause.ts";
|
|
4
4
|
import { REDACTED, type SensitiveKey } from "@shivaedev/errors/sensitive.ts";
|
|
5
|
+
import { type HostRedactionPolicy, redactionForRpc } from "#RedactionPolicy.ts";
|
|
5
6
|
import { redactRecord } from "#redactingDiagnostics.ts";
|
|
6
7
|
|
|
7
8
|
function redactLinks(values: readonly Tracer.SpanLink[], sensitive: SensitiveKey) {
|
|
8
9
|
return values.map((link) => ({ ...link, attributes: redactRecord(link.attributes, sensitive) }));
|
|
9
10
|
}
|
|
10
|
-
function redactSpan(span: Tracer.Span,
|
|
11
|
+
function redactSpan(span: Tracer.Span, policy: HostRedactionPolicy) {
|
|
11
12
|
const end = span.end.bind(span);
|
|
12
13
|
const attribute = span.attribute.bind(span);
|
|
13
14
|
const event = span.event.bind(span);
|
|
14
15
|
const addLinks = span.addLinks.bind(span);
|
|
16
|
+
function sensitive(key: string) {
|
|
17
|
+
return redactionForRpc(policy, span.attributes.get("rpc.method"))(key);
|
|
18
|
+
}
|
|
15
19
|
return Object.assign(span, {
|
|
16
20
|
addLinks: (values: readonly Tracer.SpanLink[]) => addLinks(redactLinks(values, sensitive)),
|
|
17
21
|
attribute: (key: string, value: unknown) => attribute(key, sensitive(key) ? REDACTED : redact(value, sensitive)),
|
|
@@ -24,13 +28,23 @@ function redactSpan(span: Tracer.Span, sensitive: SensitiveKey) {
|
|
|
24
28
|
event: (name: string, time: bigint, attributes?: Record<string, unknown>) => event(name, time, attributes && redactRecord(attributes, sensitive)),
|
|
25
29
|
});
|
|
26
30
|
}
|
|
27
|
-
export function redactingTracer(sensitive:
|
|
31
|
+
export function redactingTracer(sensitive: HostRedactionPolicy) {
|
|
28
32
|
return Layer.effect(
|
|
29
33
|
Tracer.Tracer,
|
|
30
34
|
Effect.map(Tracer.Tracer, (tracer) =>
|
|
31
35
|
Tracer.make({
|
|
32
36
|
...tracer,
|
|
33
|
-
span: (options) =>
|
|
37
|
+
span: (options) => {
|
|
38
|
+
const method = Option.match(options.parent, {
|
|
39
|
+
onNone: () => undefined,
|
|
40
|
+
onSome: (parent) => (parent._tag === "Span" ? parent.attributes.get("rpc.method") : undefined),
|
|
41
|
+
});
|
|
42
|
+
const span = tracer.span({ ...options, links: redactLinks(options.links, redactionForRpc(sensitive, method)) });
|
|
43
|
+
if (typeof method === "string") {
|
|
44
|
+
span.attribute("rpc.method", method);
|
|
45
|
+
}
|
|
46
|
+
return redactSpan(span, sensitive);
|
|
47
|
+
},
|
|
34
48
|
}),
|
|
35
49
|
),
|
|
36
50
|
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Effect, Layer } from "effect";
|
|
2
|
+
import { RequestTracing } from "@shivaedev/identity/middleware.ts";
|
|
3
|
+
import { requestTracingLayer } from "@shivaedev/identity/server/tracing.ts";
|
|
4
|
+
import { type HostRedactionPolicy, redactionForRpc } from "#RedactionPolicy.ts";
|
|
5
|
+
|
|
6
|
+
export function rpcRequestTracing(sensitive: HostRedactionPolicy) {
|
|
7
|
+
return Layer.succeed(RequestTracing, (effect, request) =>
|
|
8
|
+
RequestTracing.use((tracing) => tracing(effect, request)).pipe(
|
|
9
|
+
Effect.provide(requestTracingLayer({ sensitive: redactionForRpc(sensitive, request.rpc._tag) })),
|
|
10
|
+
),
|
|
11
|
+
);
|
|
12
|
+
}
|