@gettersethya/mira-client 0.1.0-alpha.10
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/LICENSE +21 -0
- package/README.md +140 -0
- package/dist/src/client/auth.d.ts +73 -0
- package/dist/src/client/auth.d.ts.map +1 -0
- package/dist/src/client/auth.js +72 -0
- package/dist/src/client/auth.js.map +1 -0
- package/dist/src/client/collection.d.ts +239 -0
- package/dist/src/client/collection.d.ts.map +1 -0
- package/dist/src/client/collection.js +137 -0
- package/dist/src/client/collection.js.map +1 -0
- package/dist/src/client/errors.d.ts +46 -0
- package/dist/src/client/errors.d.ts.map +1 -0
- package/dist/src/client/errors.js +40 -0
- package/dist/src/client/errors.js.map +1 -0
- package/dist/src/client/factory.d.ts +78 -0
- package/dist/src/client/factory.d.ts.map +1 -0
- package/dist/src/client/factory.js +108 -0
- package/dist/src/client/factory.js.map +1 -0
- package/dist/src/client/file.d.ts +116 -0
- package/dist/src/client/file.d.ts.map +1 -0
- package/dist/src/client/file.js +99 -0
- package/dist/src/client/file.js.map +1 -0
- package/dist/src/client/handler.d.ts +92 -0
- package/dist/src/client/handler.d.ts.map +1 -0
- package/dist/src/client/handler.js +62 -0
- package/dist/src/client/handler.js.map +1 -0
- package/dist/src/client/index.d.ts +13 -0
- package/dist/src/client/index.d.ts.map +1 -0
- package/dist/src/client/index.js +7 -0
- package/dist/src/client/index.js.map +1 -0
- package/dist/src/client/telemetry.d.ts +50 -0
- package/dist/src/client/telemetry.d.ts.map +1 -0
- package/dist/src/client/telemetry.js +32 -0
- package/dist/src/client/telemetry.js.map +1 -0
- package/dist/src/client/types.d.ts +137 -0
- package/dist/src/client/types.d.ts.map +1 -0
- package/dist/src/client/types.js +2 -0
- package/dist/src/client/types.js.map +1 -0
- package/dist/src/collection/auth.d.ts +79 -0
- package/dist/src/collection/auth.d.ts.map +1 -0
- package/dist/src/collection/auth.js +50 -0
- package/dist/src/collection/auth.js.map +1 -0
- package/dist/src/collection/base.d.ts +64 -0
- package/dist/src/collection/base.d.ts.map +1 -0
- package/dist/src/collection/base.js +40 -0
- package/dist/src/collection/base.js.map +1 -0
- package/dist/src/collection/bytes.d.ts +51 -0
- package/dist/src/collection/bytes.d.ts.map +1 -0
- package/dist/src/collection/bytes.js +51 -0
- package/dist/src/collection/bytes.js.map +1 -0
- package/dist/src/collection/errors.d.ts +29 -0
- package/dist/src/collection/errors.d.ts.map +1 -0
- package/dist/src/collection/errors.js +23 -0
- package/dist/src/collection/errors.js.map +1 -0
- package/dist/src/collection/field.d.ts +300 -0
- package/dist/src/collection/field.d.ts.map +1 -0
- package/dist/src/collection/field.js +175 -0
- package/dist/src/collection/field.js.map +1 -0
- package/dist/src/collection/index-builder.d.ts +59 -0
- package/dist/src/collection/index-builder.d.ts.map +1 -0
- package/dist/src/collection/index-builder.js +43 -0
- package/dist/src/collection/index-builder.js.map +1 -0
- package/dist/src/collection/index.d.ts +22 -0
- package/dist/src/collection/index.d.ts.map +1 -0
- package/dist/src/collection/index.js +21 -0
- package/dist/src/collection/index.js.map +1 -0
- package/dist/src/collection/serialize.d.ts +24 -0
- package/dist/src/collection/serialize.d.ts.map +1 -0
- package/dist/src/collection/serialize.js +127 -0
- package/dist/src/collection/serialize.js.map +1 -0
- package/dist/src/collection/types.d.ts +119 -0
- package/dist/src/collection/types.d.ts.map +1 -0
- package/dist/src/collection/types.js +2 -0
- package/dist/src/collection/types.js.map +1 -0
- package/dist/src/collection/view.d.ts +57 -0
- package/dist/src/collection/view.d.ts.map +1 -0
- package/dist/src/collection/view.js +49 -0
- package/dist/src/collection/view.js.map +1 -0
- package/dist/src/filter/builder.d.ts +127 -0
- package/dist/src/filter/builder.d.ts.map +1 -0
- package/dist/src/filter/builder.js +72 -0
- package/dist/src/filter/builder.js.map +1 -0
- package/dist/src/filter/compiler.d.ts +48 -0
- package/dist/src/filter/compiler.d.ts.map +1 -0
- package/dist/src/filter/compiler.js +132 -0
- package/dist/src/filter/compiler.js.map +1 -0
- package/dist/src/filter/index.d.ts +6 -0
- package/dist/src/filter/index.d.ts.map +1 -0
- package/dist/src/filter/index.js +4 -0
- package/dist/src/filter/index.js.map +1 -0
- package/dist/src/filter/types.d.ts +96 -0
- package/dist/src/filter/types.d.ts.map +1 -0
- package/dist/src/filter/types.js +44 -0
- package/dist/src/filter/types.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/rule/builder.d.ts +97 -0
- package/dist/src/rule/builder.d.ts.map +1 -0
- package/dist/src/rule/builder.js +126 -0
- package/dist/src/rule/builder.js.map +1 -0
- package/dist/src/rule/index.d.ts +3 -0
- package/dist/src/rule/index.d.ts.map +1 -0
- package/dist/src/rule/index.js +3 -0
- package/dist/src/rule/index.js.map +1 -0
- package/dist/src/rule/types.d.ts +129 -0
- package/dist/src/rule/types.d.ts.map +1 -0
- package/dist/src/rule/types.js +2 -0
- package/dist/src/rule/types.js.map +1 -0
- package/dist/tests/client/auth.test.d.ts +2 -0
- package/dist/tests/client/auth.test.d.ts.map +1 -0
- package/dist/tests/client/auth.test.js +67 -0
- package/dist/tests/client/auth.test.js.map +1 -0
- package/dist/tests/client/collection.test.d.ts +2 -0
- package/dist/tests/client/collection.test.d.ts.map +1 -0
- package/dist/tests/client/collection.test.js +593 -0
- package/dist/tests/client/collection.test.js.map +1 -0
- package/dist/tests/client/file.test.d.ts +2 -0
- package/dist/tests/client/file.test.d.ts.map +1 -0
- package/dist/tests/client/file.test.js +21 -0
- package/dist/tests/client/file.test.js.map +1 -0
- package/dist/tests/client/handler.test.d.ts +2 -0
- package/dist/tests/client/handler.test.d.ts.map +1 -0
- package/dist/tests/client/handler.test.js +24 -0
- package/dist/tests/client/handler.test.js.map +1 -0
- package/dist/tests/client/types.test.d.ts +2 -0
- package/dist/tests/client/types.test.d.ts.map +1 -0
- package/dist/tests/client/types.test.js +168 -0
- package/dist/tests/client/types.test.js.map +1 -0
- package/dist/tests/collection/auth.test.d.ts +2 -0
- package/dist/tests/collection/auth.test.d.ts.map +1 -0
- package/dist/tests/collection/auth.test.js +44 -0
- package/dist/tests/collection/auth.test.js.map +1 -0
- package/dist/tests/collection/base.test.d.ts +2 -0
- package/dist/tests/collection/base.test.d.ts.map +1 -0
- package/dist/tests/collection/base.test.js +70 -0
- package/dist/tests/collection/base.test.js.map +1 -0
- package/dist/tests/collection/bytes.test.d.ts +2 -0
- package/dist/tests/collection/bytes.test.d.ts.map +1 -0
- package/dist/tests/collection/bytes.test.js +9 -0
- package/dist/tests/collection/bytes.test.js.map +1 -0
- package/dist/tests/collection/field.test.d.ts +2 -0
- package/dist/tests/collection/field.test.d.ts.map +1 -0
- package/dist/tests/collection/field.test.js +140 -0
- package/dist/tests/collection/field.test.js.map +1 -0
- package/dist/tests/collection/index-type.test.d.ts +2 -0
- package/dist/tests/collection/index-type.test.d.ts.map +1 -0
- package/dist/tests/collection/index-type.test.js +28 -0
- package/dist/tests/collection/index-type.test.js.map +1 -0
- package/dist/tests/collection/serialize.test.d.ts +2 -0
- package/dist/tests/collection/serialize.test.d.ts.map +1 -0
- package/dist/tests/collection/serialize.test.js +165 -0
- package/dist/tests/collection/serialize.test.js.map +1 -0
- package/dist/tests/collection/view.test.d.ts +2 -0
- package/dist/tests/collection/view.test.d.ts.map +1 -0
- package/dist/tests/collection/view.test.js +66 -0
- package/dist/tests/collection/view.test.js.map +1 -0
- package/dist/tests/filter/compiler.test.d.ts +2 -0
- package/dist/tests/filter/compiler.test.d.ts.map +1 -0
- package/dist/tests/filter/compiler.test.js +156 -0
- package/dist/tests/filter/compiler.test.js.map +1 -0
- package/dist/tests/rule/builder.test.d.ts +2 -0
- package/dist/tests/rule/builder.test.d.ts.map +1 -0
- package/dist/tests/rule/builder.test.js +290 -0
- package/dist/tests/rule/builder.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
let _filterNodeSchema;
|
|
3
|
+
_filterNodeSchema = Schema.Union(Schema.Struct({
|
|
4
|
+
op: Schema.Literal("eq", "neq", "gt", "gte", "lt", "lte"),
|
|
5
|
+
field: Schema.String,
|
|
6
|
+
value: Schema.Unknown
|
|
7
|
+
}), Schema.Struct({
|
|
8
|
+
op: Schema.Literal("in"),
|
|
9
|
+
field: Schema.String,
|
|
10
|
+
values: Schema.Array(Schema.Unknown)
|
|
11
|
+
}), Schema.Struct({
|
|
12
|
+
op: Schema.Literal("like"),
|
|
13
|
+
field: Schema.String,
|
|
14
|
+
value: Schema.String
|
|
15
|
+
}), Schema.Struct({
|
|
16
|
+
op: Schema.Literal("null", "not_null"),
|
|
17
|
+
field: Schema.String
|
|
18
|
+
}), Schema.Struct({
|
|
19
|
+
op: Schema.Literal("and", "or"),
|
|
20
|
+
left: Schema.suspend(() => _filterNodeSchema),
|
|
21
|
+
right: Schema.suspend(() => _filterNodeSchema)
|
|
22
|
+
}), Schema.Struct({
|
|
23
|
+
op: Schema.Literal("not"),
|
|
24
|
+
node: Schema.suspend(() => _filterNodeSchema)
|
|
25
|
+
}));
|
|
26
|
+
/**
|
|
27
|
+
* Effect Schema for `FilterNode`. Used to decode filter query parameters
|
|
28
|
+
* from HTTP request JSON bodies.
|
|
29
|
+
*
|
|
30
|
+
* The schema is self-referential (recursive via `Schema.suspend`) to handle
|
|
31
|
+
* nested `and`/`or`/`not` nodes. This is why the underlying `let` variable
|
|
32
|
+
* exists — the recursive `suspend` needs a forward reference.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* import { Schema } from "effect"
|
|
36
|
+
*
|
|
37
|
+
* const raw = { op: "eq", field: "title", value: "hello" }
|
|
38
|
+
* const filter = Schema.decodeSync(FilterNodeSchema)(raw)
|
|
39
|
+
* // filter: FilterNode — { op: "eq", field: "title", value: "hello" }
|
|
40
|
+
*
|
|
41
|
+
* @see FilterNode — the TypeScript type this schema decodes to
|
|
42
|
+
*/
|
|
43
|
+
export { _filterNodeSchema as FilterNodeSchema };
|
|
44
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/filter/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AA+D/B,IAAI,iBAA4C,CAAA;AAEhD,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAC9B,MAAM,CAAC,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,KAAK,EAAE,MAAM,CAAC,OAAO;CACtB,CAAC,EACF,MAAM,CAAC,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;CACrC,CAAC,EACF,MAAM,CAAC,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,KAAK,EAAE,MAAM,CAAC,MAAM;CACrB,CAAC,EACF,MAAM,CAAC,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC,MAAM;CACrB,CAAC,EACF,MAAM,CAAC,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC;CAC/C,CAAC,EACF,MAAM,CAAC,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC;CAC9C,CAAC,CACH,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,iBAAiB,IAAI,gBAAgB,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,cAAc,mBAAmB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAA;AAC7C,cAAc,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { AnyCollectionDef, FieldsMap, InferFieldValue } from "../collection/types.js";
|
|
2
|
+
import type { ExprNode, OperandNode } from "./types.js";
|
|
3
|
+
type FieldOperandMethods<K extends string, V = unknown> = {
|
|
4
|
+
eq(right: OperandNode<any, V>): ExprNode<K>;
|
|
5
|
+
neq(right: OperandNode<any, V>): ExprNode<K>;
|
|
6
|
+
gt(right: OperandNode<any, V>): ExprNode<K>;
|
|
7
|
+
gte(right: OperandNode<any, V>): ExprNode<K>;
|
|
8
|
+
lt(right: OperandNode<any, V>): ExprNode<K>;
|
|
9
|
+
lte(right: OperandNode<any, V>): ExprNode<K>;
|
|
10
|
+
in(right: OperandNode<any, V | ReadonlyArray<V>>): ExprNode<K>;
|
|
11
|
+
startsWith(right: OperandNode<any, V>): ExprNode<K>;
|
|
12
|
+
contains(right: OperandNode<any, V>): ExprNode<K>;
|
|
13
|
+
};
|
|
14
|
+
/** An operand node with fluent comparison methods attached. */
|
|
15
|
+
export type FieldOperand<K extends string, V = unknown> = OperandNode<K, V> & FieldOperandMethods<K, V>;
|
|
16
|
+
/**
|
|
17
|
+
* A narrowed version of the Rule builder where `field()` is constrained to field
|
|
18
|
+
* names defined in `F` and comparison operands are typed to match each field's value type.
|
|
19
|
+
* Used as the argument type for the `rules` callback in collection definers.
|
|
20
|
+
*/
|
|
21
|
+
export type RuleBuilder<F extends FieldsMap> = Omit<typeof Rule, "field"> & {
|
|
22
|
+
field<K extends keyof F & string>(name: K): FieldOperand<K, InferFieldValue<F[K]>>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Rule builder API.
|
|
26
|
+
*
|
|
27
|
+
* Constructs access rule expressions using a fluent builder pattern.
|
|
28
|
+
* Rules are compiled to SQL WHERE clauses at runtime by the rule compiler.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Simple field comparison
|
|
32
|
+
* Rule.field("ownerId").eq(Rule.authId(Users))
|
|
33
|
+
*
|
|
34
|
+
* // Boolean combination
|
|
35
|
+
* Rule.or(
|
|
36
|
+
* Rule.field("isPublic").eq(Rule.literal(true)),
|
|
37
|
+
* Rule.field("ownerId").eq(Rule.authId(Users))
|
|
38
|
+
* )
|
|
39
|
+
*
|
|
40
|
+
* // Date-based rule
|
|
41
|
+
* Rule.field("createdAt").gte(Rule.dateAdd(Rule.now(), -30, "day"))
|
|
42
|
+
*
|
|
43
|
+
* // Subquery
|
|
44
|
+
* const memberTeams = Rule.subquery(Members, "teamId").where(
|
|
45
|
+
* Rule.field("userId").eq(Rule.authId(Users))
|
|
46
|
+
* )
|
|
47
|
+
* Rule.field("teamId").in(memberTeams)
|
|
48
|
+
*
|
|
49
|
+
* // Always allow
|
|
50
|
+
* Rule.public()
|
|
51
|
+
*/
|
|
52
|
+
export declare const Rule: {
|
|
53
|
+
/** Reference a record field by name. Returns a chainable operand. Value type is unknown; use via RuleBuilder for typed comparisons. */
|
|
54
|
+
field: <const K extends string>(name: K) => FieldOperand<K, unknown>;
|
|
55
|
+
/** Reference a value from the incoming request (header, query param, or body field). */
|
|
56
|
+
request: (source: "header" | "query" | "body", key: string) => FieldOperand<string, string>;
|
|
57
|
+
/** Reference a field from the authenticated user's record. */
|
|
58
|
+
auth: <C extends AnyCollectionDef, K extends keyof C["fields"] & string>(_collection: C, field: K) => FieldOperand<string, string>;
|
|
59
|
+
/** Reference the ID of the currently authenticated user. */
|
|
60
|
+
authId: <C extends AnyCollectionDef>(_collection: C) => OperandNode<any, string>;
|
|
61
|
+
/** A literal value for comparison. The value type `V` is inferred from the argument. */
|
|
62
|
+
literal: <V>(value: V) => OperandNode<any, V>;
|
|
63
|
+
/**
|
|
64
|
+
* Create a subquery operand into another collection.
|
|
65
|
+
* Call `.where()` on the result to finish the subquery.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* Rule.subquery(Members, "teamId").where(
|
|
69
|
+
* Rule.field("userId").eq(Rule.authId(Users))
|
|
70
|
+
* )
|
|
71
|
+
*/
|
|
72
|
+
subquery: <C extends AnyCollectionDef, K extends keyof C["fields"] & string>(_collection: C, field: K) => {
|
|
73
|
+
where: (expr: ExprNode<any>) => OperandNode<any, string>;
|
|
74
|
+
};
|
|
75
|
+
/** Current timestamp operand. Compiles to `datetime('now')` in SQLite. */
|
|
76
|
+
now: () => OperandNode<any, string>;
|
|
77
|
+
/** Add a duration to a date operand for date arithmetic. */
|
|
78
|
+
dateAdd: (operand: OperandNode<any>, amount: number, unit: "day" | "hour" | "minute") => OperandNode<any, string>;
|
|
79
|
+
/** Compute the difference between two date operands. */
|
|
80
|
+
dateDiff: (left: OperandNode<any>, right: OperandNode<any>, unit: "day" | "hour" | "minute") => OperandNode<any, number>;
|
|
81
|
+
/** Logical AND of expressions. */
|
|
82
|
+
and: <K extends string = string>(...exprs: Array<ExprNode<K>>) => ExprNode<K>;
|
|
83
|
+
/** Logical OR of expressions. */
|
|
84
|
+
or: <K extends string = string>(...exprs: Array<ExprNode<K>>) => ExprNode<K>;
|
|
85
|
+
/** Logical negation of a sub-expression. */
|
|
86
|
+
not: <K extends string = string>(expr: ExprNode<K>) => ExprNode<K>;
|
|
87
|
+
/** Always-true rule that allows all access. */
|
|
88
|
+
public: <K extends string = string>() => ExprNode<K>;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Creates a typed `RuleBuilder<F>` that constrains `field()` to names in `F`
|
|
92
|
+
* and types each comparison operand to the field's value type.
|
|
93
|
+
* Used internally by collection definers.
|
|
94
|
+
*/
|
|
95
|
+
export declare function makeRuleBuilder<F extends FieldsMap>(): RuleBuilder<F>;
|
|
96
|
+
export {};
|
|
97
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/rule/builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
function toChainable(operand) {
|
|
2
|
+
const methods = {
|
|
3
|
+
eq(right) { return { op: "eq", left: operand, right }; },
|
|
4
|
+
neq(right) { return { op: "neq", left: operand, right }; },
|
|
5
|
+
gt(right) { return { op: "gt", left: operand, right }; },
|
|
6
|
+
gte(right) { return { op: "gte", left: operand, right }; },
|
|
7
|
+
lt(right) { return { op: "lt", left: operand, right }; },
|
|
8
|
+
lte(right) { return { op: "lte", left: operand, right }; },
|
|
9
|
+
in(right) { return { op: "in", left: operand, right }; },
|
|
10
|
+
startsWith(right) { return { op: "startsWith", left: operand, right }; },
|
|
11
|
+
contains(right) { return { op: "contains", left: operand, right }; }
|
|
12
|
+
};
|
|
13
|
+
return Object.assign({}, operand, methods);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Rule builder API.
|
|
17
|
+
*
|
|
18
|
+
* Constructs access rule expressions using a fluent builder pattern.
|
|
19
|
+
* Rules are compiled to SQL WHERE clauses at runtime by the rule compiler.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Simple field comparison
|
|
23
|
+
* Rule.field("ownerId").eq(Rule.authId(Users))
|
|
24
|
+
*
|
|
25
|
+
* // Boolean combination
|
|
26
|
+
* Rule.or(
|
|
27
|
+
* Rule.field("isPublic").eq(Rule.literal(true)),
|
|
28
|
+
* Rule.field("ownerId").eq(Rule.authId(Users))
|
|
29
|
+
* )
|
|
30
|
+
*
|
|
31
|
+
* // Date-based rule
|
|
32
|
+
* Rule.field("createdAt").gte(Rule.dateAdd(Rule.now(), -30, "day"))
|
|
33
|
+
*
|
|
34
|
+
* // Subquery
|
|
35
|
+
* const memberTeams = Rule.subquery(Members, "teamId").where(
|
|
36
|
+
* Rule.field("userId").eq(Rule.authId(Users))
|
|
37
|
+
* )
|
|
38
|
+
* Rule.field("teamId").in(memberTeams)
|
|
39
|
+
*
|
|
40
|
+
* // Always allow
|
|
41
|
+
* Rule.public()
|
|
42
|
+
*/
|
|
43
|
+
export const Rule = {
|
|
44
|
+
/** Reference a record field by name. Returns a chainable operand. Value type is unknown; use via RuleBuilder for typed comparisons. */
|
|
45
|
+
field: (name) => toChainable({ kind: "field", field: name }),
|
|
46
|
+
/** Reference a value from the incoming request (header, query param, or body field). */
|
|
47
|
+
request: (source, key) => toChainable({ kind: "request", source, key }),
|
|
48
|
+
/** Reference a field from the authenticated user's record. */
|
|
49
|
+
auth: (_collection, field) => toChainable({ kind: "auth", collection: _collection.name, field }),
|
|
50
|
+
/** Reference the ID of the currently authenticated user. */
|
|
51
|
+
authId: (_collection) => ({
|
|
52
|
+
kind: "authId",
|
|
53
|
+
collection: _collection.name
|
|
54
|
+
}),
|
|
55
|
+
/** A literal value for comparison. The value type `V` is inferred from the argument. */
|
|
56
|
+
literal: (value) => ({
|
|
57
|
+
kind: "literal",
|
|
58
|
+
value
|
|
59
|
+
}),
|
|
60
|
+
/**
|
|
61
|
+
* Create a subquery operand into another collection.
|
|
62
|
+
* Call `.where()` on the result to finish the subquery.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* Rule.subquery(Members, "teamId").where(
|
|
66
|
+
* Rule.field("userId").eq(Rule.authId(Users))
|
|
67
|
+
* )
|
|
68
|
+
*/
|
|
69
|
+
subquery: (_collection, field) => ({
|
|
70
|
+
where: (expr) => ({
|
|
71
|
+
kind: "subquery",
|
|
72
|
+
collection: _collection.name,
|
|
73
|
+
field,
|
|
74
|
+
where: expr
|
|
75
|
+
})
|
|
76
|
+
}),
|
|
77
|
+
/** Current timestamp operand. Compiles to `datetime('now')` in SQLite. */
|
|
78
|
+
now: () => ({ kind: "now" }),
|
|
79
|
+
/** Add a duration to a date operand for date arithmetic. */
|
|
80
|
+
dateAdd: (operand, amount, unit) => ({
|
|
81
|
+
kind: "dateAdd",
|
|
82
|
+
operand,
|
|
83
|
+
amount,
|
|
84
|
+
unit
|
|
85
|
+
}),
|
|
86
|
+
/** Compute the difference between two date operands. */
|
|
87
|
+
dateDiff: (left, right, unit) => ({
|
|
88
|
+
kind: "dateDiff",
|
|
89
|
+
left,
|
|
90
|
+
right,
|
|
91
|
+
unit
|
|
92
|
+
}),
|
|
93
|
+
/** Logical AND of expressions. */
|
|
94
|
+
and: (...exprs) => {
|
|
95
|
+
if (exprs.length === 0)
|
|
96
|
+
return { op: "public" };
|
|
97
|
+
if (exprs.length === 1)
|
|
98
|
+
return exprs[0];
|
|
99
|
+
return exprs.slice(1).reduce((acc, curr) => ({ op: "and", left: acc, right: curr }), exprs[0]);
|
|
100
|
+
},
|
|
101
|
+
/** Logical OR of expressions. */
|
|
102
|
+
or: (...exprs) => {
|
|
103
|
+
if (exprs.length === 0)
|
|
104
|
+
return { op: "public" };
|
|
105
|
+
if (exprs.length === 1)
|
|
106
|
+
return exprs[0];
|
|
107
|
+
return exprs.slice(1).reduce((acc, curr) => ({ op: "or", left: acc, right: curr }), exprs[0]);
|
|
108
|
+
},
|
|
109
|
+
/** Logical negation of a sub-expression. */
|
|
110
|
+
not: (expr) => ({ op: "not", expr }),
|
|
111
|
+
/** Always-true rule that allows all access. */
|
|
112
|
+
public: () => ({ op: "public" })
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Creates a typed `RuleBuilder<F>` that constrains `field()` to names in `F`
|
|
116
|
+
* and types each comparison operand to the field's value type.
|
|
117
|
+
* Used internally by collection definers.
|
|
118
|
+
*/
|
|
119
|
+
export function makeRuleBuilder() {
|
|
120
|
+
function field(name) {
|
|
121
|
+
return toChainable({ kind: "field", field: name });
|
|
122
|
+
}
|
|
123
|
+
const builder = { ...Rule, field };
|
|
124
|
+
return builder;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../../src/rule/builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rule/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rule/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A value node in a rule expression — can be a field reference, literal, auth context, subquery, date operation, or request value.
|
|
3
|
+
*
|
|
4
|
+
* - `field` — a record field (e.g., `Rule.field("ownerId")`)
|
|
5
|
+
* - `literal` — a static value (e.g., `Rule.literal(42)`)
|
|
6
|
+
* - `auth` — a field from the authenticated user record (e.g., `Rule.auth(Users, "role")`)
|
|
7
|
+
* - `authId` — the ID of the authenticated user (e.g., `Rule.authId(Users)`)
|
|
8
|
+
* - `subquery` — a subquery into another collection (e.g., `Rule.subquery(Members, "teamId")`)
|
|
9
|
+
* - `request` — a value from the incoming request (header, query, body)
|
|
10
|
+
* - `now` — current timestamp (e.g., `Rule.now()`)
|
|
11
|
+
* - `dateAdd` — date arithmetic (e.g., `Rule.dateAdd(Rule.now(), 7, "day")`)
|
|
12
|
+
* - `dateDiff` — difference between two dates (e.g., `Rule.dateDiff(Rule.field("created"), Rule.now(), "day")`)
|
|
13
|
+
*/
|
|
14
|
+
export type OperandNode<K extends string = string, V = unknown> = {
|
|
15
|
+
kind: "field";
|
|
16
|
+
collection?: string;
|
|
17
|
+
field: K;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "literal";
|
|
20
|
+
value: V;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "auth";
|
|
23
|
+
collection: string;
|
|
24
|
+
field: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: "authId";
|
|
27
|
+
collection: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "subquery";
|
|
30
|
+
collection: string;
|
|
31
|
+
field: string;
|
|
32
|
+
where: ExprNode<any>;
|
|
33
|
+
} | {
|
|
34
|
+
kind: "request";
|
|
35
|
+
source: "header" | "query" | "body";
|
|
36
|
+
key: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "now";
|
|
39
|
+
} | {
|
|
40
|
+
kind: "dateAdd";
|
|
41
|
+
operand: OperandNode<any>;
|
|
42
|
+
amount: number;
|
|
43
|
+
unit: "day" | "hour" | "minute";
|
|
44
|
+
} | {
|
|
45
|
+
kind: "dateDiff";
|
|
46
|
+
left: OperandNode<any>;
|
|
47
|
+
right: OperandNode<any>;
|
|
48
|
+
unit: "day" | "hour" | "minute";
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* A boolean expression node in a rule — the result of comparing operands or combining sub-expressions.
|
|
52
|
+
*
|
|
53
|
+
* - `eq` / `neq` / `gt` / `gte` / `lt` / `lte` — comparison operators
|
|
54
|
+
* - `in` — membership test (literal array or subquery)
|
|
55
|
+
* - `and` / `or` / `not` — boolean combinators
|
|
56
|
+
* - `startsWith` / `contains` — string pattern matching
|
|
57
|
+
* - `public` — always-true marker
|
|
58
|
+
*/
|
|
59
|
+
export type ExprNode<K extends string = string> = {
|
|
60
|
+
op: "eq";
|
|
61
|
+
left: OperandNode<K>;
|
|
62
|
+
right: OperandNode<any>;
|
|
63
|
+
} | {
|
|
64
|
+
op: "neq";
|
|
65
|
+
left: OperandNode<K>;
|
|
66
|
+
right: OperandNode<any>;
|
|
67
|
+
} | {
|
|
68
|
+
op: "gt";
|
|
69
|
+
left: OperandNode<K>;
|
|
70
|
+
right: OperandNode<any>;
|
|
71
|
+
} | {
|
|
72
|
+
op: "gte";
|
|
73
|
+
left: OperandNode<K>;
|
|
74
|
+
right: OperandNode<any>;
|
|
75
|
+
} | {
|
|
76
|
+
op: "lt";
|
|
77
|
+
left: OperandNode<K>;
|
|
78
|
+
right: OperandNode<any>;
|
|
79
|
+
} | {
|
|
80
|
+
op: "lte";
|
|
81
|
+
left: OperandNode<K>;
|
|
82
|
+
right: OperandNode<any>;
|
|
83
|
+
} | {
|
|
84
|
+
op: "in";
|
|
85
|
+
left: OperandNode<K>;
|
|
86
|
+
right: OperandNode<any>;
|
|
87
|
+
} | {
|
|
88
|
+
op: "and";
|
|
89
|
+
left: ExprNode<K>;
|
|
90
|
+
right: ExprNode<K>;
|
|
91
|
+
} | {
|
|
92
|
+
op: "or";
|
|
93
|
+
left: ExprNode<K>;
|
|
94
|
+
right: ExprNode<K>;
|
|
95
|
+
} | {
|
|
96
|
+
op: "not";
|
|
97
|
+
expr: ExprNode<K>;
|
|
98
|
+
} | {
|
|
99
|
+
op: "startsWith";
|
|
100
|
+
left: OperandNode<K>;
|
|
101
|
+
right: OperandNode<any>;
|
|
102
|
+
} | {
|
|
103
|
+
op: "contains";
|
|
104
|
+
left: OperandNode<K>;
|
|
105
|
+
right: OperandNode<any>;
|
|
106
|
+
} | {
|
|
107
|
+
op: "public";
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* A map of access rules keyed by action.
|
|
111
|
+
* Used in `CollectionSchema["x-rules"]`. Actions without a rule deny all access by default.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* {
|
|
115
|
+
* list: Rule.public(), // anyone can list
|
|
116
|
+
* view: Rule.field("ownerId").eq(Rule.authId(Users)), // owner only
|
|
117
|
+
* create: Rule.field("ownerId").eq(Rule.authId(Users)),
|
|
118
|
+
* update: Rule.field("ownerId").eq(Rule.authId(Users)),
|
|
119
|
+
* delete: Rule.field("ownerId").eq(Rule.authId(Users))
|
|
120
|
+
* }
|
|
121
|
+
*/
|
|
122
|
+
export type RuleMap<K extends string = string> = {
|
|
123
|
+
list?: ExprNode<K>;
|
|
124
|
+
view?: ExprNode<K>;
|
|
125
|
+
create?: ExprNode<K>;
|
|
126
|
+
update?: ExprNode<K>;
|
|
127
|
+
delete?: ExprNode<K>;
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/rule/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/rule/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../../../tests/client/auth.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Effect, MutableRef } from "effect";
|
|
3
|
+
import { makeBrowserAuth, makeServerAuth } from "@/client/auth.js";
|
|
4
|
+
import { makeClientHandler } from "@/client/handler.js";
|
|
5
|
+
describe("BrowserAuth", () => {
|
|
6
|
+
it("isLoggedIn() false initially", () => {
|
|
7
|
+
const loggedInRef = MutableRef.make(false);
|
|
8
|
+
const execute = () => Effect.succeed(undefined);
|
|
9
|
+
const auth = makeBrowserAuth(execute, makeClientHandler, loggedInRef);
|
|
10
|
+
expect(auth.isLoggedIn()).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
it("isLoggedIn() true after setting ref", () => {
|
|
13
|
+
const loggedInRef = MutableRef.make(true);
|
|
14
|
+
const execute = () => Effect.succeed(undefined);
|
|
15
|
+
const auth = makeBrowserAuth(execute, makeClientHandler, loggedInRef);
|
|
16
|
+
expect(auth.isLoggedIn()).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe("ServerAuth", () => {
|
|
20
|
+
it("token is null initially", () => {
|
|
21
|
+
const authTokenRef = MutableRef.make(null);
|
|
22
|
+
const fileTokenCacheRef = MutableRef.make(new Map());
|
|
23
|
+
const auth = makeServerAuth(authTokenRef, fileTokenCacheRef);
|
|
24
|
+
expect(auth.token).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
it("setToken stores the token, token reads it back", () => {
|
|
27
|
+
const authTokenRef = MutableRef.make(null);
|
|
28
|
+
const fileTokenCacheRef = MutableRef.make(new Map());
|
|
29
|
+
const auth = makeServerAuth(authTokenRef, fileTokenCacheRef);
|
|
30
|
+
auth.setToken("my-jwt-token");
|
|
31
|
+
expect(auth.token).toBe("my-jwt-token");
|
|
32
|
+
});
|
|
33
|
+
it("clear() sets token to null, clears file token cache", () => {
|
|
34
|
+
const authTokenRef = MutableRef.make(null);
|
|
35
|
+
const fileTokenCacheRef = MutableRef.make(new Map([["users", { token: "t", expiresAt: 123 }]]));
|
|
36
|
+
const auth = makeServerAuth(authTokenRef, fileTokenCacheRef);
|
|
37
|
+
auth.setToken("my-jwt-token");
|
|
38
|
+
auth.clear();
|
|
39
|
+
expect(auth.token).toBeNull();
|
|
40
|
+
expect(MutableRef.get(fileTokenCacheRef).size).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
it("isValid() returns false for null token", () => {
|
|
43
|
+
const authTokenRef = MutableRef.make(null);
|
|
44
|
+
const fileTokenCacheRef = MutableRef.make(new Map());
|
|
45
|
+
const auth = makeServerAuth(authTokenRef, fileTokenCacheRef);
|
|
46
|
+
expect(auth.isValid()).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
it("isValid() returns true for valid JWT", () => {
|
|
49
|
+
const futureExp = Math.floor(Date.now() / 1000) + 3600;
|
|
50
|
+
const payload = JSON.stringify({ exp: futureExp });
|
|
51
|
+
const fakeJwt = `header.${Buffer.from(payload).toString("base64")}.sig`;
|
|
52
|
+
const authTokenRef = MutableRef.make(fakeJwt);
|
|
53
|
+
const fileTokenCacheRef = MutableRef.make(new Map());
|
|
54
|
+
const auth = makeServerAuth(authTokenRef, fileTokenCacheRef);
|
|
55
|
+
expect(auth.isValid()).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
it("isValid() returns false for expired JWT", () => {
|
|
58
|
+
const pastExp = Math.floor(Date.now() / 1000) - 3600;
|
|
59
|
+
const payload = JSON.stringify({ exp: pastExp });
|
|
60
|
+
const fakeJwt = `header.${Buffer.from(payload).toString("base64")}.sig`;
|
|
61
|
+
const authTokenRef = MutableRef.make(fakeJwt);
|
|
62
|
+
const fileTokenCacheRef = MutableRef.make(new Map());
|
|
63
|
+
const auth = makeServerAuth(authTokenRef, fileTokenCacheRef);
|
|
64
|
+
expect(auth.isValid()).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=auth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../../../tests/client/auth.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collection.test.d.ts","sourceRoot":"","sources":["../../../tests/client/collection.test.ts"],"names":[],"mappings":""}
|