@gettersethya/mira-collection 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 +164 -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 +55 -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 +45 -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 +334 -0
- package/dist/src/collection/field.d.ts.map +1 -0
- package/dist/src/collection/field.js +201 -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 +133 -0
- package/dist/src/collection/serialize.js.map +1 -0
- package/dist/src/collection/types.d.ts +127 -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 +54 -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 +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/rule/builder.d.ts +91 -0
- package/dist/src/rule/builder.d.ts.map +1 -0
- package/dist/src/rule/builder.js +138 -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 +132 -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/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 +165 -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 +193 -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 +342 -0
- package/dist/tests/rule/builder.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/collection/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAA;AACpH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection definition system.
|
|
3
|
+
*
|
|
4
|
+
* Provides builders for defining collections (base, auth, view), their fields,
|
|
5
|
+
* indexes, and byte-size helpers. The primary entry points are:
|
|
6
|
+
*
|
|
7
|
+
* - `BaseCollection.define()` — standard CRUD collections
|
|
8
|
+
* - `AuthCollection.define()` — auth/user collections with system fields
|
|
9
|
+
* - `ViewCollection.define()` — read-only SQL view collections
|
|
10
|
+
* - `Field.*()` — field type builders
|
|
11
|
+
* - `Index.*()` — index builders
|
|
12
|
+
* - `Bytes.*` — human-readable byte size constants
|
|
13
|
+
*/
|
|
14
|
+
export { AuthCollection } from "./auth.js";
|
|
15
|
+
export { BaseCollection } from "./base.js";
|
|
16
|
+
export { Bytes } from "./bytes.js";
|
|
17
|
+
export { ValidationError } from "./errors.js";
|
|
18
|
+
export { Field } from "./field.js";
|
|
19
|
+
export { Index } from "./index-builder.js";
|
|
20
|
+
export { ViewCollection } from "./view.js";
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/collection/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAE1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RuleMap } from "../rule/types.js";
|
|
2
|
+
import type { IndexEntry } from "./index-builder.js";
|
|
3
|
+
import type { CollectionSchema, FieldsMap, JsonSchemaProperty } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Converts a user-facing field definition map into a JSON Schema `CollectionSchema`.
|
|
6
|
+
*
|
|
7
|
+
* - Automatically injects `seqId` as the first property.
|
|
8
|
+
- Injects system fields (e.g., auth email/password) before user fields.
|
|
9
|
+
- Collects `required` from fields without defaults.
|
|
10
|
+
- Normalizes `unique`/`indexed` flags into `x-indexes`.
|
|
11
|
+
- Merges collection-level indexes from `options.indexes`.
|
|
12
|
+
- Passes through `x-rules` and `x-view-query` if provided.
|
|
13
|
+
*
|
|
14
|
+
* Used internally by `BaseCollection.define()`, `AuthCollection.define()`, and `ViewCollection.define()`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function toJSONSchema<K extends "base" | "auth" | "view">(kind: K, _name: string, fields: FieldsMap, options: {
|
|
17
|
+
indexes?: Array<IndexEntry<string>>;
|
|
18
|
+
rules?: RuleMap;
|
|
19
|
+
viewQuery?: string;
|
|
20
|
+
systemFields?: Record<string, JsonSchemaProperty>;
|
|
21
|
+
}): CollectionSchema & {
|
|
22
|
+
"x-collection-kind": K;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/collection/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAY,SAAS,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAwB3F;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,EAC7D,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IACnC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CAClD,GACA,gBAAgB,GAAG;IAAE,mBAAmB,EAAE,CAAC,CAAA;CAAE,CAkD/C"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
const ID_PROPERTY = {
|
|
2
|
+
type: "string",
|
|
3
|
+
"x-system": true
|
|
4
|
+
};
|
|
5
|
+
const SEQID_PROPERTY = {
|
|
6
|
+
type: "integer",
|
|
7
|
+
"x-kind": "seqId",
|
|
8
|
+
"x-system": true,
|
|
9
|
+
"x-hidden": true
|
|
10
|
+
};
|
|
11
|
+
const CREATED_PROPERTY = {
|
|
12
|
+
type: "string",
|
|
13
|
+
"x-system": true
|
|
14
|
+
};
|
|
15
|
+
const UPDATED_PROPERTY = {
|
|
16
|
+
type: "string",
|
|
17
|
+
"x-system": true
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Converts a user-facing field definition map into a JSON Schema `CollectionSchema`.
|
|
21
|
+
*
|
|
22
|
+
* - Automatically injects `seqId` as the first property.
|
|
23
|
+
- Injects system fields (e.g., auth email/password) before user fields.
|
|
24
|
+
- Collects `required` from fields without defaults.
|
|
25
|
+
- Normalizes `unique`/`indexed` flags into `x-indexes`.
|
|
26
|
+
- Merges collection-level indexes from `options.indexes`.
|
|
27
|
+
- Passes through `x-rules` and `x-view-query` if provided.
|
|
28
|
+
*
|
|
29
|
+
* Used internally by `BaseCollection.define()`, `AuthCollection.define()`, and `ViewCollection.define()`.
|
|
30
|
+
*/
|
|
31
|
+
export function toJSONSchema(kind, _name, fields, options) {
|
|
32
|
+
const xIndexes = [];
|
|
33
|
+
const required = [];
|
|
34
|
+
const properties = {};
|
|
35
|
+
for (const [key, prop] of Object.entries(options.systemFields ?? {})) {
|
|
36
|
+
if (prop.default === undefined) {
|
|
37
|
+
required.push(key);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const [key, field] of Object.entries(fields)) {
|
|
41
|
+
const name = field.name ?? key;
|
|
42
|
+
const prop = fieldToProperty(field);
|
|
43
|
+
if (field.required !== false && field.default === undefined) {
|
|
44
|
+
required.push(name);
|
|
45
|
+
}
|
|
46
|
+
if (field.unique) {
|
|
47
|
+
xIndexes.push({ fields: [name], unique: true });
|
|
48
|
+
}
|
|
49
|
+
if (field.indexed) {
|
|
50
|
+
xIndexes.push({ fields: [name], unique: false });
|
|
51
|
+
}
|
|
52
|
+
properties[name] = prop;
|
|
53
|
+
}
|
|
54
|
+
for (const idx of options.indexes ?? []) {
|
|
55
|
+
xIndexes.push({ fields: [...idx.fields], unique: idx.unique });
|
|
56
|
+
}
|
|
57
|
+
const result = {
|
|
58
|
+
"x-collection-kind": kind,
|
|
59
|
+
...(xIndexes.length > 0 ? { "x-indexes": xIndexes } : {}),
|
|
60
|
+
...(options.rules !== undefined ? { "x-rules": options.rules } : {}),
|
|
61
|
+
...(options.viewQuery !== undefined ? { "x-view-query": options.viewQuery } : {}),
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
...(kind !== "view" ? { id: ID_PROPERTY, seqId: SEQID_PROPERTY } : {}),
|
|
65
|
+
...(options.systemFields ?? {}),
|
|
66
|
+
...properties,
|
|
67
|
+
...(kind !== "view" ? { created: CREATED_PROPERTY, updated: UPDATED_PROPERTY } : {})
|
|
68
|
+
},
|
|
69
|
+
...(required.length > 0 ? { required } : {})
|
|
70
|
+
};
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
/** Converts a single `FieldDef` to its JSON Schema property representation. */
|
|
74
|
+
function fieldToProperty(field) {
|
|
75
|
+
const base = (() => {
|
|
76
|
+
switch (field.kind) {
|
|
77
|
+
case "text":
|
|
78
|
+
return {
|
|
79
|
+
type: "string",
|
|
80
|
+
...(field.minLength !== undefined ? { minLength: field.minLength } : {}),
|
|
81
|
+
...(field.maxLength !== undefined ? { maxLength: field.maxLength } : {})
|
|
82
|
+
};
|
|
83
|
+
case "literalText":
|
|
84
|
+
return {
|
|
85
|
+
type: "string",
|
|
86
|
+
"x-kind": "literalText",
|
|
87
|
+
...(field.literal !== undefined ? { "x-literal": field.literal } : {})
|
|
88
|
+
};
|
|
89
|
+
case "number":
|
|
90
|
+
return {
|
|
91
|
+
type: "number",
|
|
92
|
+
...(field.min !== undefined ? { minimum: field.min } : {}),
|
|
93
|
+
...(field.max !== undefined ? { maximum: field.max } : {})
|
|
94
|
+
};
|
|
95
|
+
case "integer":
|
|
96
|
+
return {
|
|
97
|
+
type: "integer",
|
|
98
|
+
...(field.min !== undefined ? { minimum: field.min } : {}),
|
|
99
|
+
...(field.max !== undefined ? { maximum: field.max } : {})
|
|
100
|
+
};
|
|
101
|
+
case "boolean":
|
|
102
|
+
return {
|
|
103
|
+
type: "boolean",
|
|
104
|
+
...(field.default !== undefined ? { default: field.default } : {})
|
|
105
|
+
};
|
|
106
|
+
case "email":
|
|
107
|
+
return { type: "string", format: "email" };
|
|
108
|
+
case "date":
|
|
109
|
+
return { type: "string", "x-kind": "date" };
|
|
110
|
+
case "json":
|
|
111
|
+
return { "x-kind": "json" };
|
|
112
|
+
case "relation":
|
|
113
|
+
return {
|
|
114
|
+
type: "string",
|
|
115
|
+
"x-kind": "relation",
|
|
116
|
+
"x-collection": field.targetCollection,
|
|
117
|
+
"x-field": field.targetField ?? "id"
|
|
118
|
+
};
|
|
119
|
+
case "seqId":
|
|
120
|
+
return { type: "integer", "x-kind": "seqId", "x-system": true };
|
|
121
|
+
case "file":
|
|
122
|
+
return {
|
|
123
|
+
type: "string",
|
|
124
|
+
"x-kind": "file",
|
|
125
|
+
...(field.maxSize !== undefined ? { "x-maxSize": field.maxSize } : {}),
|
|
126
|
+
...(field.mimeTypes !== undefined ? { "x-mimeTypes": field.mimeTypes } : {}),
|
|
127
|
+
...(field.protected === true ? { "x-protected": true } : {})
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
})();
|
|
131
|
+
return field.viewOnly ? { ...base, "x-view-only": true } : base;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../../src/collection/serialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kind of constraint that failed validation on a field.
|
|
3
|
+
* Passed to the `error` callback on `FieldDef` so callers can return
|
|
4
|
+
* a per-constraint custom message.
|
|
5
|
+
*/
|
|
6
|
+
export type ConstraintKind = "type" | "required" | "minLength" | "maxLength" | "email" | "minimum" | "maximum" | "int" | "literal";
|
|
7
|
+
/** Constraint kinds that can fire on a `Field.text()` field. */
|
|
8
|
+
export type TextConstraintKind = "type" | "required" | "minLength" | "maxLength";
|
|
9
|
+
/** Constraint kinds that can fire on a `Field.email()` field. */
|
|
10
|
+
export type EmailConstraintKind = "type" | "required" | "email";
|
|
11
|
+
/** Constraint kinds that can fire on a `Field.number()` field. */
|
|
12
|
+
export type NumberConstraintKind = "type" | "required" | "minimum" | "maximum";
|
|
13
|
+
/** Constraint kinds that can fire on a `Field.integer()` field. */
|
|
14
|
+
export type IntegerConstraintKind = "type" | "required" | "int" | "minimum" | "maximum";
|
|
15
|
+
/** Constraint kinds that can fire on a `Field.literalText()` field. */
|
|
16
|
+
export type LiteralTextConstraintKind = "type" | "required" | "literal";
|
|
17
|
+
/** Constraint kinds that can fire on simple fields (boolean, date, json, file, relation). */
|
|
18
|
+
export type SimpleConstraintKind = "type" | "required";
|
|
19
|
+
/** Supported field kinds that define the data type of a collection field. */
|
|
20
|
+
export type FieldKind = "text" | "literalText" | "number" | "integer" | "boolean" | "email" | "date" | "json" | "relation" | "file" | "seqId";
|
|
21
|
+
/**
|
|
22
|
+
* Describes a single field in a collection definition.
|
|
23
|
+
* Created via `Field.*()` builders — never constructed directly.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* Field.text({ maxLength: 200 })
|
|
27
|
+
* Field.relation(Users, { field: "id" })
|
|
28
|
+
*/
|
|
29
|
+
export type FieldDef = {
|
|
30
|
+
_tag: "FieldDef";
|
|
31
|
+
kind: FieldKind;
|
|
32
|
+
name?: string;
|
|
33
|
+
required?: boolean;
|
|
34
|
+
unique?: boolean;
|
|
35
|
+
indexed?: boolean;
|
|
36
|
+
default?: unknown;
|
|
37
|
+
minLength?: number;
|
|
38
|
+
maxLength?: number;
|
|
39
|
+
min?: number;
|
|
40
|
+
max?: number;
|
|
41
|
+
targetCollection?: string;
|
|
42
|
+
targetField?: string;
|
|
43
|
+
maxSize?: number;
|
|
44
|
+
mimeTypes?: Array<string>;
|
|
45
|
+
viewOnly?: boolean;
|
|
46
|
+
protected?: boolean;
|
|
47
|
+
literal?: readonly string[];
|
|
48
|
+
_literal?: readonly string[];
|
|
49
|
+
_target?: AnyCollectionDef;
|
|
50
|
+
error?(kind: ConstraintKind): string | undefined;
|
|
51
|
+
};
|
|
52
|
+
/** A database index on one or more fields, either unique or non-unique. */
|
|
53
|
+
export type IndexDef = {
|
|
54
|
+
fields: Array<string>;
|
|
55
|
+
unique: boolean;
|
|
56
|
+
};
|
|
57
|
+
import type { RuleMap } from "../rule/types.js";
|
|
58
|
+
/**
|
|
59
|
+
* The JSON Schema representation of a collection.
|
|
60
|
+
* This is the serialized format stored in the `_collections` table.
|
|
61
|
+
* TypeScript field definitions are compiled down to this format.
|
|
62
|
+
*/
|
|
63
|
+
export type CollectionSchema = {
|
|
64
|
+
"x-collection-kind": "base" | "auth" | "view";
|
|
65
|
+
"x-indexes"?: Array<IndexDef>;
|
|
66
|
+
"x-rules"?: RuleMap;
|
|
67
|
+
"x-view-query"?: string;
|
|
68
|
+
type: "object";
|
|
69
|
+
properties: Record<string, JsonSchemaProperty>;
|
|
70
|
+
required?: Array<string>;
|
|
71
|
+
};
|
|
72
|
+
/** A single property within a JSON Schema collection definition. */
|
|
73
|
+
export type JsonSchemaProperty = {
|
|
74
|
+
type?: "string" | "number" | "integer" | "boolean";
|
|
75
|
+
format?: "email";
|
|
76
|
+
default?: unknown;
|
|
77
|
+
minimum?: number;
|
|
78
|
+
maximum?: number;
|
|
79
|
+
minLength?: number;
|
|
80
|
+
maxLength?: number;
|
|
81
|
+
"x-kind"?: "date" | "json" | "relation" | "file" | "seqId" | "literalText";
|
|
82
|
+
"x-collection"?: string;
|
|
83
|
+
"x-field"?: string;
|
|
84
|
+
"x-maxSize"?: number;
|
|
85
|
+
"x-mimeTypes"?: Array<string>;
|
|
86
|
+
"x-protected"?: boolean;
|
|
87
|
+
"x-system"?: boolean;
|
|
88
|
+
"x-hidden"?: boolean;
|
|
89
|
+
"x-view-only"?: boolean;
|
|
90
|
+
"x-literal"?: ReadonlyArray<string>;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* A record mapping field names to their `FieldDef` definitions.
|
|
94
|
+
* Used when defining collection fields.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* { title: Field.text(), published: Field.boolean() }
|
|
98
|
+
*/
|
|
99
|
+
export type FieldsMap = Record<string, FieldDef>;
|
|
100
|
+
/**
|
|
101
|
+
* The user-facing output of a collection definition.
|
|
102
|
+
* Returned by `BaseCollection.define()`, `AuthCollection.define()`, and `ViewCollection.define()`.
|
|
103
|
+
*/
|
|
104
|
+
export type AnyCollectionDef = {
|
|
105
|
+
name: string;
|
|
106
|
+
fields: FieldsMap;
|
|
107
|
+
schema: CollectionSchema;
|
|
108
|
+
};
|
|
109
|
+
/** Maps each FieldKind to its corresponding TypeScript scalar type. */
|
|
110
|
+
export type FieldKindToType = {
|
|
111
|
+
text: string;
|
|
112
|
+
literalText: string;
|
|
113
|
+
number: number;
|
|
114
|
+
integer: number;
|
|
115
|
+
boolean: boolean;
|
|
116
|
+
email: string;
|
|
117
|
+
date: string;
|
|
118
|
+
json: unknown;
|
|
119
|
+
relation: string;
|
|
120
|
+
file: string;
|
|
121
|
+
seqId: number;
|
|
122
|
+
};
|
|
123
|
+
/** Infers the TypeScript value type for a given FieldDef. */
|
|
124
|
+
export type InferFieldValue<T extends FieldDef> = T["kind"] extends "literalText" ? T extends {
|
|
125
|
+
_literal: readonly (infer V)[];
|
|
126
|
+
} ? V : string : FieldKindToType[T["kind"]];
|
|
127
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/collection/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/collection/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { RuleBuilder } from "../rule/builder.js";
|
|
2
|
+
import type { RuleMap } from "../rule/types.js";
|
|
3
|
+
import type { CollectionSchema, FieldDef, FieldsMap } from "./types.js";
|
|
4
|
+
type ViewFields = {
|
|
5
|
+
id: FieldDef & {
|
|
6
|
+
viewOnly: true;
|
|
7
|
+
};
|
|
8
|
+
seqId: FieldDef & {
|
|
9
|
+
viewOnly: true;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
type RuleCb<F extends FieldsMap> = (R: RuleBuilder<F>) => RuleMap;
|
|
13
|
+
/**
|
|
14
|
+
* Builder returned by `ViewCollection.define()`.
|
|
15
|
+
* Immediately satisfies `AnyCollectionDef` — no terminal `.build()` needed.
|
|
16
|
+
* Chain `.rules()` to add access rules. Views have no `.indexes()` — they are not physical tables.
|
|
17
|
+
* Each chained method returns a new builder; the original is unchanged.
|
|
18
|
+
*/
|
|
19
|
+
export type ViewCollectionBuilder<F extends FieldsMap> = {
|
|
20
|
+
name: string;
|
|
21
|
+
fields: F;
|
|
22
|
+
schema: CollectionSchema;
|
|
23
|
+
/**
|
|
24
|
+
* Add per-action access rules. No rule means deny all.
|
|
25
|
+
* Pass a callback to get a typed rule builder with auto-completion over field names.
|
|
26
|
+
*/
|
|
27
|
+
rules(cb: RuleCb<F>): ViewCollectionBuilder<F>;
|
|
28
|
+
};
|
|
29
|
+
/** @internal Exported for testing only. */
|
|
30
|
+
export declare function validateViewFields(name: string, fields: Record<string, {
|
|
31
|
+
viewOnly?: boolean;
|
|
32
|
+
}>): void;
|
|
33
|
+
/**
|
|
34
|
+
* Defines a read-only view collection backed by a raw SQL query.
|
|
35
|
+
* Requires `id` and `seqId` in the field map, both declared with `.view()`.
|
|
36
|
+
* No indexes are supported.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const ActivePosts = ViewCollection.define(
|
|
40
|
+
* "active_posts",
|
|
41
|
+
* `WITH ranked AS (
|
|
42
|
+
* SELECT p.id, p.title, ROW_NUMBER() OVER (ORDER BY p.created DESC) AS seqId
|
|
43
|
+
* FROM posts p WHERE p.status = 'active'
|
|
44
|
+
* ) SELECT * FROM ranked`,
|
|
45
|
+
* {
|
|
46
|
+
* id: Field.text().view(),
|
|
47
|
+
* seqId: Field.integer().view(),
|
|
48
|
+
* title: Field.text().view()
|
|
49
|
+
* }
|
|
50
|
+
* )
|
|
51
|
+
* .rules((R) => ({ list: R.public(), view: R.public() }))
|
|
52
|
+
*/
|
|
53
|
+
export declare const ViewCollection: {
|
|
54
|
+
define<F extends ViewFields & FieldsMap>(name: string, query: string, fields: F): ViewCollectionBuilder<F>;
|
|
55
|
+
};
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/collection/view.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAE9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEvE,KAAK,UAAU,GAAG;IAChB,EAAE,EAAK,QAAQ,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAA;IACpC,KAAK,EAAE,QAAQ,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAA;CACrC,CAAA;AAED,KAAK,MAAM,CAAC,CAAC,SAAS,SAAS,IAAI,CACjC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,KACd,OAAO,CAAA;AAEZ;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,SAAS,IAAI;IACvD,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,CAAC,CAAA;IACT,MAAM,EAAE,gBAAgB,CAAA;IACxB;;;OAGG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAA;CAC/C,CAAA;AAED,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,IAAI,CAKrG;AA0BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,cAAc;WAClB,CAAC,SAAS,UAAU,GAAG,SAAS,QAC/B,MAAM,SACL,MAAM,UACL,CAAC,GACR,qBAAqB,CAAC,CAAC,CAAC;CAI5B,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { makeRuleBuilder } from "../rule/builder.js";
|
|
2
|
+
import { toJSONSchema } from "./serialize.js";
|
|
3
|
+
/** @internal Exported for testing only. */
|
|
4
|
+
export function validateViewFields(name, fields) {
|
|
5
|
+
if (!fields.id || fields.id.viewOnly !== true)
|
|
6
|
+
throw new Error(`ViewCollection "${name}": "id" must be declared with .view()`);
|
|
7
|
+
if (!fields.seqId || fields.seqId.viewOnly !== true)
|
|
8
|
+
throw new Error(`ViewCollection "${name}": "seqId" must be declared with .view()`);
|
|
9
|
+
}
|
|
10
|
+
function makeViewBuilder(name, query, fields, rulesCb) {
|
|
11
|
+
let _schema;
|
|
12
|
+
return {
|
|
13
|
+
name,
|
|
14
|
+
fields,
|
|
15
|
+
get schema() {
|
|
16
|
+
if (_schema === undefined) {
|
|
17
|
+
const rules = rulesCb?.(makeRuleBuilder());
|
|
18
|
+
_schema = toJSONSchema("view", name, fields, {
|
|
19
|
+
viewQuery: query,
|
|
20
|
+
...(rules !== undefined ? { rules } : {})
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return _schema;
|
|
24
|
+
},
|
|
25
|
+
rules: (cb) => makeViewBuilder(name, query, fields, cb)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Defines a read-only view collection backed by a raw SQL query.
|
|
30
|
+
* Requires `id` and `seqId` in the field map, both declared with `.view()`.
|
|
31
|
+
* No indexes are supported.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const ActivePosts = ViewCollection.define(
|
|
35
|
+
* "active_posts",
|
|
36
|
+
* `WITH ranked AS (
|
|
37
|
+
* SELECT p.id, p.title, ROW_NUMBER() OVER (ORDER BY p.created DESC) AS seqId
|
|
38
|
+
* FROM posts p WHERE p.status = 'active'
|
|
39
|
+
* ) SELECT * FROM ranked`,
|
|
40
|
+
* {
|
|
41
|
+
* id: Field.text().view(),
|
|
42
|
+
* seqId: Field.integer().view(),
|
|
43
|
+
* title: Field.text().view()
|
|
44
|
+
* }
|
|
45
|
+
* )
|
|
46
|
+
* .rules((R) => ({ list: R.public(), view: R.public() }))
|
|
47
|
+
*/
|
|
48
|
+
export const ViewCollection = {
|
|
49
|
+
define(name, query, fields) {
|
|
50
|
+
validateViewFields(name, fields);
|
|
51
|
+
return makeViewBuilder(name, query, fields);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/collection/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AA6B7C,2CAA2C;AAC3C,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,MAA8C;IAC7F,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,EAAE,CAAC,QAAQ,KAAK,IAAI;QAC3C,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,uCAAuC,CAAC,CAAA;IACjF,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,IAAI;QACjD,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,0CAA0C,CAAC,CAAA;AACtF,CAAC;AAED,SAAS,eAAe,CACtB,IAAY,EACZ,KAAa,EACb,MAAS,EACT,OAAmB;IAEnB,IAAI,OAAqC,CAAA;IACzC,OAAO;QACL,IAAI;QACJ,MAAM;QACN,IAAI,MAAM;YACR,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC,eAAe,EAAK,CAAC,CAAA;gBAC7C,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;oBAC3C,SAAS,EAAE,KAAK;oBAChB,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC1C,CAAC,CAAA;YACJ,CAAC;YACD,OAAO,OAAQ,CAAA;QACjB,CAAC;QACD,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;KACxD,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,MAAM,CACJ,IAAY,EACZ,KAAa,EACb,MAAS;QAET,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAChC,OAAO,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;IAC7C,CAAC;CACF,CAAA"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { FieldsMap, InferFieldValue } from "../collection/types.js";
|
|
2
|
+
import type { FilterNode } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Operand returned by `Filter.field(name)` — provides comparison methods
|
|
5
|
+
* that each produce a `FilterNode`.
|
|
6
|
+
*
|
|
7
|
+
* The type parameter `V` constrains the value type for comparisons:
|
|
8
|
+
* when used through `FilterBuilder<F>.field(name)`, `V` is the inferred
|
|
9
|
+
* TypeScript type of the field (string, number, boolean, etc.). When used
|
|
10
|
+
* through the untyped `Filter.field(name)`, `V` is `unknown`.
|
|
11
|
+
*
|
|
12
|
+
* Available comparisons:
|
|
13
|
+
* - `.eq(v)` / `.neq(v)` — equality / inequality
|
|
14
|
+
* - `.gt(v)` / `.gte(v)` — greater than / greater or equal
|
|
15
|
+
* - `.lt(v)` / `.lte(v)` — less than / less or equal
|
|
16
|
+
* - `.in(values)` — membership in a list
|
|
17
|
+
* - `.like(pattern)` — SQL LIKE pattern match (always string-valued)
|
|
18
|
+
* - `.null()` / `.notNull()` — IS NULL / IS NOT NULL (no value argument)
|
|
19
|
+
* - `.between(lo, hi)` — compound of `.gte(lo)` + `.lte(hi)`
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* import { Filter } from "@gettersethya/mira-collection"
|
|
23
|
+
*
|
|
24
|
+
* Filter.field("age").gte(18)
|
|
25
|
+
* Filter.field("title").like("%effect%")
|
|
26
|
+
* Filter.field("tags").in(["a", "b", "c"])
|
|
27
|
+
* Filter.field("deletedAt").null()
|
|
28
|
+
* Filter.field("price").between(10, 100)
|
|
29
|
+
*
|
|
30
|
+
* @see Filter — entry point to create FieldFilterOperand
|
|
31
|
+
* @see FilterBuilder — typed variant with field-name and value-type safety
|
|
32
|
+
*/
|
|
33
|
+
export type FieldFilterOperand<V = unknown> = {
|
|
34
|
+
eq(value: V): FilterNode;
|
|
35
|
+
neq(value: V): FilterNode;
|
|
36
|
+
gt(value: V): FilterNode;
|
|
37
|
+
gte(value: V): FilterNode;
|
|
38
|
+
lt(value: V): FilterNode;
|
|
39
|
+
lte(value: V): FilterNode;
|
|
40
|
+
in(values: ReadonlyArray<V>): FilterNode;
|
|
41
|
+
like(value: string): FilterNode;
|
|
42
|
+
null(): FilterNode;
|
|
43
|
+
notNull(): FilterNode;
|
|
44
|
+
between(lo: V, hi: V): FilterNode;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Typed filter builder constrained to a specific `FieldsMap`.
|
|
48
|
+
* Provides the same methods as `Filter` but narrows field names and value
|
|
49
|
+
* types according to the collection's field definitions.
|
|
50
|
+
*
|
|
51
|
+
* Used inside `CollectionClient.getList({ filter: (f) => ... })` callbacks.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* interface PostFields { title: FieldDef & { kind: "text" }; views: FieldDef & { kind: "number" } }
|
|
55
|
+
* const f: FilterBuilder<PostFields>
|
|
56
|
+
*
|
|
57
|
+
* f.field("title").eq("hello") // typed — value is string
|
|
58
|
+
* f.field("views").gte(100) // typed — value is number
|
|
59
|
+
* f.field("views").eq("bad") // type error — expects number
|
|
60
|
+
* f.field("nonexistent").eq(1) // type error — field does not exist
|
|
61
|
+
*
|
|
62
|
+
* @see Filter — untyped version of the same DSL
|
|
63
|
+
* @see FieldFilterOperand — the return type of .field()
|
|
64
|
+
*/
|
|
65
|
+
export type FilterBuilder<F extends FieldsMap = FieldsMap> = {
|
|
66
|
+
field<K extends keyof F & string>(name: K): FieldFilterOperand<InferFieldValue<F[K]>>;
|
|
67
|
+
and(left: FilterNode, right: FilterNode): FilterNode;
|
|
68
|
+
or(left: FilterNode, right: FilterNode): FilterNode;
|
|
69
|
+
not(node: FilterNode): FilterNode;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Filter DSL builder for constructing `FilterNode` expressions.
|
|
73
|
+
*
|
|
74
|
+
* Use `Filter.field(name)` to start a comparison chain, then call a comparison
|
|
75
|
+
* method (`.eq()`, `.neq()`, `.gt()`, etc.) to produce a `FilterNode`.
|
|
76
|
+
* Combine nodes with `Filter.and()`, `Filter.or()`, `Filter.not()`.
|
|
77
|
+
*
|
|
78
|
+
* This is the untyped variant — field names are plain strings and values are
|
|
79
|
+
* `unknown`. For type-safe field access, use `FilterBuilder<F>` via the
|
|
80
|
+
* `CollectionClient` callback pattern.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* import { Filter } from "@gettersethya/mira-collection"
|
|
84
|
+
*
|
|
85
|
+
* // Simple equality
|
|
86
|
+
* const published = Filter.field("published").eq(true)
|
|
87
|
+
*
|
|
88
|
+
* // Range check
|
|
89
|
+
* const popular = Filter.and(
|
|
90
|
+
* Filter.field("views").gte(100),
|
|
91
|
+
* Filter.field("views").lte(10_000)
|
|
92
|
+
* )
|
|
93
|
+
*
|
|
94
|
+
* // In-list
|
|
95
|
+
* const draftOrArchived = Filter.field("status").in(["draft", "archived"])
|
|
96
|
+
*
|
|
97
|
+
* // LIKE pattern
|
|
98
|
+
* const search = Filter.field("title").like("%effect%")
|
|
99
|
+
*
|
|
100
|
+
* // Null checks
|
|
101
|
+
* const hasDeletedAt = Filter.field("deletedAt").null()
|
|
102
|
+
* const notDeleted = Filter.field("deletedAt").notNull()
|
|
103
|
+
*
|
|
104
|
+
* // Complex combination
|
|
105
|
+
* const query = Filter.and(
|
|
106
|
+
* Filter.field("published").eq(true),
|
|
107
|
+
* Filter.or(
|
|
108
|
+
* Filter.field("category").eq("tech"),
|
|
109
|
+
* Filter.field("tags").contains("effect")
|
|
110
|
+
* )
|
|
111
|
+
* )
|
|
112
|
+
*
|
|
113
|
+
* @see FilterNode — the AST node produced by filter methods
|
|
114
|
+
* @see FilterBuilder — typed variant used in CollectionClient methods
|
|
115
|
+
* @see filterNodeToWhereClause — compiles FilterNode to SQL
|
|
116
|
+
*/
|
|
117
|
+
export declare const Filter: {
|
|
118
|
+
/** Start a filter chain for a field by name. Returns a `FieldFilterOperand` with comparison methods. */
|
|
119
|
+
field: <K extends string>(name: K) => FieldFilterOperand<unknown>;
|
|
120
|
+
/** Combine two filter nodes with logical AND. Produces `(left) AND (right)` in SQL. */
|
|
121
|
+
and: (left: FilterNode, right: FilterNode) => FilterNode;
|
|
122
|
+
/** Combine two filter nodes with logical OR. Produces `(left) OR (right)` in SQL. */
|
|
123
|
+
or: (left: FilterNode, right: FilterNode) => FilterNode;
|
|
124
|
+
/** Negate a filter node with logical NOT. Produces `NOT (node)` in SQL. */
|
|
125
|
+
not: (node: FilterNode) => FilterNode;
|
|
126
|
+
};
|
|
127
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/filter/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC5C,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;IACxB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;IACzB,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;IACxB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;IACzB,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;IACxB,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;IACzB,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,CAAA;IACxC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAA;IAC/B,IAAI,IAAI,UAAU,CAAA;IAClB,OAAO,IAAI,UAAU,CAAA;IACrB,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,UAAU,CAAA;CAClC,CAAA;AAkBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,IAAI;IAC3D,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACrF,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,UAAU,CAAA;IACpD,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,UAAU,CAAA;IACnD,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAAA;CAClC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,eAAO,MAAM,MAAM;IACjB,wGAAwG;YAChG,CAAC,SAAS,MAAM,QAAQ,CAAC,KAAG,kBAAkB,CAAC,OAAO,CAAC;IAG/D,uFAAuF;gBAC3E,UAAU,SAAS,UAAU,KAAG,UAAU;IAGtD,qFAAqF;eAC1E,UAAU,SAAS,UAAU,KAAG,UAAU;IAGrD,2EAA2E;gBAC/D,UAAU,KAAG,UAAU;CAEpC,CAAA"}
|