@shivaedev/server 0.9.2 → 0.10.0
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 +190 -0
- package/README.md +1 -1
- 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.d.ts +1 -1
- package/dist/hostChanges.d.ts.map +1 -1
- package/dist/hostChanges.js +6 -12
- 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/dist/setupDatabases.d.ts +1 -1
- package/dist/setupDatabases.d.ts.map +1 -1
- package/dist/setupDatabases.js +1 -1
- package/dist/setupDatabases.js.map +1 -1
- package/package.json +13 -17
- package/src/RedactionPolicy.ts +7 -1
- package/src/hostChanges.ts +12 -16
- 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
- package/src/setupDatabases.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safeOtlpSerialization.d.ts","sourceRoot":"","sources":["../src/safeOtlpSerialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAwC,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAOzG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAK,EAAE,SAAS,GAAE,YAA6B,UAE/F;
|
|
1
|
+
{"version":3,"file":"safeOtlpSerialization.d.ts","sourceRoot":"","sources":["../src/safeOtlpSerialization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAwC,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAOzG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAK,EAAE,SAAS,GAAE,YAA6B,UAE/F;AAuDD,eAAO,MAAM,qBAAqB,8FAUjC,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect, Layer } from "effect";
|
|
2
2
|
import { OtlpSerialization } from "effect/observability";
|
|
3
3
|
import { isSensitiveKey, REDACTED, redactText } from "@shivaedev/errors/sensitive.ts";
|
|
4
|
-
import { RedactionPolicy } from "#RedactionPolicy.ts";
|
|
4
|
+
import { RedactionPolicy, redactionForRpc } from "#RedactionPolicy.ts";
|
|
5
5
|
import { redactOtlpUrl } from "#redactOtlpUrl.ts";
|
|
6
6
|
function otlpSensitive(sensitive) {
|
|
7
7
|
return (key) => sensitive(key) || ["db.user", "db.user.name", "db.connection_string"].includes(key.toLowerCase());
|
|
@@ -33,32 +33,37 @@ function spanName(span) {
|
|
|
33
33
|
}
|
|
34
34
|
return span.name;
|
|
35
35
|
}
|
|
36
|
-
function redactTraces(data,
|
|
37
|
-
|
|
38
|
-
return redactOtlpText(value, "", sensitive);
|
|
39
|
-
}
|
|
36
|
+
function redactTraces(data, policy) {
|
|
37
|
+
const resourceSensitive = otlpSensitive(policy);
|
|
40
38
|
return {
|
|
41
39
|
...data,
|
|
42
40
|
resourceSpans: data.resourceSpans.map((resource) => ({
|
|
43
41
|
...resource,
|
|
44
|
-
resource: { ...resource.resource, attributes: attributes(resource.resource.attributes,
|
|
42
|
+
resource: { ...resource.resource, attributes: attributes(resource.resource.attributes, resourceSensitive) },
|
|
45
43
|
scopeSpans: resource.scopeSpans.map((scope) => ({
|
|
46
44
|
...scope,
|
|
47
|
-
spans: scope.spans.map((span) =>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
spans: scope.spans.map((span) => {
|
|
46
|
+
const method = span.attributes.find(({ key }) => key === "rpc.method")?.value.stringValue;
|
|
47
|
+
const sensitive = otlpSensitive(redactionForRpc(policy, method));
|
|
48
|
+
function text(value) {
|
|
49
|
+
return redactOtlpText(value, "", sensitive);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
...span,
|
|
53
|
+
attributes: attributes(span.attributes, sensitive),
|
|
54
|
+
events: span.events.map((event) => ({ ...event, attributes: attributes(event.attributes, sensitive), name: text(event.name) })),
|
|
55
|
+
links: span.links.map((link) => ({ ...link, attributes: attributes(link.attributes, sensitive) })),
|
|
56
|
+
name: text(spanName(span)),
|
|
57
|
+
status: { ...span.status, ...(span.status.message === undefined ? {} : { message: text(span.status.message) }) },
|
|
58
|
+
};
|
|
59
|
+
}),
|
|
55
60
|
})),
|
|
56
61
|
})),
|
|
57
62
|
};
|
|
58
63
|
}
|
|
59
64
|
export const safeOtlpSerialization = Layer.effect(OtlpSerialization.OtlpSerialization, Effect.gen(function* () {
|
|
60
65
|
const serialization = yield* OtlpSerialization.OtlpSerialization;
|
|
61
|
-
const sensitive =
|
|
66
|
+
const sensitive = yield* RedactionPolicy;
|
|
62
67
|
return OtlpSerialization.OtlpSerialization.of({
|
|
63
68
|
...serialization,
|
|
64
69
|
traces: (data) => serialization.traces(redactTraces(data, sensitive)),
|
|
@@ -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/dist/setupDatabases.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Config, Effect } from "effect";
|
|
2
|
-
export declare const setupDatabases: () => Effect.Effect<void, Config.ConfigError,
|
|
2
|
+
export declare const setupDatabases: () => Effect.Effect<void, Config.ConfigError | import("@shivaedev/local-postgres/server/LocalPostgresError.ts").LocalPostgresError | import("@shivaedev/local-postgres/server/PostgresCommandError.ts").PostgresCommandError | import("@shivaedev/local-postgres/server/localConnections.ts").PostgresSettingError | import("@shivaedev/local-postgres/server/PostgresVersionMismatch.ts").PostgresVersionMismatch, import("effect/process/ChildProcessSpawner").ChildProcessSpawner>;
|
|
3
3
|
//# sourceMappingURL=setupDatabases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setupDatabases.d.ts","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"setupDatabases.d.ts","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,eAAO,MAAM,cAAc,udAQzB,CAAC"}
|
package/dist/setupDatabases.js
CHANGED
|
@@ -7,6 +7,6 @@ export const setupDatabases = Effect.fn("Platform.setupDatabases")(function* ()
|
|
|
7
7
|
"DOCKER_HOST": Config.String("DOCKER_HOST").pipe(Config.withDefault("")),
|
|
8
8
|
"TEST_DATABASE_URL": Config.String("TEST_DATABASE_URL"),
|
|
9
9
|
});
|
|
10
|
-
yield*
|
|
10
|
+
yield* localPostgres(config).prepareDatabases([config.DATABASE_URL, config.TEST_DATABASE_URL]);
|
|
11
11
|
});
|
|
12
12
|
//# sourceMappingURL=setupDatabases.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setupDatabases.js","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,mDAAmD,CAAC;AAElF,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAChC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;QAC7C,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9E,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxE,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC;KACvD,CAAC,CAAC;IACH,KAAK,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"setupDatabases.js","sourceRoot":"","sources":["../src/setupDatabases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,mDAAmD,CAAC;AAElF,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAChC,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;QAC7C,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9E,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACxE,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC;KACvD,CAAC,CAAC;IACH,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAChG,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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,32 +41,32 @@
|
|
|
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.
|
|
52
|
-
"@shivaedev/local-postgres": "0.
|
|
49
|
+
"@shivaedev/contract": "0.27.0",
|
|
50
|
+
"@shivaedev/errors": "0.1.3",
|
|
51
|
+
"@shivaedev/http": "0.3.1",
|
|
52
|
+
"@shivaedev/identity": "0.10.1",
|
|
53
|
+
"@shivaedev/local-postgres": "0.8.0",
|
|
53
54
|
"@shivaedev/sql": "0.27.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
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.3",
|
|
62
|
+
"@shivaedev/jobs": "0.25.0",
|
|
63
|
+
"@shivaedev/quality": "0.48.2",
|
|
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.28.0",
|
|
65
67
|
"@types/node": "24.19.2",
|
|
66
|
-
"@types/pg": "8.20.0",
|
|
67
68
|
"better-auth": "1.7.12",
|
|
68
69
|
"effect": "4.0.6",
|
|
69
|
-
"pg": "8.23.0",
|
|
70
70
|
"pg-boss": "12.38.0",
|
|
71
71
|
"typescript": "7.0.2",
|
|
72
72
|
"vitest": "5.0.5"
|
|
@@ -76,8 +76,7 @@
|
|
|
76
76
|
"@effect/sql-pg": "4.0.6",
|
|
77
77
|
"@effect/vitest": "4.0.6",
|
|
78
78
|
"better-auth": "1.7.12",
|
|
79
|
-
"effect": "4.0.6"
|
|
80
|
-
"pg": "8.23.0"
|
|
79
|
+
"effect": "4.0.6"
|
|
81
80
|
},
|
|
82
81
|
"peerDependenciesMeta": {
|
|
83
82
|
"@effect/platform-node": {
|
|
@@ -91,9 +90,6 @@
|
|
|
91
90
|
},
|
|
92
91
|
"better-auth": {
|
|
93
92
|
"optional": true
|
|
94
|
-
},
|
|
95
|
-
"pg": {
|
|
96
|
-
"optional": true
|
|
97
93
|
}
|
|
98
94
|
},
|
|
99
95
|
"engines": {
|
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
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Context, Effect, Layer, Option, Stream } from "effect";
|
|
2
2
|
import { Headers } from "effect/http";
|
|
3
|
-
import
|
|
3
|
+
import { Rpc, type RpcGroup } from "effect/rpc";
|
|
4
4
|
import { CurrentViewer, type Viewer } from "@shivaedev/contract/readPolicy.ts";
|
|
5
5
|
import type { QueryReference } from "@shivaedev/contract/serverMetadata.ts";
|
|
6
6
|
import { Unauthorized } from "@shivaedev/errors/taxonomy.ts";
|
|
7
7
|
import { recheckSession } from "@shivaedev/identity/server/recheckSession.ts";
|
|
8
|
+
import { revalidateStream } from "@shivaedev/identity/server/revalidateStream.ts";
|
|
8
9
|
import type { SessionPolicy, SessionShape } from "@shivaedev/identity/server/session.ts";
|
|
9
10
|
import { resolveChanges } from "@shivaedev/identity/server/sessionKeys.ts";
|
|
10
|
-
import { revalidateSession } from "@shivaedev/identity/server/socketSession.ts";
|
|
11
11
|
import type { AppChanges } from "#appHost.ts";
|
|
12
12
|
import { rerunQuery } from "#rerunQuery.ts";
|
|
13
13
|
|
|
@@ -21,7 +21,7 @@ export function hostChanges<R extends Rpc.Any, TSession extends SessionShape>(
|
|
|
21
21
|
const changes = yield* Effect.serviceOption(changesService);
|
|
22
22
|
const services = yield* Effect.context<never>();
|
|
23
23
|
const handlers = new Map<string, unknown>();
|
|
24
|
-
function subscribe(rpc: Rpc.
|
|
24
|
+
function subscribe(rpc: Rpc.AnyWithProps, queries: readonly QueryReference[], options: Parameters<Rpc.Handler<string>["handler"]>[1]) {
|
|
25
25
|
return Stream.unwrap(
|
|
26
26
|
Effect.gen(function* () {
|
|
27
27
|
const { subscription, context } = yield* resolveChanges(rpc, queries);
|
|
@@ -33,12 +33,15 @@ export function hostChanges<R extends Rpc.Any, TSession extends SessionShape>(
|
|
|
33
33
|
if (sessions === undefined || Option.isNone(viewer)) {
|
|
34
34
|
return stream;
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
const revalidation = Effect.never.pipe(
|
|
37
|
+
revalidateStream(sessions, rpc, viewer.value.id, recheckSession(sessions, Headers.empty, rpc._tag)),
|
|
38
|
+
);
|
|
39
|
+
return Stream.interruptWhen(stream, revalidation);
|
|
37
40
|
}),
|
|
38
41
|
);
|
|
39
42
|
}
|
|
40
43
|
for (const rpc of group.requests.values()) {
|
|
41
|
-
if (!rpc._tag.endsWith(".$changes")) {
|
|
44
|
+
if (!(Rpc.isRpc(rpc) && rpc._tag.endsWith(".$changes"))) {
|
|
42
45
|
continue;
|
|
43
46
|
}
|
|
44
47
|
const provided = services.mapUnsafe.get(rpc.key);
|
|
@@ -69,16 +72,9 @@ function authorizeSession<TSession extends SessionShape, E, R>(
|
|
|
69
72
|
}
|
|
70
73
|
return recheckSession(sessions, Headers.empty, tag).pipe(
|
|
71
74
|
Effect.map((current) => Option.isNone(viewer) || (Option.isSome(current) && current.value.user.id === viewer.value.id)),
|
|
72
|
-
Effect.
|
|
73
|
-
|
|
75
|
+
Effect.flatMap(
|
|
76
|
+
(allowed): Effect.Effect<boolean, E | Unauthorized, R> =>
|
|
77
|
+
allowed ? policy : Effect.fail(new Unauthorized({ message: "Authentication required" })),
|
|
78
|
+
),
|
|
74
79
|
);
|
|
75
80
|
}
|
|
76
|
-
|
|
77
|
-
function sessionRevoked<TSession extends SessionShape>(sessions: SessionPolicy<TSession>, tag: string, id: string) {
|
|
78
|
-
return Effect.gen(function* () {
|
|
79
|
-
const current = yield* recheckSession(sessions, Headers.empty, tag).pipe(Effect.catchTag("AuthUnavailable", () => Effect.succeed(undefined)));
|
|
80
|
-
if (current !== undefined && (Option.isNone(current) || current.value.user.id !== id)) {
|
|
81
|
-
return yield* new Unauthorized({ message: "Authentication required" });
|
|
82
|
-
}
|
|
83
|
-
}).pipe((check) => revalidateSession(check, sessions.streamRevalidationInterval ?? "30 seconds"));
|
|
84
|
-
}
|