@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
166 lines (162 loc) • 5.49 kB
JavaScript
;
var node_buffer = require('node:buffer');
/**
* Owns the generated-route authorization decision used after guard execution.
* Subscriber-facing decisions are detached views and can never mutate this snapshot.
*/
class ApiControllerGeneratedSecuritySnapshot {
static create(decision) {
return decision ? freezeValue(cloneValue(decision)) : undefined;
}
static createMutableScopeWhere(snapshot) {
return cloneValue(snapshot?.scope?.where);
}
static createSubscriberView(snapshot, resource) {
if (!snapshot) {
return undefined;
}
const view = cloneValue(snapshot);
if (resource !== undefined) {
view.resource = resource;
}
return view;
}
static detach(value) {
return cloneValue(value);
}
static withResource(snapshot, resource) {
if (!snapshot || resource === undefined) {
return snapshot;
}
return Object.freeze({
...snapshot,
resource,
});
}
}
/**
* Clones a security graph through own descriptors so no mutable container aliases its source.
* Function values are intentionally retained as executable identities; their containers are detached.
* @template T - Value type.
* @param {T} value - Value to clone.
* @returns {T} Detached clone.
*/
function cloneValue(value) {
return cloneValueWithReferences(value, new WeakMap());
}
/**
* Clones one value while preserving cycles within the detached graph.
* @template T - Value type.
* @param {T} value - Current value.
* @param {WeakMap<object, object>} references - Source-to-clone references.
* @returns {T} Detached value.
*/
function cloneValueWithReferences(value, references) {
if (value === null || typeof value !== "object") {
return value;
}
const source = value;
const existing = references.get(source);
if (existing) {
return existing;
}
if (value instanceof Date) {
return new Date(value);
}
if (value instanceof RegExp) {
return new RegExp(value.source, value.flags);
}
if (node_buffer.Buffer.isBuffer(value)) {
return node_buffer.Buffer.from(value);
}
if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {
return structuredClone(value);
}
if (value instanceof Map) {
const clone = new Map();
references.set(source, clone);
for (const [key, item] of value) {
clone.set(cloneValueWithReferences(key, references), cloneValueWithReferences(item, references));
}
return clone;
}
if (value instanceof Set) {
const clone = new Set();
references.set(source, clone);
for (const item of value) {
clone.add(cloneValueWithReferences(item, references));
}
return clone;
}
const clone = Array.isArray(value) ? [] : Object.create(Object.getPrototypeOf(value));
references.set(source, clone);
for (const key of Reflect.ownKeys(source)) {
if (Array.isArray(value) && key === "length") {
continue;
}
const descriptor = Object.getOwnPropertyDescriptor(source, key);
if (!descriptor) {
continue;
}
Object.defineProperty(clone, key, {
...descriptor,
// Subscriber views must remain independently mutable even when cloned from a frozen canonical snapshot.
// eslint-disable-next-line @elsikora/typescript/naming-convention
configurable: true,
...("value" in descriptor
? {
value: cloneValueWithReferences(descriptor.value, references),
// eslint-disable-next-line @elsikora/typescript/naming-convention
writable: true,
}
: {}),
});
}
return clone;
}
/**
* Recursively freezes detached security containers without mutating executable function identities.
* @template T - Value type.
* @param {T} value - Detached value.
* @returns {T} Deeply frozen value.
*/
function freezeValue(value) {
freezeValueWithReferences(value, new WeakSet());
return value;
}
/**
* Freezes one detached value while preserving cyclic graphs.
* @param {unknown} value - Current value.
* @param {WeakSet<object>} references - Already visited objects.
* @returns {void}
*/
function freezeValueWithReferences(value, references) {
if (!value || typeof value !== "object" || references.has(value)) {
return;
}
references.add(value);
if (value instanceof Map) {
for (const [key, item] of value) {
freezeValueWithReferences(key, references);
freezeValueWithReferences(item, references);
}
}
else if (value instanceof Set) {
for (const item of value) {
freezeValueWithReferences(item, references);
}
}
else {
for (const key of Reflect.ownKeys(value)) {
const descriptor = Object.getOwnPropertyDescriptor(value, key);
if (descriptor && "value" in descriptor) {
freezeValueWithReferences(descriptor.value, references);
}
}
}
if (!ArrayBuffer.isView(value)) {
Object.freeze(value);
}
}
exports.ApiControllerGeneratedSecuritySnapshot = ApiControllerGeneratedSecuritySnapshot;
//# sourceMappingURL=security-snapshot.class.js.map