@docstack/client 0.1.5 → 0.1.6
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 +10 -0
- package/README.md +1 -1
- package/lib/core/attribute.d.ts +11 -2
- package/lib/core/class.d.ts +29 -6
- package/lib/core/content-transfer.d.ts +178 -0
- package/lib/core/crypto-engine/index.d.ts +82 -1
- package/lib/core/crypto-engine/utils.d.ts +36 -1
- package/lib/core/datamodel/index.d.ts +16 -0
- package/lib/core/domain.d.ts +1 -1
- package/lib/core/guarded-db.d.ts +52 -0
- package/lib/core/index.d.ts +106 -1
- package/lib/core/policy-engine/index.d.ts +35 -0
- package/lib/core/query-engine/classes.d.ts +24 -0
- package/lib/core/query-engine/executor.d.ts +11 -0
- package/lib/core/query-engine/index.d.ts +2 -1
- package/lib/core/query-engine/planner.d.ts +19 -0
- package/lib/core/stack.d.ts +676 -7
- package/lib/core/sync/class-filter.d.ts +106 -0
- package/lib/core/sync/filter-identity.d.ts +53 -0
- package/lib/core/sync/index.d.ts +334 -0
- package/lib/core/sync/internal-docs.d.ts +159 -0
- package/lib/index.d.ts +27 -1
- package/lib/index.js +4976 -607
- package/lib/index.umd.js +5004 -621
- package/lib/plugins/pouchdb.d.ts +43 -3
- package/lib/utils/logger/index.d.ts +28 -4
- package/lib/utils/logger/transport.d.ts +52 -11
- package/package.json +18 -10
- package/lib/core/attribute.js +0 -406
- package/lib/core/attribute.js.map +0 -1
- package/lib/core/class.js +0 -774
- package/lib/core/class.js.map +0 -1
- package/lib/core/crypto-engine/index.js +0 -229
- package/lib/core/crypto-engine/index.js.map +0 -1
- package/lib/core/crypto-engine/utils.js +0 -88
- package/lib/core/crypto-engine/utils.js.map +0 -1
- package/lib/core/datamodel/index.js +0 -1308
- package/lib/core/datamodel/index.js.map +0 -1
- package/lib/core/domain.js +0 -423
- package/lib/core/domain.js.map +0 -1
- package/lib/core/index.js +0 -532
- package/lib/core/index.js.map +0 -1
- package/lib/core/job-engine/index.js +0 -220
- package/lib/core/job-engine/index.js.map +0 -1
- package/lib/core/policy-engine/index.js +0 -232
- package/lib/core/policy-engine/index.js.map +0 -1
- package/lib/core/query-engine/accumulators.js +0 -258
- package/lib/core/query-engine/accumulators.js.map +0 -1
- package/lib/core/query-engine/evaluator.js +0 -179
- package/lib/core/query-engine/evaluator.js.map +0 -1
- package/lib/core/query-engine/executor.js +0 -405
- package/lib/core/query-engine/executor.js.map +0 -1
- package/lib/core/query-engine/index.js +0 -4
- package/lib/core/query-engine/index.js.map +0 -1
- package/lib/core/query-engine/parser.js +0 -515
- package/lib/core/query-engine/parser.js.map +0 -1
- package/lib/core/query-engine/planner.js +0 -330
- package/lib/core/query-engine/planner.js.map +0 -1
- package/lib/core/stack.js +0 -1827
- package/lib/core/stack.js.map +0 -1
- package/lib/core/test-utils/docstack.js +0 -222
- package/lib/core/test-utils/docstack.js.map +0 -1
- package/lib/core/trigger/index.js +0 -81
- package/lib/core/trigger/index.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/plugins/pouchdb.js +0 -412
- package/lib/plugins/pouchdb.js.map +0 -1
- package/lib/utils/crypto/index.js +0 -34
- package/lib/utils/crypto/index.js.map +0 -1
- package/lib/utils/index.js +0 -58
- package/lib/utils/index.js.map +0 -1
- package/lib/utils/logger/index.js +0 -20
- package/lib/utils/logger/index.js.map +0 -1
- package/lib/utils/logger/transport.js +0 -28
- package/lib/utils/logger/transport.js.map +0 -1
- package/lib/workers/dataModel.js +0 -48
- package/lib/workers/dataModel.js.map +0 -1
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Calculates a SHA-256 hash of the given content.
|
|
3
|
-
* Used to verify job content integrity.
|
|
4
|
-
* @param content - The string content to hash
|
|
5
|
-
* @returns The hex-encoded hash string
|
|
6
|
-
*/
|
|
7
|
-
const calculateHash = async (content) => {
|
|
8
|
-
const getCrypto = () => globalThis.crypto;
|
|
9
|
-
const crypto = getCrypto();
|
|
10
|
-
const encoder = new TextEncoder();
|
|
11
|
-
const data = encoder.encode(content);
|
|
12
|
-
const buffer = await crypto.subtle.digest('SHA-256', data);
|
|
13
|
-
return Array.from(new Uint8Array(buffer)).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
14
|
-
};
|
|
15
|
-
const now = () => Date.now();
|
|
16
|
-
/**
|
|
17
|
-
* Represents an executable job that can perform background tasks.
|
|
18
|
-
*
|
|
19
|
-
* Jobs are stored as documents with executable content that is verified
|
|
20
|
-
* via hash before execution. They support singleton mode (only one instance
|
|
21
|
-
* can run at a time), metadata persistence, and run history tracking.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* // Jobs are typically executed via JobEngine
|
|
26
|
-
* const run = await stack.jobEngine.executeJob('Job-auth', {
|
|
27
|
-
* password: 'user-password',
|
|
28
|
-
* salt: 'user-salt'
|
|
29
|
-
* });
|
|
30
|
-
* console.log('Job result:', run.finalMetadata);
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
export class Job {
|
|
34
|
-
constructor(model, stack) {
|
|
35
|
-
this.model = model;
|
|
36
|
-
this.stack = stack;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Creates a validated Job instance from a JobModel document.
|
|
40
|
-
* Verifies the content hash to ensure integrity.
|
|
41
|
-
*
|
|
42
|
-
* @param model - The JobModel document from the database
|
|
43
|
-
* @param stack - The parent ClientStack instance
|
|
44
|
-
* @returns A validated Job instance
|
|
45
|
-
* @throws Error if the content hash doesn't match
|
|
46
|
-
*/
|
|
47
|
-
static async create(model, stack) {
|
|
48
|
-
const computed = await calculateHash(model.content);
|
|
49
|
-
if (computed !== model.hash) {
|
|
50
|
-
throw new Error(`Job content hash mismatch for ${model._id}`);
|
|
51
|
-
}
|
|
52
|
-
return new Job(model, stack);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Hydrates the job content into an executable function.
|
|
56
|
-
* The job content must define an `execute(stack, params, job)` function.
|
|
57
|
-
*/
|
|
58
|
-
hydrate() {
|
|
59
|
-
return new Function("stack", "params", "job", `"use strict"; ${this.model.content}; return execute(stack, params, job);`);
|
|
60
|
-
}
|
|
61
|
-
async hasRunningInstance() {
|
|
62
|
-
var _a;
|
|
63
|
-
if (!this.model.isSingleton)
|
|
64
|
-
return false;
|
|
65
|
-
const existingRuns = await this.stack.db.find({
|
|
66
|
-
selector: {
|
|
67
|
-
"~class": "~JobRun",
|
|
68
|
-
jobId: this.model._id,
|
|
69
|
-
status: "RUNNING",
|
|
70
|
-
},
|
|
71
|
-
limit: 1,
|
|
72
|
-
});
|
|
73
|
-
return Boolean((_a = existingRuns === null || existingRuns === void 0 ? void 0 : existingRuns.docs) === null || _a === void 0 ? void 0 : _a.length);
|
|
74
|
-
}
|
|
75
|
-
buildRun(triggerType, runtimeArgs) {
|
|
76
|
-
const getCrypto = () => globalThis.crypto;
|
|
77
|
-
const crypto = getCrypto();
|
|
78
|
-
const id = `JobRun-${crypto.randomUUID ? crypto.randomUUID() :
|
|
79
|
-
Array.from(crypto.getRandomValues(new Uint8Array(16))).map(b => b.toString(16).padStart(2, '0')).join('')}`;
|
|
80
|
-
const base = {
|
|
81
|
-
_id: id,
|
|
82
|
-
"~class": "~JobRun",
|
|
83
|
-
jobId: this.model._id,
|
|
84
|
-
status: "PENDING",
|
|
85
|
-
triggerType,
|
|
86
|
-
startTime: now(),
|
|
87
|
-
runtimeArgs,
|
|
88
|
-
initialMetadata: this.model.metadata ? Object.assign({}, this.model.metadata) : undefined,
|
|
89
|
-
};
|
|
90
|
-
return base;
|
|
91
|
-
}
|
|
92
|
-
async persistRun(run) {
|
|
93
|
-
const existing = await this.stack.db.get(run._id).catch(() => null);
|
|
94
|
-
const doc = existing ? Object.assign(Object.assign({}, run), { _rev: existing._rev }) : run;
|
|
95
|
-
await this.stack.db.bulkDocs([doc]);
|
|
96
|
-
return doc;
|
|
97
|
-
}
|
|
98
|
-
async persistJobMetadata(metadata) {
|
|
99
|
-
if (!metadata)
|
|
100
|
-
return;
|
|
101
|
-
const current = await this.stack.db.get(this.model._id).catch(() => null);
|
|
102
|
-
const nextDoc = Object.assign(Object.assign({}, this.model), { _rev: current === null || current === void 0 ? void 0 : current._rev, metadata });
|
|
103
|
-
await this.stack.db.bulkDocs([nextDoc]);
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Executes the job with optional runtime arguments.
|
|
107
|
-
*
|
|
108
|
-
* Creates a JobRun document to track execution, handles singleton logic,
|
|
109
|
-
* and persists any metadata updates from the job execution.
|
|
110
|
-
*
|
|
111
|
-
* @param runtimeArgs - Optional parameters to pass to the job
|
|
112
|
-
* @param triggerType - How the job was triggered ('manual', 'scheduled', etc.)
|
|
113
|
-
* @returns The completed JobRunModel with status and results
|
|
114
|
-
* @throws Error if the job is disabled or a singleton instance is already running
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* ```typescript
|
|
118
|
-
* const run = await job.execute({ userId: 'user-123' }, 'manual');
|
|
119
|
-
* if (run.status === 'SUCCESS') {
|
|
120
|
-
* console.log('Result:', run.finalMetadata);
|
|
121
|
-
* }
|
|
122
|
-
* ```
|
|
123
|
-
*/
|
|
124
|
-
async execute(runtimeArgs, triggerType = "manual") {
|
|
125
|
-
let run = this.buildRun(triggerType, runtimeArgs);
|
|
126
|
-
run = await this.persistRun(run);
|
|
127
|
-
if (!this.model.isEnabled) {
|
|
128
|
-
run.status = "SKIPPED";
|
|
129
|
-
run.errorMessage = `Job ${this.model._id} is disabled`;
|
|
130
|
-
run.endTime = now();
|
|
131
|
-
run.durationMs = run.endTime - run.startTime;
|
|
132
|
-
await this.persistRun(run);
|
|
133
|
-
throw new Error(run.errorMessage);
|
|
134
|
-
}
|
|
135
|
-
if (await this.hasRunningInstance()) {
|
|
136
|
-
run.status = "SKIPPED";
|
|
137
|
-
run.errorMessage = `Job ${this.model._id} already has a running instance`;
|
|
138
|
-
run.endTime = now();
|
|
139
|
-
run.durationMs = run.endTime - run.startTime;
|
|
140
|
-
await this.persistRun(run);
|
|
141
|
-
throw new Error(run.errorMessage);
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
run.status = "RUNNING";
|
|
145
|
-
run.startTime = now();
|
|
146
|
-
run = await this.persistRun(run);
|
|
147
|
-
const executor = this.hydrate();
|
|
148
|
-
const params = Object.assign(Object.assign({}, (this.model.defaultParams || {})), (runtimeArgs || {}));
|
|
149
|
-
const result = await executor(this.stack, params, this.model);
|
|
150
|
-
const finalMetadata = (result && result.metadata) || this.model.metadata;
|
|
151
|
-
if (finalMetadata) {
|
|
152
|
-
run.finalMetadata = finalMetadata;
|
|
153
|
-
this.model.metadata = finalMetadata;
|
|
154
|
-
await this.persistJobMetadata(finalMetadata);
|
|
155
|
-
}
|
|
156
|
-
run.status = "SUCCESS";
|
|
157
|
-
run.endTime = now();
|
|
158
|
-
run.durationMs = run.endTime - run.startTime;
|
|
159
|
-
return await this.persistRun(run);
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
run.status = "FAILURE";
|
|
163
|
-
run.errorMessage = (error === null || error === void 0 ? void 0 : error.message) || String(error);
|
|
164
|
-
run.errorStack = error === null || error === void 0 ? void 0 : error.stack;
|
|
165
|
-
run.endTime = now();
|
|
166
|
-
run.durationMs = run.endTime - run.startTime;
|
|
167
|
-
return await this.persistRun(run);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Engine for executing background jobs in the DocStack system.
|
|
173
|
-
*
|
|
174
|
-
* The JobEngine provides a simple interface to execute jobs by their ID.
|
|
175
|
-
* Jobs are fetched from the database, validated, and executed with
|
|
176
|
-
* full run tracking and metadata persistence.
|
|
177
|
-
*
|
|
178
|
-
* @example
|
|
179
|
-
* ```typescript
|
|
180
|
-
* // Execute a job
|
|
181
|
-
* const run = await stack.jobEngine.executeJob('Job-process-data', {
|
|
182
|
-
* batchSize: 100
|
|
183
|
-
* });
|
|
184
|
-
*
|
|
185
|
-
* console.log('Status:', run.status);
|
|
186
|
-
* console.log('Duration:', run.durationMs, 'ms');
|
|
187
|
-
* ```
|
|
188
|
-
*/
|
|
189
|
-
export class JobEngine {
|
|
190
|
-
/**
|
|
191
|
-
* Creates a new JobEngine instance.
|
|
192
|
-
* @param stack - The parent ClientStack instance
|
|
193
|
-
*/
|
|
194
|
-
constructor(stack) {
|
|
195
|
-
this.stack = stack;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Executes a job by its document ID.
|
|
199
|
-
*
|
|
200
|
-
* @param jobId - The job document ID (e.g., 'Job-auth')
|
|
201
|
-
* @param runtimeArgs - Optional parameters to pass to the job
|
|
202
|
-
* @param triggerType - How the job was triggered (default: 'manual')
|
|
203
|
-
* @returns The completed JobRunModel with execution results
|
|
204
|
-
*
|
|
205
|
-
* @example
|
|
206
|
-
* ```typescript
|
|
207
|
-
* const authRun = await jobEngine.executeJob('Job-auth', {
|
|
208
|
-
* password: 'secret',
|
|
209
|
-
* salt: 'user-salt'
|
|
210
|
-
* });
|
|
211
|
-
* const derivedKey = authRun.finalMetadata?.derivedKey;
|
|
212
|
-
* ```
|
|
213
|
-
*/
|
|
214
|
-
async executeJob(jobId, runtimeArgs, triggerType = "manual") {
|
|
215
|
-
const jobDoc = await this.stack.db.get(jobId);
|
|
216
|
-
const job = await Job.create(jobDoc, this.stack);
|
|
217
|
-
return job.execute(runtimeArgs, triggerType);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/job-engine/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Set of system classes that bypass policy evaluation.
|
|
3
|
-
* These classes are internal to DocStack and always accessible.
|
|
4
|
-
*/
|
|
5
|
-
const SYSTEM_CLASSES = new Set([
|
|
6
|
-
"~Policy",
|
|
7
|
-
"~Job",
|
|
8
|
-
"~JobRun",
|
|
9
|
-
"~AuthModule",
|
|
10
|
-
"~UserSession",
|
|
11
|
-
"class",
|
|
12
|
-
"domain"
|
|
13
|
-
]);
|
|
14
|
-
/**
|
|
15
|
-
* Engine for evaluating access control policies on documents.
|
|
16
|
-
*
|
|
17
|
-
* PolicyEngine implements role-based access control (RBAC) by evaluating
|
|
18
|
-
* policy rules against documents and user sessions. Policies can be:
|
|
19
|
-
* - Class-level (apply to all documents of a class)
|
|
20
|
-
* - User-specific (apply only to a specific user)
|
|
21
|
-
* - Group-specific (apply only to users in a specific group)
|
|
22
|
-
*
|
|
23
|
-
* Policy rules are JavaScript expressions that receive the document,
|
|
24
|
-
* session, and groupId as context and return a boolean.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```typescript
|
|
28
|
-
* // Policy engine is used automatically during document operations
|
|
29
|
-
* // Policies are defined as documents:
|
|
30
|
-
* await stack.createDoc(null, '~Policy', null, {
|
|
31
|
-
* name: 'user-read-own',
|
|
32
|
-
* targetClass: ['User'],
|
|
33
|
-
* rule: 'return document.userId === session.userId;'
|
|
34
|
-
* });
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export class PolicyEngine {
|
|
38
|
-
/**
|
|
39
|
-
* Creates a new PolicyEngine instance.
|
|
40
|
-
* @param stack - The parent ClientStack instance
|
|
41
|
-
*/
|
|
42
|
-
constructor(stack) {
|
|
43
|
-
this.stack = stack;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Gets the current authentication session proof.
|
|
47
|
-
* @returns The session proof, or undefined if not authenticated
|
|
48
|
-
*/
|
|
49
|
-
getSessionProof() {
|
|
50
|
-
return this.stack.authSession;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Checks if a class should bypass policy evaluation.
|
|
54
|
-
* System classes (prefixed with ~) are always allowed.
|
|
55
|
-
*
|
|
56
|
-
* @param targetClass - The class name to check
|
|
57
|
-
* @returns `true` if the class should bypass policies
|
|
58
|
-
*/
|
|
59
|
-
shouldBypass(targetClass) {
|
|
60
|
-
if (SYSTEM_CLASSES.has(targetClass))
|
|
61
|
-
return true;
|
|
62
|
-
const normalized = targetClass.startsWith("~") ? targetClass.slice(1) : `~${targetClass}`;
|
|
63
|
-
return SYSTEM_CLASSES.has(normalized);
|
|
64
|
-
}
|
|
65
|
-
async loadPolicies(targetClass, aliases = []) {
|
|
66
|
-
const identifiers = new Set([targetClass, ...aliases]);
|
|
67
|
-
const result = await this.stack.findDocuments({ "~class": "~Policy" });
|
|
68
|
-
return result.docs.filter((doc) => {
|
|
69
|
-
if (!Array.isArray(doc.targetClass))
|
|
70
|
-
return false;
|
|
71
|
-
return doc.targetClass.some((entry) => identifiers.has(entry));
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
getTargetIdentifiers(targetId, targetName) {
|
|
75
|
-
const identifiers = new Set();
|
|
76
|
-
const variants = [targetId, targetName];
|
|
77
|
-
for (const value of variants) {
|
|
78
|
-
identifiers.add(value);
|
|
79
|
-
if (value.startsWith("~")) {
|
|
80
|
-
identifiers.add(value.slice(1));
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
identifiers.add(`~${value}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return Array.from(identifiers);
|
|
87
|
-
}
|
|
88
|
-
async resolveClassTarget(targetClass) {
|
|
89
|
-
var _a, _b;
|
|
90
|
-
const classModel = await this.stack.getClassModel(targetClass).catch(() => null);
|
|
91
|
-
return {
|
|
92
|
-
id: (_a = classModel === null || classModel === void 0 ? void 0 : classModel._id) !== null && _a !== void 0 ? _a : targetClass,
|
|
93
|
-
name: (_b = classModel === null || classModel === void 0 ? void 0 : classModel.name) !== null && _b !== void 0 ? _b : targetClass,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Evaluates a policy rule against a document and session.
|
|
98
|
-
* The rule is a JavaScript expression that returns a boolean.
|
|
99
|
-
*
|
|
100
|
-
* @param policy - The policy containing the rule
|
|
101
|
-
* @param document - The document being accessed
|
|
102
|
-
* @param session - The current auth session
|
|
103
|
-
* @returns Whether the rule permits access
|
|
104
|
-
*/
|
|
105
|
-
async evaluateRule(policy, document, session) {
|
|
106
|
-
const executor = new Function("document", "session", "groupId", `"use strict"; ${policy.rule}`);
|
|
107
|
-
const result = executor(document || {}, session.session, session.session.groupId);
|
|
108
|
-
if (result instanceof Promise) {
|
|
109
|
-
return Boolean(await result);
|
|
110
|
-
}
|
|
111
|
-
return Boolean(result);
|
|
112
|
-
}
|
|
113
|
-
filterPoliciesForSession(policies, session) {
|
|
114
|
-
const sessionUserId = session.session.userId || session.session.username;
|
|
115
|
-
const sessionGroups = Array.isArray(session.session.groupId)
|
|
116
|
-
? session.session.groupId
|
|
117
|
-
: session.session.groupId
|
|
118
|
-
? [session.session.groupId]
|
|
119
|
-
: [];
|
|
120
|
-
return policies.filter((policy) => {
|
|
121
|
-
const matchesUser = !policy.userId || policy.userId === sessionUserId || policy.userId === session.session.username;
|
|
122
|
-
const matchesGroup = !policy.groupId || sessionGroups.includes(policy.groupId);
|
|
123
|
-
return matchesUser && matchesGroup;
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
async authorize(targetClass, operation, document) {
|
|
127
|
-
const { id: targetId, name: targetName } = await this.resolveClassTarget(targetClass);
|
|
128
|
-
const identifiers = this.getTargetIdentifiers(targetId, targetName);
|
|
129
|
-
if (this.shouldBypass(targetName)) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
const policies = await this.loadPolicies(targetId, identifiers);
|
|
133
|
-
if (policies.length === 0) {
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
const session = this.getSessionProof();
|
|
137
|
-
if (!session) {
|
|
138
|
-
throw new Error("Stack is not authenticated for policy evaluation");
|
|
139
|
-
}
|
|
140
|
-
const targetedPolicies = policies.filter((policy) => policy.userId || policy.groupId);
|
|
141
|
-
const basePolicies = policies.filter((policy) => !policy.userId && !policy.groupId);
|
|
142
|
-
const matchingPolicies = targetedPolicies.length > 0
|
|
143
|
-
? this.filterPoliciesForSession(targetedPolicies, session)
|
|
144
|
-
: this.filterPoliciesForSession(basePolicies, session);
|
|
145
|
-
if (targetedPolicies.length > 0 && matchingPolicies.length === 0) {
|
|
146
|
-
throw new Error(`No matching policy allowed ${operation} on class '${targetClass}'`);
|
|
147
|
-
}
|
|
148
|
-
let allowed = false;
|
|
149
|
-
for (const policy of matchingPolicies) {
|
|
150
|
-
const result = await this.evaluateRule(policy, document, session);
|
|
151
|
-
if (result === false) {
|
|
152
|
-
throw new Error(`Policy '${policy._id}' denied ${operation} on class '${targetClass}'`);
|
|
153
|
-
}
|
|
154
|
-
if (result === true) {
|
|
155
|
-
allowed = true;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return allowed;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Ensures write access is allowed for a document of the given class.
|
|
162
|
-
* Throws an error if no policy permits the write operation.
|
|
163
|
-
*
|
|
164
|
-
* @param targetClass - The class of the document being written
|
|
165
|
-
* @param document - The document to write
|
|
166
|
-
* @throws Error if write is not permitted
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* ```typescript
|
|
170
|
-
* // Called automatically during createDoc/updateCard operations
|
|
171
|
-
* await policyEngine.ensureWriteAllowed('Task', taskDocument);
|
|
172
|
-
* ```
|
|
173
|
-
*/
|
|
174
|
-
async ensureWriteAllowed(targetClass, document) {
|
|
175
|
-
const allowed = await this.authorize(targetClass, "write", document);
|
|
176
|
-
if (!allowed) {
|
|
177
|
-
throw new Error(`No matching policy allowed write on class '${targetClass}'`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Checks if a document is readable by the current user.
|
|
182
|
-
* Used to filter query results based on read policies.
|
|
183
|
-
*
|
|
184
|
-
* @param document - The document to check
|
|
185
|
-
* @returns `true` if the document can be read
|
|
186
|
-
* @throws Error if the stack is not authenticated
|
|
187
|
-
*
|
|
188
|
-
* @example
|
|
189
|
-
* ```typescript
|
|
190
|
-
* // Used internally during findDocuments
|
|
191
|
-
* const readable = await policyEngine.isReadableDocument(doc);
|
|
192
|
-
* if (readable) {
|
|
193
|
-
* results.push(doc);
|
|
194
|
-
* }
|
|
195
|
-
* ```
|
|
196
|
-
*/
|
|
197
|
-
async isReadableDocument(document) {
|
|
198
|
-
const targetClass = document === null || document === void 0 ? void 0 : document["~class"];
|
|
199
|
-
const { id: targetId, name: targetName } = await this.resolveClassTarget(targetClass);
|
|
200
|
-
if (!targetClass || this.shouldBypass(targetName)) {
|
|
201
|
-
return true;
|
|
202
|
-
}
|
|
203
|
-
const policies = await this.loadPolicies(targetId, this.getTargetIdentifiers(targetId, targetName));
|
|
204
|
-
if (policies.length === 0) {
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
const session = this.getSessionProof();
|
|
208
|
-
if (!session) {
|
|
209
|
-
throw new Error("Stack is not authenticated for policy evaluation");
|
|
210
|
-
}
|
|
211
|
-
const targetedPolicies = policies.filter((policy) => policy.userId || policy.groupId);
|
|
212
|
-
const basePolicies = policies.filter((policy) => !policy.userId && !policy.groupId);
|
|
213
|
-
const matchingPolicies = targetedPolicies.length > 0
|
|
214
|
-
? this.filterPoliciesForSession(targetedPolicies, session)
|
|
215
|
-
: this.filterPoliciesForSession(basePolicies, session);
|
|
216
|
-
if (targetedPolicies.length > 0 && matchingPolicies.length === 0) {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
let permitted = false;
|
|
220
|
-
for (const policy of matchingPolicies) {
|
|
221
|
-
const result = await this.evaluateRule(policy, document, session);
|
|
222
|
-
if (result === false) {
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
if (result === true) {
|
|
226
|
-
permitted = true;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return permitted;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/policy-engine/index.ts"],"names":[],"mappings":"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"}
|