Skip to content

Commit

Permalink
enhance: Control gcpolicy above controller
Browse files Browse the repository at this point in the history
Fix code scanning alert no. 81: Prototype-polluting assignment

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

Revert "Fix code scanning alert no. 81: Prototype-polluting assignment"

This reverts commit 848b4981b3c563c2bb0e5e7bcc47d39001bf083d.
  • Loading branch information
ntucker committed Jan 4, 2025
1 parent b73fa9a commit d66fb9f
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 93 deletions.
8 changes: 5 additions & 3 deletions packages/core/src/controller/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
} from './actions/index.js';
import ensurePojo from './ensurePojo.js';
import type { EndpointUpdateFunction } from './types.js';
import GCPolicy from '../manager/GCPolicy.js';
import type { GCInterface } from '../state/GCPolicy.js';
import { initialState } from '../state/reducer/createReducer.js';
import selectMeta from '../state/selectMeta.js';
import type { ActionTypes, State } from '../types.js';
Expand All @@ -47,6 +47,7 @@ interface ConstructorProps<D extends GenericDispatch = DataClientDispatch> {
dispatch?: D;
getState?: () => State<unknown>;
memo?: Pick<MemoCache, 'denormalize' | 'query' | 'buildQueryKey'>;
gcPolicy?: GCInterface;
}

const unsetDispatch = (action: unknown): Promise<void> => {
Expand Down Expand Up @@ -93,17 +94,18 @@ export default class Controller<
/**
* Handles garbage collection
*/
declare readonly gcPolicy: GCPolicy;
declare readonly gcPolicy: GCInterface;

constructor({
dispatch = unsetDispatch as any,
getState = unsetState,
memo = new MemoCache(),
gcPolicy = { createCountRef: () => () => () => undefined },
}: ConstructorProps<D> = {}) {
this.dispatch = dispatch;
this.getState = getState;
this.memo = memo;
this.gcPolicy = new GCPolicy(this);
this.gcPolicy = gcPolicy;
}

/*************** Action Dispatchers ***************/
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export {
default as NetworkManager,
ResetError,
} from './manager/NetworkManager.js';
export * from './state/GCPolicy.js';
export {
default as createReducer,
initialState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,47 @@ import type { EntityPath } from '@data-client/normalizr';
import { GC } from '../actionTypes.js';
import Controller from '../controller/Controller.js';

export default class GCPolicy {
protected endpointCount: Record<string, number> = {};
protected entityCount: Record<string, Record<string, number>> = {};
export class GCPolicy implements GCInterface {
protected endpointCount: Record<string, number> = Object.create(null);
protected entityCount: Record<string, Record<string, number>> =
Object.create(null);

protected endpoints = new Set<string>();
protected entities: EntityPath[] = [];
declare protected intervalId: ReturnType<typeof setInterval>;
declare protected controller: Controller;
declare protected options: GCOptions;

constructor(
controller: Controller,
// every 5 min
{ intervalMS = 60 * 1000 * 5 }: GCOptions = {},
) {
this.controller = controller;
this.options = { intervalMS };
}

init(controller: Controller) {
this.controller = controller;

this.intervalId = setInterval(() => {
if (typeof requestIdleCallback === 'function') {
requestIdleCallback(() => this.runSweep(), { timeout: 1000 });
} else {
this.runSweep();
}
}, this.options.intervalMS);
}

cleanup() {
clearInterval(this.intervalId);
}

createCountRef({ key, paths = [] }: { key: string; paths?: EntityPath[] }) {
if (!ENV_DYNAMIC) return () => () => undefined;
// increment
return () => {
this.endpointCount[key]++;
paths.forEach(path => {
if (!(path.key in this.endpointCount)) {
this.entityCount[path.key] = {};
if (!(path.key in this.entityCount)) {
this.entityCount[path.key] = Object.create(null);
}
this.entityCount[path.key][path.pk]++;
});
Expand All @@ -38,34 +53,20 @@ export default class GCPolicy {
if (this.endpointCount[key]-- <= 0) {
// queue for cleanup
this.endpoints.add(key);
this.entities.concat(...paths);
}
paths.forEach(path => {
if (!(path.key in this.endpointCount)) {
return;
}
this.entityCount[path.key][path.pk]--;
if (this.entityCount[path.key][path.pk]-- <= 0) {
// queue for cleanup
this.entities.concat(...paths);
}
});
};
};
}

init() {
// don't run this in nodejs env
if (ENV_DYNAMIC)
this.intervalId = setInterval(() => {
if (typeof requestIdleCallback === 'function') {
requestIdleCallback(() => this.runSweep(), { timeout: 1000 });
} else {
this.runSweep();
}
}, this.options.intervalMS);
}

cleanup() {
clearInterval(this.intervalId);
}

protected runSweep() {
const state = this.controller.getState();
const entities: EntityPath[] = [];
Expand Down Expand Up @@ -94,6 +95,9 @@ export default class GCPolicy {
export interface GCOptions {
intervalMS?: number;
}

const ENV_DYNAMIC =
typeof navigator !== 'undefined' || typeof window !== 'undefined';
export interface CreateCountRef {
({ key, paths }: { key: string; paths?: EntityPath[] }): () => () => void;
}
export interface GCInterface {
createCountRef: CreateCountRef;
}
Loading

0 comments on commit d66fb9f

Please sign in to comment.