@docstack/client 0.0.1
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/README.md +214 -0
- package/lib/core/attribute.d.ts +174 -0
- package/lib/core/attribute.js +296 -0
- package/lib/core/attribute.js.map +1 -0
- package/lib/core/class.d.ts +340 -0
- package/lib/core/class.js +540 -0
- package/lib/core/class.js.map +1 -0
- package/lib/core/crypto-engine/index.d.ts +121 -0
- package/lib/core/crypto-engine/index.js +130 -0
- package/lib/core/crypto-engine/index.js.map +1 -0
- package/lib/core/crypto-engine/utils.d.ts +20 -0
- package/lib/core/crypto-engine/utils.js +76 -0
- package/lib/core/crypto-engine/utils.js.map +1 -0
- package/lib/core/datamodel/index.d.ts +3 -0
- package/lib/core/datamodel/index.js +1186 -0
- package/lib/core/datamodel/index.js.map +1 -0
- package/lib/core/domain.d.ts +200 -0
- package/lib/core/domain.js +285 -0
- package/lib/core/domain.js.map +1 -0
- package/lib/core/index.d.ts +176 -0
- package/lib/core/index.js +379 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/job-engine/index.d.ts +110 -0
- package/lib/core/job-engine/index.js +116 -0
- package/lib/core/job-engine/index.js.map +1 -0
- package/lib/core/policy-engine/index.d.ts +97 -0
- package/lib/core/policy-engine/index.js +150 -0
- package/lib/core/policy-engine/index.js.map +1 -0
- package/lib/core/query-engine/accumulators.d.ts +9 -0
- package/lib/core/query-engine/accumulators.js +258 -0
- package/lib/core/query-engine/accumulators.js.map +1 -0
- package/lib/core/query-engine/evaluator.d.ts +37 -0
- package/lib/core/query-engine/evaluator.js +179 -0
- package/lib/core/query-engine/evaluator.js.map +1 -0
- package/lib/core/query-engine/executor.d.ts +14 -0
- package/lib/core/query-engine/executor.js +405 -0
- package/lib/core/query-engine/executor.js.map +1 -0
- package/lib/core/query-engine/index.d.ts +4 -0
- package/lib/core/query-engine/index.js +4 -0
- package/lib/core/query-engine/index.js.map +1 -0
- package/lib/core/query-engine/parser.d.ts +10 -0
- package/lib/core/query-engine/parser.js +515 -0
- package/lib/core/query-engine/parser.js.map +1 -0
- package/lib/core/query-engine/planner.d.ts +27 -0
- package/lib/core/query-engine/planner.js +330 -0
- package/lib/core/query-engine/planner.js.map +1 -0
- package/lib/core/stack.d.ts +497 -0
- package/lib/core/stack.js +1507 -0
- package/lib/core/stack.js.map +1 -0
- package/lib/core/test-utils/docstack.d.ts +29 -0
- package/lib/core/test-utils/docstack.js +222 -0
- package/lib/core/test-utils/docstack.js.map +1 -0
- package/lib/core/trigger/index.d.ts +31 -0
- package/lib/core/trigger/index.js +81 -0
- package/lib/core/trigger/index.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +8237 -0
- package/lib/index.js.map +1 -0
- package/lib/plugins/pouchdb.d.ts +9 -0
- package/lib/plugins/pouchdb.js +403 -0
- package/lib/plugins/pouchdb.js.map +1 -0
- package/lib/utils/crypto/index.d.ts +3 -0
- package/lib/utils/crypto/index.js +34 -0
- package/lib/utils/crypto/index.js.map +1 -0
- package/lib/utils/index.d.ts +4 -0
- package/lib/utils/index.js +58 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/logger/index.d.ts +4 -0
- package/lib/utils/logger/index.js +20 -0
- package/lib/utils/logger/index.js.map +1 -0
- package/lib/utils/logger/transport.d.ts +11 -0
- package/lib/utils/logger/transport.js +28 -0
- package/lib/utils/logger/transport.js.map +1 -0
- package/lib/workers/dataModel.d.ts +1 -0
- package/lib/workers/dataModel.js +48 -0
- package/lib/workers/dataModel.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
const calculateHash = (content) => {
|
|
3
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
4
|
+
};
|
|
5
|
+
const now = () => Date.now();
|
|
6
|
+
export class Job {
|
|
7
|
+
constructor(model, stack) {
|
|
8
|
+
this.model = model;
|
|
9
|
+
this.stack = stack;
|
|
10
|
+
const computed = calculateHash(model.content);
|
|
11
|
+
if (computed !== model.hash) {
|
|
12
|
+
throw new Error(`Job content hash mismatch for ${model._id}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
hydrate() {
|
|
16
|
+
return new Function("stack", "params", "job", `"use strict"; ${this.model.content}; return execute(stack, params, job);`);
|
|
17
|
+
}
|
|
18
|
+
async hasRunningInstance() {
|
|
19
|
+
var _a;
|
|
20
|
+
if (!this.model.isSingleton)
|
|
21
|
+
return false;
|
|
22
|
+
const existingRuns = await this.stack.db.find({
|
|
23
|
+
selector: {
|
|
24
|
+
"~class": "~JobRun",
|
|
25
|
+
jobId: this.model._id,
|
|
26
|
+
status: "RUNNING",
|
|
27
|
+
},
|
|
28
|
+
limit: 1,
|
|
29
|
+
});
|
|
30
|
+
return Boolean((_a = existingRuns === null || existingRuns === void 0 ? void 0 : existingRuns.docs) === null || _a === void 0 ? void 0 : _a.length);
|
|
31
|
+
}
|
|
32
|
+
buildRun(triggerType, runtimeArgs) {
|
|
33
|
+
const id = `JobRun-${crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(16).toString("hex")}`;
|
|
34
|
+
const base = {
|
|
35
|
+
_id: id,
|
|
36
|
+
"~class": "~JobRun",
|
|
37
|
+
jobId: this.model._id,
|
|
38
|
+
status: "PENDING",
|
|
39
|
+
triggerType,
|
|
40
|
+
startTime: now(),
|
|
41
|
+
runtimeArgs,
|
|
42
|
+
initialMetadata: this.model.metadata ? Object.assign({}, this.model.metadata) : undefined,
|
|
43
|
+
};
|
|
44
|
+
return base;
|
|
45
|
+
}
|
|
46
|
+
async persistRun(run) {
|
|
47
|
+
const existing = await this.stack.db.get(run._id).catch(() => null);
|
|
48
|
+
const doc = existing ? Object.assign(Object.assign({}, run), { _rev: existing._rev }) : run;
|
|
49
|
+
await this.stack.db.bulkDocs([doc]);
|
|
50
|
+
return doc;
|
|
51
|
+
}
|
|
52
|
+
async persistJobMetadata(metadata) {
|
|
53
|
+
if (!metadata)
|
|
54
|
+
return;
|
|
55
|
+
const current = await this.stack.db.get(this.model._id).catch(() => null);
|
|
56
|
+
const nextDoc = Object.assign(Object.assign({}, this.model), { _rev: current === null || current === void 0 ? void 0 : current._rev, metadata });
|
|
57
|
+
await this.stack.db.bulkDocs([nextDoc]);
|
|
58
|
+
}
|
|
59
|
+
async execute(runtimeArgs, triggerType = "manual") {
|
|
60
|
+
let run = this.buildRun(triggerType, runtimeArgs);
|
|
61
|
+
run = await this.persistRun(run);
|
|
62
|
+
if (!this.model.isEnabled) {
|
|
63
|
+
run.status = "SKIPPED";
|
|
64
|
+
run.errorMessage = `Job ${this.model._id} is disabled`;
|
|
65
|
+
run.endTime = now();
|
|
66
|
+
run.durationMs = run.endTime - run.startTime;
|
|
67
|
+
await this.persistRun(run);
|
|
68
|
+
throw new Error(run.errorMessage);
|
|
69
|
+
}
|
|
70
|
+
if (await this.hasRunningInstance()) {
|
|
71
|
+
run.status = "SKIPPED";
|
|
72
|
+
run.errorMessage = `Job ${this.model._id} already has a running instance`;
|
|
73
|
+
run.endTime = now();
|
|
74
|
+
run.durationMs = run.endTime - run.startTime;
|
|
75
|
+
await this.persistRun(run);
|
|
76
|
+
throw new Error(run.errorMessage);
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
run.status = "RUNNING";
|
|
80
|
+
run.startTime = now();
|
|
81
|
+
run = await this.persistRun(run);
|
|
82
|
+
const executor = this.hydrate();
|
|
83
|
+
const params = Object.assign(Object.assign({}, (this.model.defaultParams || {})), (runtimeArgs || {}));
|
|
84
|
+
const result = await executor(this.stack, params, this.model);
|
|
85
|
+
const finalMetadata = (result && result.metadata) || this.model.metadata;
|
|
86
|
+
if (finalMetadata) {
|
|
87
|
+
run.finalMetadata = finalMetadata;
|
|
88
|
+
this.model.metadata = finalMetadata;
|
|
89
|
+
await this.persistJobMetadata(finalMetadata);
|
|
90
|
+
}
|
|
91
|
+
run.status = "SUCCESS";
|
|
92
|
+
run.endTime = now();
|
|
93
|
+
run.durationMs = run.endTime - run.startTime;
|
|
94
|
+
return await this.persistRun(run);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
run.status = "FAILURE";
|
|
98
|
+
run.errorMessage = (error === null || error === void 0 ? void 0 : error.message) || String(error);
|
|
99
|
+
run.errorStack = error === null || error === void 0 ? void 0 : error.stack;
|
|
100
|
+
run.endTime = now();
|
|
101
|
+
run.durationMs = run.endTime - run.startTime;
|
|
102
|
+
return await this.persistRun(run);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export class JobEngine {
|
|
107
|
+
constructor(stack) {
|
|
108
|
+
this.stack = stack;
|
|
109
|
+
}
|
|
110
|
+
async executeJob(jobId, runtimeArgs, triggerType = "manual") {
|
|
111
|
+
const jobDoc = await this.stack.db.get(jobId);
|
|
112
|
+
const job = new Job(jobDoc, this.stack);
|
|
113
|
+
return job.execute(runtimeArgs, triggerType);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/job-engine/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type ClientStack from "../stack.js";
|
|
2
|
+
import type { Document } from "@docstack/shared";
|
|
3
|
+
/** The type of operation being authorized: read or write. */
|
|
4
|
+
export type PolicyOperation = "read" | "write";
|
|
5
|
+
/**
|
|
6
|
+
* Engine for evaluating access control policies on documents.
|
|
7
|
+
*
|
|
8
|
+
* PolicyEngine implements role-based access control (RBAC) by evaluating
|
|
9
|
+
* policy rules against documents and user sessions. Policies can be:
|
|
10
|
+
* - Class-level (apply to all documents of a class)
|
|
11
|
+
* - User-specific (apply only to a specific user)
|
|
12
|
+
* - Group-specific (apply only to users in a specific group)
|
|
13
|
+
*
|
|
14
|
+
* Policy rules are JavaScript expressions that receive the document,
|
|
15
|
+
* session, and groupId as context and return a boolean.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Policy engine is used automatically during document operations
|
|
20
|
+
* // Policies are defined as documents:
|
|
21
|
+
* await stack.createDoc(null, '~Policy', null, {
|
|
22
|
+
* name: 'user-read-own',
|
|
23
|
+
* targetClass: ['User'],
|
|
24
|
+
* rule: 'return document.userId === session.userId;'
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class PolicyEngine {
|
|
29
|
+
/** Reference to the parent stack for database and session access. */
|
|
30
|
+
private readonly stack;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a new PolicyEngine instance.
|
|
33
|
+
* @param stack - The parent ClientStack instance
|
|
34
|
+
*/
|
|
35
|
+
constructor(stack: ClientStack);
|
|
36
|
+
/**
|
|
37
|
+
* Gets the current authentication session proof.
|
|
38
|
+
* @returns The session proof, or undefined if not authenticated
|
|
39
|
+
*/
|
|
40
|
+
private getSessionProof;
|
|
41
|
+
/**
|
|
42
|
+
* Checks if a class should bypass policy evaluation.
|
|
43
|
+
* System classes (prefixed with ~) are always allowed.
|
|
44
|
+
*
|
|
45
|
+
* @param targetClass - The class name to check
|
|
46
|
+
* @returns `true` if the class should bypass policies
|
|
47
|
+
*/
|
|
48
|
+
private shouldBypass;
|
|
49
|
+
private loadPolicies;
|
|
50
|
+
private getTargetIdentifiers;
|
|
51
|
+
private resolveClassTarget;
|
|
52
|
+
/**
|
|
53
|
+
* Evaluates a policy rule against a document and session.
|
|
54
|
+
* The rule is a JavaScript expression that returns a boolean.
|
|
55
|
+
*
|
|
56
|
+
* @param policy - The policy containing the rule
|
|
57
|
+
* @param document - The document being accessed
|
|
58
|
+
* @param session - The current auth session
|
|
59
|
+
* @returns Whether the rule permits access
|
|
60
|
+
*/
|
|
61
|
+
private evaluateRule;
|
|
62
|
+
private filterPoliciesForSession;
|
|
63
|
+
private authorize;
|
|
64
|
+
/**
|
|
65
|
+
* Ensures write access is allowed for a document of the given class.
|
|
66
|
+
* Throws an error if no policy permits the write operation.
|
|
67
|
+
*
|
|
68
|
+
* @param targetClass - The class of the document being written
|
|
69
|
+
* @param document - The document to write
|
|
70
|
+
* @throws Error if write is not permitted
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // Called automatically during createDoc/updateCard operations
|
|
75
|
+
* await policyEngine.ensureWriteAllowed('Task', taskDocument);
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
ensureWriteAllowed(targetClass: string, document: Document | null): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Checks if a document is readable by the current user.
|
|
81
|
+
* Used to filter query results based on read policies.
|
|
82
|
+
*
|
|
83
|
+
* @param document - The document to check
|
|
84
|
+
* @returns `true` if the document can be read
|
|
85
|
+
* @throws Error if the stack is not authenticated
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* // Used internally during findDocuments
|
|
90
|
+
* const readable = await policyEngine.isReadableDocument(doc);
|
|
91
|
+
* if (readable) {
|
|
92
|
+
* results.push(doc);
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
isReadableDocument(document: Document): Promise<boolean>;
|
|
97
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const SYSTEM_CLASSES = new Set([
|
|
2
|
+
"~Policy",
|
|
3
|
+
"~Job",
|
|
4
|
+
"~JobRun",
|
|
5
|
+
"~AuthModule",
|
|
6
|
+
"~UserSession",
|
|
7
|
+
"class",
|
|
8
|
+
"domain"
|
|
9
|
+
]);
|
|
10
|
+
export class PolicyEngine {
|
|
11
|
+
constructor(stack) {
|
|
12
|
+
this.stack = stack;
|
|
13
|
+
}
|
|
14
|
+
getSessionProof() {
|
|
15
|
+
return this.stack.authSession;
|
|
16
|
+
}
|
|
17
|
+
shouldBypass(targetClass) {
|
|
18
|
+
if (SYSTEM_CLASSES.has(targetClass))
|
|
19
|
+
return true;
|
|
20
|
+
const normalized = targetClass.startsWith("~") ? targetClass.slice(1) : `~${targetClass}`;
|
|
21
|
+
return SYSTEM_CLASSES.has(normalized);
|
|
22
|
+
}
|
|
23
|
+
async loadPolicies(targetClass, aliases = []) {
|
|
24
|
+
const identifiers = new Set([targetClass, ...aliases]);
|
|
25
|
+
const result = await this.stack.findDocuments({ "~class": "~Policy" });
|
|
26
|
+
return result.docs.filter((doc) => {
|
|
27
|
+
if (!Array.isArray(doc.targetClass))
|
|
28
|
+
return false;
|
|
29
|
+
return doc.targetClass.some((entry) => identifiers.has(entry));
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
getTargetIdentifiers(targetId, targetName) {
|
|
33
|
+
const identifiers = new Set();
|
|
34
|
+
const variants = [targetId, targetName];
|
|
35
|
+
for (const value of variants) {
|
|
36
|
+
identifiers.add(value);
|
|
37
|
+
if (value.startsWith("~")) {
|
|
38
|
+
identifiers.add(value.slice(1));
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
identifiers.add(`~${value}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return Array.from(identifiers);
|
|
45
|
+
}
|
|
46
|
+
async resolveClassTarget(targetClass) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
const classModel = await this.stack.getClassModel(targetClass).catch(() => null);
|
|
49
|
+
return {
|
|
50
|
+
id: (_a = classModel === null || classModel === void 0 ? void 0 : classModel._id) !== null && _a !== void 0 ? _a : targetClass,
|
|
51
|
+
name: (_b = classModel === null || classModel === void 0 ? void 0 : classModel.name) !== null && _b !== void 0 ? _b : targetClass,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async evaluateRule(policy, document, session) {
|
|
55
|
+
const executor = new Function("document", "session", "groupId", `"use strict"; ${policy.rule}`);
|
|
56
|
+
const result = executor(document || {}, session.session, session.session.groupId);
|
|
57
|
+
if (result instanceof Promise) {
|
|
58
|
+
return Boolean(await result);
|
|
59
|
+
}
|
|
60
|
+
return Boolean(result);
|
|
61
|
+
}
|
|
62
|
+
filterPoliciesForSession(policies, session) {
|
|
63
|
+
const sessionUserId = session.session.userId || session.session.username;
|
|
64
|
+
const sessionGroups = Array.isArray(session.session.groupId)
|
|
65
|
+
? session.session.groupId
|
|
66
|
+
: session.session.groupId
|
|
67
|
+
? [session.session.groupId]
|
|
68
|
+
: [];
|
|
69
|
+
return policies.filter((policy) => {
|
|
70
|
+
const matchesUser = !policy.userId || policy.userId === sessionUserId || policy.userId === session.session.username;
|
|
71
|
+
const matchesGroup = !policy.groupId || sessionGroups.includes(policy.groupId);
|
|
72
|
+
return matchesUser && matchesGroup;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async authorize(targetClass, operation, document) {
|
|
76
|
+
const { id: targetId, name: targetName } = await this.resolveClassTarget(targetClass);
|
|
77
|
+
const identifiers = this.getTargetIdentifiers(targetId, targetName);
|
|
78
|
+
if (this.shouldBypass(targetName)) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
const policies = await this.loadPolicies(targetId, identifiers);
|
|
82
|
+
if (policies.length === 0) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const session = this.getSessionProof();
|
|
86
|
+
if (!session) {
|
|
87
|
+
throw new Error("Stack is not authenticated for policy evaluation");
|
|
88
|
+
}
|
|
89
|
+
const targetedPolicies = policies.filter((policy) => policy.userId || policy.groupId);
|
|
90
|
+
const basePolicies = policies.filter((policy) => !policy.userId && !policy.groupId);
|
|
91
|
+
const matchingPolicies = targetedPolicies.length > 0
|
|
92
|
+
? this.filterPoliciesForSession(targetedPolicies, session)
|
|
93
|
+
: this.filterPoliciesForSession(basePolicies, session);
|
|
94
|
+
if (targetedPolicies.length > 0 && matchingPolicies.length === 0) {
|
|
95
|
+
throw new Error(`No matching policy allowed ${operation} on class '${targetClass}'`);
|
|
96
|
+
}
|
|
97
|
+
let allowed = false;
|
|
98
|
+
for (const policy of matchingPolicies) {
|
|
99
|
+
const result = await this.evaluateRule(policy, document, session);
|
|
100
|
+
if (result === false) {
|
|
101
|
+
throw new Error(`Policy '${policy._id}' denied ${operation} on class '${targetClass}'`);
|
|
102
|
+
}
|
|
103
|
+
if (result === true) {
|
|
104
|
+
allowed = true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return allowed;
|
|
108
|
+
}
|
|
109
|
+
async ensureWriteAllowed(targetClass, document) {
|
|
110
|
+
const allowed = await this.authorize(targetClass, "write", document);
|
|
111
|
+
if (!allowed) {
|
|
112
|
+
throw new Error(`No matching policy allowed write on class '${targetClass}'`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async isReadableDocument(document) {
|
|
116
|
+
const targetClass = document === null || document === void 0 ? void 0 : document["~class"];
|
|
117
|
+
const { id: targetId, name: targetName } = await this.resolveClassTarget(targetClass);
|
|
118
|
+
if (!targetClass || this.shouldBypass(targetName)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
const policies = await this.loadPolicies(targetId, this.getTargetIdentifiers(targetId, targetName));
|
|
122
|
+
if (policies.length === 0) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
const session = this.getSessionProof();
|
|
126
|
+
if (!session) {
|
|
127
|
+
throw new Error("Stack is not authenticated for policy evaluation");
|
|
128
|
+
}
|
|
129
|
+
const targetedPolicies = policies.filter((policy) => policy.userId || policy.groupId);
|
|
130
|
+
const basePolicies = policies.filter((policy) => !policy.userId && !policy.groupId);
|
|
131
|
+
const matchingPolicies = targetedPolicies.length > 0
|
|
132
|
+
? this.filterPoliciesForSession(targetedPolicies, session)
|
|
133
|
+
: this.filterPoliciesForSession(basePolicies, session);
|
|
134
|
+
if (targetedPolicies.length > 0 && matchingPolicies.length === 0) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
let permitted = false;
|
|
138
|
+
for (const policy of matchingPolicies) {
|
|
139
|
+
const result = await this.evaluateRule(policy, document, session);
|
|
140
|
+
if (result === false) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (result === true) {
|
|
144
|
+
permitted = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return permitted;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/policy-engine/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates an array of accumulator instances based on the aggregate functions in the query plan.
|
|
3
|
+
* @param {Array<object>} aggregates A list of aggregate function definitions from the plan.
|
|
4
|
+
* @param {string} fromAlias The alias for the FROM table.
|
|
5
|
+
* @param {object} joinAliases A map of join aliases.
|
|
6
|
+
* @returns {Array<object>} An array of initialized accumulator instances.
|
|
7
|
+
* @throws {Error} If an unsupported aggregate function is specified.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAccumulators(aggregates: any, fromAlias: any, joinAliases: any): any;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { evalExpression } from './evaluator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Accumulator for the SUM() aggregate function.
|
|
5
|
+
*/
|
|
6
|
+
class Sum {
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} alias The result alias for this aggregate.
|
|
9
|
+
* @param {object} expr The expression to be summed.
|
|
10
|
+
* @param {string} fromAlias The alias of the FROM table.
|
|
11
|
+
* @param {object} joinAliases A map of join table aliases.
|
|
12
|
+
*/
|
|
13
|
+
constructor(alias, expr, fromAlias, joinAliases) {
|
|
14
|
+
this.alias = alias;
|
|
15
|
+
this.expr = expr;
|
|
16
|
+
this.fromAlias = fromAlias;
|
|
17
|
+
this.joinAliases = joinAliases;
|
|
18
|
+
this.sum = 0;
|
|
19
|
+
this.seen = false;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Adds a row's value to the sum.
|
|
23
|
+
* @param {object} row The row to process.
|
|
24
|
+
*/
|
|
25
|
+
async add(row) {
|
|
26
|
+
const val = await evalExpression(row, this.expr, this.fromAlias, this.joinAliases);
|
|
27
|
+
if (val != null && typeof val === 'number') {
|
|
28
|
+
this.sum += val;
|
|
29
|
+
this.seen = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns the final sum.
|
|
34
|
+
* @returns {number|null} The total sum, or null if no values were added.
|
|
35
|
+
*/
|
|
36
|
+
result() { return this.seen ? this.sum : null; }
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Accumulator for the COUNT() aggregate function.
|
|
40
|
+
*/
|
|
41
|
+
class Count {
|
|
42
|
+
/**
|
|
43
|
+
* @param {string} alias The result alias for this aggregate.
|
|
44
|
+
* @param {object} expr The expression to be counted.
|
|
45
|
+
* @param {string} fromAlias The alias of the FROM table.
|
|
46
|
+
* @param {object} joinAliases A map of join table aliases.
|
|
47
|
+
*/
|
|
48
|
+
constructor(alias, expr, fromAlias, joinAliases) {
|
|
49
|
+
this.alias = alias;
|
|
50
|
+
this.expr = expr;
|
|
51
|
+
this.fromAlias = fromAlias;
|
|
52
|
+
this.joinAliases = joinAliases;
|
|
53
|
+
this.count = 0;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Increments the count for a row. For COUNT(column), it only counts non-null values.
|
|
57
|
+
* For COUNT(*), it counts all rows.
|
|
58
|
+
* @param {object} row The row to process.
|
|
59
|
+
*/
|
|
60
|
+
async add(row) {
|
|
61
|
+
if (this.expr.type === 'star') {
|
|
62
|
+
this.count++;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const val = await evalExpression(row, this.expr, this.fromAlias, this.joinAliases);
|
|
66
|
+
if (val != null) {
|
|
67
|
+
this.count++;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the final count.
|
|
73
|
+
* @returns {number} The total count.
|
|
74
|
+
*/
|
|
75
|
+
result() { return this.count; }
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Accumulator for the AVG() aggregate function.
|
|
79
|
+
*/
|
|
80
|
+
class Avg {
|
|
81
|
+
/**
|
|
82
|
+
* @param {string} alias The result alias for this aggregate.
|
|
83
|
+
* @param {object} expr The expression to be averaged.
|
|
84
|
+
* @param {string} fromAlias The alias of the FROM table.
|
|
85
|
+
* @param {object} joinAliases A map of join table aliases.
|
|
86
|
+
*/
|
|
87
|
+
constructor(alias, expr, fromAlias, joinAliases) {
|
|
88
|
+
this.alias = alias;
|
|
89
|
+
this.expr = expr;
|
|
90
|
+
this.fromAlias = fromAlias;
|
|
91
|
+
this.joinAliases = joinAliases;
|
|
92
|
+
this.sum = 0;
|
|
93
|
+
this.count = 0;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Adds a row's value to the running sum and increments the count.
|
|
97
|
+
* @param {object} row The row to process.
|
|
98
|
+
*/
|
|
99
|
+
async add(row) {
|
|
100
|
+
const val = await evalExpression(row, this.expr, this.fromAlias, this.joinAliases);
|
|
101
|
+
if (val != null && typeof val === 'number') {
|
|
102
|
+
this.sum += val;
|
|
103
|
+
this.count++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Returns the final average.
|
|
108
|
+
* @returns {number|null} The average, or null if no values were added.
|
|
109
|
+
*/
|
|
110
|
+
result() { return this.count > 0 ? this.sum / this.count : null; }
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Accumulator for the MIN() aggregate function.
|
|
114
|
+
*/
|
|
115
|
+
class Min {
|
|
116
|
+
/**
|
|
117
|
+
* @param {string} alias The result alias for this aggregate.
|
|
118
|
+
* @param {object} expr The expression to find the minimum of.
|
|
119
|
+
* @param {string} fromAlias The alias of the FROM table.
|
|
120
|
+
* @param {object} joinAliases A map of join table aliases.
|
|
121
|
+
*/
|
|
122
|
+
constructor(alias, expr, fromAlias, joinAliases) {
|
|
123
|
+
this.alias = alias;
|
|
124
|
+
this.expr = expr;
|
|
125
|
+
this.fromAlias = fromAlias;
|
|
126
|
+
this.joinAliases = joinAliases;
|
|
127
|
+
this.min = null;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Updates the minimum value based on the current row.
|
|
131
|
+
* @param {object} row The row to process.
|
|
132
|
+
*/
|
|
133
|
+
async add(row) {
|
|
134
|
+
const val = await evalExpression(row, this.expr, this.fromAlias, this.joinAliases);
|
|
135
|
+
if (val != null) {
|
|
136
|
+
if (this.min === null || val < this.min) {
|
|
137
|
+
this.min = val;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Returns the final minimum value.
|
|
143
|
+
* @returns {*} The minimum value, or null if no values were processed.
|
|
144
|
+
*/
|
|
145
|
+
result() { return this.min; }
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Accumulator for the MAX() aggregate function.
|
|
149
|
+
*/
|
|
150
|
+
class Max {
|
|
151
|
+
/**
|
|
152
|
+
* @param {string} alias The result alias for this aggregate.
|
|
153
|
+
* @param {object} expr The expression to find the maximum of.
|
|
154
|
+
* @param {string} fromAlias The alias of the FROM table.
|
|
155
|
+
* @param {object} joinAliases A map of join table aliases.
|
|
156
|
+
*/
|
|
157
|
+
constructor(alias, expr, fromAlias, joinAliases) {
|
|
158
|
+
this.alias = alias;
|
|
159
|
+
this.expr = expr;
|
|
160
|
+
this.fromAlias = fromAlias;
|
|
161
|
+
this.joinAliases = joinAliases;
|
|
162
|
+
this.max = null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Updates the maximum value based on the current row.
|
|
166
|
+
* @param {object} row The row to process.
|
|
167
|
+
*/
|
|
168
|
+
async add(row) {
|
|
169
|
+
const val = await evalExpression(row, this.expr, this.fromAlias, this.joinAliases);
|
|
170
|
+
if (val != null) {
|
|
171
|
+
if (this.max === null || val > this.max) {
|
|
172
|
+
this.max = val;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Returns the final maximum value.
|
|
178
|
+
* @returns {*} The maximum value, or null if no values were processed.
|
|
179
|
+
*/
|
|
180
|
+
result() { return this.max; }
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* A wrapper class that adds DISTINCT functionality to another accumulator.
|
|
184
|
+
* It ensures that the inner accumulator only processes unique values.
|
|
185
|
+
*/
|
|
186
|
+
class DistinctWrapper {
|
|
187
|
+
/**
|
|
188
|
+
* @param {object} innerAccumulator The accumulator to wrap (e.g., Count, Sum).
|
|
189
|
+
*/
|
|
190
|
+
constructor(innerAccumulator) {
|
|
191
|
+
this.inner = innerAccumulator;
|
|
192
|
+
this.seen = new Set();
|
|
193
|
+
this.alias = this.inner.alias;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Adds a row's value to the inner accumulator only if it hasn't been seen before.
|
|
197
|
+
* @param {object} row The row to process.
|
|
198
|
+
*/
|
|
199
|
+
async add(row) {
|
|
200
|
+
const val = await evalExpression(row, this.inner.expr, this.inner.fromAlias, this.inner.joinAliases);
|
|
201
|
+
const key = JSON.stringify(val); // Use JSON to handle objects/arrays as keys
|
|
202
|
+
if (!this.seen.has(key)) {
|
|
203
|
+
this.seen.add(key);
|
|
204
|
+
// Delegate to the inner accumulator, which will re-evaluate, but only for unique values
|
|
205
|
+
await this.inner.add(row);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Returns the result from the inner accumulator.
|
|
210
|
+
* @returns {*} The final aggregated result.
|
|
211
|
+
*/
|
|
212
|
+
result() {
|
|
213
|
+
return this.inner.result();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Creates an array of accumulator instances based on the aggregate functions in the query plan.
|
|
218
|
+
* @param {Array<object>} aggregates A list of aggregate function definitions from the plan.
|
|
219
|
+
* @param {string} fromAlias The alias for the FROM table.
|
|
220
|
+
* @param {object} joinAliases A map of join aliases.
|
|
221
|
+
* @returns {Array<object>} An array of initialized accumulator instances.
|
|
222
|
+
* @throws {Error} If an unsupported aggregate function is specified.
|
|
223
|
+
*/
|
|
224
|
+
export function createAccumulators(aggregates, fromAlias, joinAliases) {
|
|
225
|
+
return aggregates.map(agg => {
|
|
226
|
+
const alias = agg.as || agg.expr.name;
|
|
227
|
+
const expr = agg.expr.args.expr;
|
|
228
|
+
const isDistinct = agg.expr.args.distinct;
|
|
229
|
+
let accumulator;
|
|
230
|
+
switch (agg.expr.name) {
|
|
231
|
+
case 'COUNT':
|
|
232
|
+
accumulator = new Count(alias, expr, fromAlias, joinAliases);
|
|
233
|
+
break;
|
|
234
|
+
case 'SUM':
|
|
235
|
+
accumulator = new Sum(alias, expr, fromAlias, joinAliases);
|
|
236
|
+
break;
|
|
237
|
+
case 'AVG':
|
|
238
|
+
accumulator = new Avg(alias, expr, fromAlias, joinAliases);
|
|
239
|
+
break;
|
|
240
|
+
case 'MIN':
|
|
241
|
+
accumulator = new Min(alias, expr, fromAlias, joinAliases);
|
|
242
|
+
break;
|
|
243
|
+
case 'MAX':
|
|
244
|
+
accumulator = new Max(alias, expr, fromAlias, joinAliases);
|
|
245
|
+
break;
|
|
246
|
+
default:
|
|
247
|
+
throw new Error(`Unsupported aggregate function: ${agg.expr.name}`);
|
|
248
|
+
}
|
|
249
|
+
if (isDistinct) {
|
|
250
|
+
// COUNT(*) should not be distinct
|
|
251
|
+
if (expr.type === 'star')
|
|
252
|
+
return accumulator;
|
|
253
|
+
return new DistinctWrapper(accumulator);
|
|
254
|
+
}
|
|
255
|
+
return accumulator;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=accumulators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accumulators.js","sourceRoot":"","sources":["../../../src/core/query-engine/accumulators.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;GAEG;AACH,MAAM,GAAG;IACL;;;;;OAKG;IACH,YAAY,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACb,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACtB,CAAC;IACD;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,GAAG;QACT,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACzC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC;YAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACrB,CAAC;IACL,CAAC;IACD;;;OAGG;IACH,MAAM,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,KAAK;IACN;;;;;MAKE;IACH,YAAY,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC;IACD;;;;OAIG;IACH,KAAK,CAAC,GAAG,CAAC,GAAG;QACT,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;aAAM,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YACnF,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;gBACd,IAAI,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;QACL,CAAC;IACL,CAAC;IACD;;;OAGG;IACH,MAAM,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,GAAG;IACL;;;;;OAKG;IACH,YAAY,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC;IACD;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,GAAG;QACT,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACzC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC;YAChB,IAAI,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;IACL,CAAC;IACD;;;OAGG;IACH,MAAM,KAAK,OAAO,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,GAAG;IACL;;;;;OAKG;IACH,YAAY,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;IACpB,CAAC;IACD;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,GAAG;QACT,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACtC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;YACnB,CAAC;QACL,CAAC;IACL,CAAC;IACD;;;OAGG;IACH,MAAM,KAAK,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,GAAG;IACL;;;;;OAKG;IACH,YAAY,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;IACpB,CAAC;IACD;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,GAAG;QACT,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACtC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;YACnB,CAAC;QACL,CAAC;IACL,CAAC;IACD;;;OAGG;IACH,MAAM,KAAK,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,eAAe;IACjB;;OAEG;IACH,YAAY,gBAAgB;QACxB,IAAI,CAAC,KAAK,GAAG,gBAAgB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,GAAG;QACT,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACrG,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,4CAA4C;QAE7E,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACnB,wFAAwF;YACxF,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,MAAM;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IAC/B,CAAC;CACJ;AAGD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW;IACjE,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QACxB,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAChC,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;QAE1C,IAAI,WAAW,CAAC;QAEhB,QAAO,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,OAAO;gBACR,WAAW,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;gBAC7D,MAAM;YACV,KAAK,KAAK;gBACN,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;gBAC3D,MAAM;YACV,KAAK,KAAK;gBACN,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;gBAC3D,MAAM;YACV,KAAK,KAAK;gBACN,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;gBAC3D,MAAM;YACV,KAAK,KAAK;gBACN,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;gBAC3D,MAAM;YACV;gBACI,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACb,kCAAkC;YAClC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,WAAW,CAAC;YAC7C,OAAO,IAAI,eAAe,CAAC,WAAW,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO,WAAW,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|