Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/parsed-policy-statement.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RulesLogic } from "json-logic-js";
import { randomUUID } from "node:crypto";
import { createRandomId } from "./utils/random-id.js";
import { PolicyStatement } from "./types.js";
import { arrayify } from "./utils/arr.js";
import { traverseRulesLogic } from "./utils/logic.js";
Expand Down Expand Up @@ -100,7 +100,7 @@ export function parsePolicyStatement(
const { action, constraint, effect } = statement;
const actions = arrayify(action);

const sid = opts.sid ?? statement.sid ?? randomUUID();
const sid = opts.sid ?? statement.sid ?? createRandomId();
const gid = opts.gid;

return {
Expand Down
2 changes: 1 addition & 1 deletion lib/policy-resolver.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import assert from "node:assert";
import { describe, it, mock } from "node:test";
import { beforeEach, describe, it, mock } from "node:test";
import { parsePolicyStatement } from "./parsed-policy-statement.js";
import { PolicyResolver } from "./policy-resolver.js";
import { IndexedStatementsStore } from "./store/index.js";
Expand Down
4 changes: 2 additions & 2 deletions lib/policy-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pathExists from "just-has";
import jsonLogic from "json-logic-js";
import { LRUCache } from "lru-cache";
import { randomUUID } from "node:crypto";
import { CachedStatementsStore } from "./store/cached-statements-store.js";
import { PolicyStatementStore } from "./store/types.js";
import { createRandomId } from "./utils/random-id.js";
import {
ParsedPolicyStatement,
parsePolicyStatement,
Expand Down Expand Up @@ -58,7 +58,7 @@ export class PolicyResolver {
docs.forEach((doc) => {
validator.validate(doc);

const gid = doc.id ?? randomUUID();
const gid = doc.id ?? createRandomId();

const parsed = arrayify(doc.statement).map((statement) =>
parsePolicyStatement(statement),
Expand Down
5 changes: 3 additions & 2 deletions lib/store/cached-statements-store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LRUCache } from "lru-cache";
import assert from "node:assert";
import { ParsedPolicyStatement } from "../parsed-policy-statement.js";
import { TypedEmitter } from "../utils/events.js";
import { IndexedStatementsStore } from "./indexed-statements-store.js";
Expand Down Expand Up @@ -72,7 +71,9 @@ export class CachedStatementsStore
#mustGet(sid: string): ParsedPolicyStatement {
const statement = this.#store.get(sid);

assert.ok(statement, `no statement with sid '${sid}'`);
if (!statement) {
throw new Error(`no statement with sid '${sid}'`);
}

return statement;
}
Expand Down
5 changes: 3 additions & 2 deletions lib/store/indexed-statements-store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import uniq from "just-unique";
import assert from "node:assert";
import { ParsedPolicyStatement } from "../parsed-policy-statement.js";
import { TypedEmitter } from "../utils/events.js";
import {
Expand Down Expand Up @@ -154,7 +153,9 @@ export class IndexedStatementsStore
#mustGet(sid: string): ParsedPolicyStatement {
const statement = this.#statements.get(sid);

assert.ok(statement, `no statement with sid '${sid}'`);
if (!statement) {
throw new Error(`no statement with sid '${sid}'`);
}

return statement;
}
Expand Down
31 changes: 24 additions & 7 deletions lib/utils/events.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import EventEmitter from "node:events";

type EventMap = Record<string, unknown>;

type EventKey<T extends EventMap> = string & keyof T;
Expand All @@ -12,20 +10,39 @@ export interface Emitter<T extends EventMap> {
}

export class TypedEmitter<T extends EventMap> implements Emitter<T> {
private emitter = new EventEmitter();
private listeners = new Map<string, Set<EventReceiver<unknown>>>();

on<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>) {
this.emitter.on(eventName, fn);
const listeners =
this.listeners.get(eventName) ?? new Set<EventReceiver<unknown>>();
listeners.add(fn as EventReceiver<unknown>);
this.listeners.set(eventName, listeners);
}

off<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>) {
this.emitter.off(eventName, fn);
const listeners = this.listeners.get(eventName);
if (!listeners) {
return;
}

listeners.delete(fn as EventReceiver<unknown>);
if (listeners.size === 0) {
this.listeners.delete(eventName);
}
}

emit<K extends EventKey<T>>(eventName: K, params: T[K]) {
this.emitter.emit(eventName, params);
const listeners = this.listeners.get(eventName);
if (!listeners) {
return;
}

for (const listener of listeners) {
listener(params);
}
}

removeAllListeners() {
this.emitter.removeAllListeners();
this.listeners.clear();
}
}
10 changes: 10 additions & 0 deletions lib/utils/random-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function createRandomId(): string {
const cryptoApi = globalThis.crypto;
if (cryptoApi && typeof cryptoApi.randomUUID === "function") {
return cryptoApi.randomUUID();
}

const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).slice(2, 14);
return `${timestamp}-${random}`;
}
Loading
Loading