Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
141 changes: 138 additions & 3 deletions packages/node-core/src/indexer/dynamic-ds.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ class TestDynamicDsService extends DynamicDsService<BaseDataSource, ISubqueryPro
}

// Make it public
getTemplate(templateName: string, startBlock?: number | undefined): BaseDataSource {
return super.getTemplate(templateName, startBlock);
getTemplate(templateName: string, startBlock?: number | undefined, endBlock?: number | undefined): BaseDataSource {
return super.getTemplate(templateName, startBlock, endBlock);
}
}

const testParam1 = {templateName: 'Test', startBlock: 1};
const testParam2 = {templateName: 'Test', startBlock: 2};
const testParam3 = {templateName: 'Test', startBlock: 3};
const testParam4 = {templateName: 'Test', startBlock: 4};
const testParamOther = {templateName: 'Other', startBlock: 5};

const mockMetadata = (initData: DatasourceParams[] = []) => {
let datasourceParams: DatasourceParams[] = initData;
Expand All @@ -40,7 +41,7 @@ const mockMetadata = (initData: DatasourceParams[] = []) => {
describe('DynamicDsService', () => {
let service: TestDynamicDsService;
const project = {
templates: [{name: 'Test'}],
templates: [{name: 'Test'}, {name: 'Other'}],
} as any as ISubqueryProject;

beforeEach(() => {
Expand Down Expand Up @@ -70,6 +71,67 @@ describe('DynamicDsService', () => {
]);
});

it('can destroy a dynamic datasource', async () => {
const meta = mockMetadata([testParam1, testParam2]);
await service.init(meta);

await service.destroyDynamicDatasource('Test', 50);

const updatedParams = (service as any)._datasourceParams;
expect(updatedParams[0]).toEqual({...testParam1, endBlock: 50});
expect(updatedParams[1]).toEqual(testParam2);

const datasources = (service as any)._datasources;
expect(datasources[0].endBlock).toBe(50);
});

it('throws error when destroying non-existent datasource', async () => {
const meta = mockMetadata([testParam1]);
await service.init(meta);

await expect(service.destroyDynamicDatasource('NonExistent', 50)).rejects.toThrow(
'Dynamic datasource with template name "NonExistent" not found'
);
});

it('throws error when destroying already destroyed datasource', async () => {
const destroyedParam = {...testParam1, endBlock: 30};
const meta = mockMetadata([destroyedParam]);
await service.init(meta);

await expect(service.destroyDynamicDatasource('Test', 50)).rejects.toThrow(
'Dynamic datasource "Test" is already destroyed'
);
});

it('allows creating new datasource after destroying existing one', async () => {
const meta = mockMetadata([testParam1]);
await service.init(meta);

expect((service as any)._datasourceParams).toEqual([testParam1]);

await service.destroyDynamicDatasource('Test', 50);

const paramsAfterDestroy = (service as any)._datasourceParams;
expect(paramsAfterDestroy[0]).toEqual({...testParam1, endBlock: 50});

const newParam = {templateName: 'Test', startBlock: 60};
await service.createDynamicDatasource(newParam);

const finalParams = (service as any)._datasourceParams;
const destroyedCount = finalParams.filter((p) => p.endBlock !== undefined).length;
const activeCount = finalParams.filter((p) => p.endBlock === undefined).length;

expect(destroyedCount).toBeGreaterThanOrEqual(1);
expect(activeCount).toBeGreaterThanOrEqual(1);

const destroyedParam = finalParams.find((p) => p.startBlock === 1 && p.endBlock === 50);
expect(destroyedParam).toBeDefined();

const newParamFound = finalParams.find((p) => p.startBlock === 60 && !p.endBlock);
expect(newParamFound).toBeDefined();
});
Comment on lines +108 to +135
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Strengthen count assertions for precision.

Lines 127-128 use toBeGreaterThanOrEqual(1), but after destroying one datasource and creating one new datasource, the counts should be exact: 1 destroyed and 1 active. Weak assertions may miss bugs where extra datasources are inadvertently created or destroyed.

Apply this diff:

-    expect(destroyedCount).toBeGreaterThanOrEqual(1);
-    expect(activeCount).toBeGreaterThanOrEqual(1);
+    expect(destroyedCount).toBe(1);
+    expect(activeCount).toBe(1);
🤖 Prompt for AI Agents
In packages/node-core/src/indexer/dynamic-ds.service.spec.ts around lines 108 to
135, the test uses weak assertions (toBeGreaterThanOrEqual(1)) for
destroyedCount and activeCount which should be exact after destroying one
datasource and creating one new one; change those two assertions to
expect(destroyedCount).toBe(1) and expect(activeCount).toBe(1) so the test
verifies exactly one destroyed and one active datasource, preventing unnoticed
extra creations or destructions.


it('resets dynamic datasources', async () => {
const meta = mockMetadata([testParam1, testParam2, testParam3, testParam4]);
await service.init(meta);
Expand All @@ -83,6 +145,25 @@ describe('DynamicDsService', () => {
]);
});

it('handles reset after datasource destruction correctly', async () => {
const params = [testParam1, testParam2, testParam3, testParam4];
const meta = mockMetadata(params);
await service.init(meta);

await service.destroyDynamicDatasource('Test', 25); // Destroys testParam1

const paramsAfterDestroy = (service as any)._datasourceParams;
expect(paramsAfterDestroy[0]).toEqual({...testParam1, endBlock: 25});

// Reset to block 2 (should keep testParam1 and testParam2)
await service.resetDynamicDatasource(2, null as any);

const paramsAfterReset = (service as any)._datasourceParams;
expect(paramsAfterReset).toHaveLength(2);
expect(paramsAfterReset[0]).toEqual({...testParam1, endBlock: 25});
expect(paramsAfterReset[1]).toEqual(testParam2);
});

it('getDynamicDatasources with force reloads from metadata', async () => {
const meta = mockMetadata([testParam1, testParam2]);
await service.init(meta);
Expand All @@ -107,6 +188,29 @@ describe('DynamicDsService', () => {
]);
});

it('loads destroyed datasources with endBlock correctly', async () => {
const destroyedParam = {...testParam1, endBlock: 100};
const meta = mockMetadata([destroyedParam, testParam2]);
await service.init(meta);

const datasources = await service.getDynamicDatasources();
expect(datasources).toHaveLength(2);
expect((datasources[0] as any).endBlock).toBe(100);
expect((datasources[1] as any).endBlock).toBeUndefined();
});

it('updates metadata correctly when destroying datasource', async () => {
const meta = mockMetadata([testParam1, testParam2]);
await service.init(meta);

await service.destroyDynamicDatasource('Test', 75);

const metadataParams = await meta.find('dynamicDatasources');
expect(metadataParams).toBeDefined();
expect(metadataParams![0]).toEqual({...testParam1, endBlock: 75});
expect(metadataParams![1]).toEqual(testParam2);
Comment on lines +205 to +215
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

This metadata assertion is currently non-diagnostic.

These checks depend on mockMetadata, but that fixture only clones the array, not the DatasourceParams entries. Mutating (service as any)._datasourceParams[0].endBlock can therefore mutate the backing datasourceParams object too, so meta.find('dynamicDatasources') may look “persisted” even if DynamicDsService never called set.

🧪 One way to make the fixture independent
const cloneParam = (param: DatasourceParams): DatasourceParams => ({
  ...param,
  args: param.args ? {...param.args} : undefined,
});

const mockMetadata = (initData: DatasourceParams[] = []) => {
  let datasourceParams: DatasourceParams[] = initData.map(cloneParam);

  return {
    set: (_key: string, value: DatasourceParams[]) => {
      datasourceParams = value.map(cloneParam);
    },
    find: (_key: string) => Promise.resolve(datasourceParams.map(cloneParam)),
    setNewDynamicDatasource: (params: DatasourceParams) => datasourceParams.push(cloneParam(params)),
  } as unknown as CacheMetadataModel;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/node-core/src/indexer/dynamic-ds.service.spec.ts` around lines 205 -
215, The test's metadata assertions are non-diagnostic because mockMetadata
currently shallow-clones the array but not each DatasourceParams, so mutations
to (service as any)._datasourceParams[0].endBlock can mutate the fixture and
make meta.find appear updated even if DynamicDsService never called set; fix
mockMetadata to deep-clone each DatasourceParams (including args object) on
initialization, on set/setNewDynamicDatasource, and when returning from find so
returned objects are independent copies, then re-run the test that calls
service.init(meta) and service.destroyDynamicDatasource('Test', 75, 0) and
assert meta.find('dynamicDatasources') reflects only real persisted updates.

});

it('can find a template and cannot mutate the template', () => {
const template1 = service.getTemplate('Test', 1);
const template2 = service.getTemplate('Test', 2);
Expand All @@ -120,4 +224,35 @@ describe('DynamicDsService', () => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expect(project.templates![0]).toEqual({name: 'Test'});
});

it('can create template with endBlock', () => {
const template = service.getTemplate('Test', 1, 100);

expect(template.startBlock).toBe(1);
expect((template as any).endBlock).toBe(100);
expect((template as any).name).toBeUndefined();
});

it('handles multiple templates with same name during destruction', async () => {
const param1 = {templateName: 'Test', startBlock: 1};
const param2 = {templateName: 'Test', startBlock: 5};
const param3 = {templateName: 'Other', startBlock: 3};

const meta = mockMetadata([param1, param2, param3]);
await service.init(meta);

// Should destroy the first matching one
await service.destroyDynamicDatasource('Test', 10);

const updatedParams = (service as any)._datasourceParams;
expect(updatedParams[0]).toEqual({...param1, endBlock: 10});
expect(updatedParams[1]).toEqual(param2); // Not destroyed
expect(updatedParams[2]).toEqual(param3); // Not destroyed
});

it('throws error when service not initialized for destruction', async () => {
await expect(service.destroyDynamicDatasource('Test', 50)).rejects.toThrow(
'DynamicDsService has not been initialized'
);
});
});
38 changes: 34 additions & 4 deletions packages/node-core/src/indexer/dynamic-ds.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ export interface DatasourceParams {
templateName: string;
args?: Record<string, unknown>;
startBlock: number;
endBlock?: number;
}

export interface IDynamicDsService<DS> {
dynamicDatasources: DS[];
createDynamicDatasource(params: DatasourceParams): Promise<DS>;
destroyDynamicDatasource(templateName: string, currentBlockHeight: number): Promise<void>;
getDynamicDatasources(forceReload?: boolean): Promise<DS[]>;
}

Expand Down Expand Up @@ -91,6 +93,34 @@ export class DynamicDsService<DS extends BaseDataSource = BaseDataSource, P exte
}
}

async destroyDynamicDatasource(templateName: string, currentBlockHeight: number, tx?: Transaction): Promise<void> {
if (!this._datasources || !this._datasourceParams) {
throw new Error('DynamicDsService has not been initialized');
}

const dsIndex = this._datasourceParams.findIndex((params) => params.templateName === templateName);
if (dsIndex === -1) {
throw new Error(`Dynamic datasource with template name "${templateName}" not found`);
}

const dsParam = this._datasourceParams[dsIndex];

if (dsParam.endBlock !== undefined) {
throw new Error(`Dynamic datasource "${templateName}" is already destroyed`);
}

const updatedParams = {...dsParam, endBlock: currentBlockHeight};
this._datasourceParams[dsIndex] = updatedParams;

if (this._datasources[dsIndex]) {
(this._datasources[dsIndex] as any).endBlock = currentBlockHeight;
}
Comment thread
stwiname marked this conversation as resolved.

await this.metadata.set(METADATA_KEY, this._datasourceParams, tx);
Comment on lines +165 to +179
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

In-memory state updated before persistence could cause inconsistency.

If metadata.set fails, the in-memory state (_datasourceParams[index] and _datasources[index].endBlock) is already modified, leaving the service in an inconsistent state. Compare with createDynamicDatasource which persists to metadata before updating in-memory state.

Consider reordering to persist first:

-   // Update the datasource params
-   const updatedParams = {...dsParam, endBlock: currentBlockHeight};
-   this._datasourceParams[index] = updatedParams;
-
-   // Update the datasource object if it exists
-   const datasource = this._datasources[index];
-   if (!datasource) {
-     throw new Error(`Datasources array out of sync with params at index ${index}`);
-   }
-   // Set endBlock on the datasource object
-   datasource.endBlock = currentBlockHeight;
-
-   await this.metadata.set(METADATA_KEY, this._datasourceParams, tx);
+   // Prepare updated params
+   const updatedParams = {...dsParam, endBlock: currentBlockHeight};
+
+   // Create a copy for persistence
+   const paramsForPersistence = [...this._datasourceParams];
+   paramsForPersistence[index] = updatedParams;
+
+   // Persist first, then update in-memory on success
+   await this.metadata.set(METADATA_KEY, paramsForPersistence, tx);
+
+   // Update in-memory state only after successful persistence
+   this._datasourceParams[index] = updatedParams;
+
+   const datasource = this._datasources[index];
+   if (!datasource) {
+     throw new Error(`Datasources array out of sync with params at index ${index}`);
+   }
+   datasource.endBlock = currentBlockHeight;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
packages/node-core/src/indexer/dynamic-ds.service.ts around lines 165 to 179:
the code mutates in-memory state (_datasourceParams[index] and
_datasources[index].endBlock) before calling metadata.set, which can leave the
service inconsistent if persistence fails; instead, build the updated params
object/array but do NOT assign it into _datasourceParams or modify
datasource.endBlock until metadata.set(METADATA_KEY, updatedParamsArray, tx)
completes successfully; after metadata.set resolves, then assign
this._datasourceParams[index] = updatedParams and set
this._datasources[index].endBlock = currentBlockHeight (and keep throwing the
same error if datasource is missing before doing any in-memory mutation).


logger.info(`Destroyed dynamic datasource "${templateName}" at block ${currentBlockHeight}`);
}

// Not force only seems to be used for project changes
async getDynamicDatasources(forceReload?: boolean): Promise<DS[]> {
// Workers should not cache this result in order to keep in sync
Expand All @@ -117,19 +147,19 @@ export class DynamicDsService<DS extends BaseDataSource = BaseDataSource, P exte
*
* This will throw if the template cannot be found by name.
*
* Inserts the startBlock into the template.
* Inserts the startBlock and optionally endBlock into the template.
* */
protected getTemplate(templateName: string, startBlock?: number): DS {
protected getTemplate(templateName: string, startBlock?: number, endBlock?: number): DS {
const t = (this.project.templates ?? []).find((t) => t.name === templateName);
if (!t) {
throw new Error(`Unable to find matching template in project for name: "${templateName}"`);
}
const {name, ...template} = cloneDeep(t);
return {...template, startBlock} as DS;
return {...template, startBlock, endBlock} as DS;
}

private async getDatasource(params: DatasourceParams): Promise<DS> {
const dsObj = this.getTemplate(params.templateName, params.startBlock);
const dsObj = this.getTemplate(params.templateName, params.startBlock, params.endBlock);

try {
await this.blockchainService.updateDynamicDs(params, dsObj);
Expand Down
23 changes: 23 additions & 0 deletions packages/node-core/src/indexer/indexer.manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,29 @@ export abstract class BaseIndexerManager<
dynamicDsCreated = true;
}, 'createDynamicDatasource');

// Inject function to destroy ds into vm
vm.freeze(async (templateName?: string) => {
if (!templateName) {
throw new Error('Cannot destroy datasource: template name must be provided');
}

await this.dynamicDsService.destroyDynamicDatasource(templateName, blockHeight);

// Mark datasources with this template for removal from current processing
filteredDataSources.forEach((fds) => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The destroyed dynamic datasources should be removed from filteredDatasources, at this point it shouldn't be used anymore.

const dsParams = this.dynamicDsService.dynamicDatasources.find((dynamicDs) => {
// Find the corresponding params for this datasource
const params = (this.dynamicDsService as any)._datasourceParams?.find(
(p: any) => p.templateName === templateName && p.startBlock === (fds as any).startBlock
);
return params !== undefined;
});
if (dsParams) {
(fds as any).endBlock = blockHeight;
}
});
}, 'destroyDynamicDatasource');

Comment on lines +124 to +136
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

In-block destroy isn’t effective: reassign doesn’t affect current iteration; filter logic won’t exclude endBlock === current block.

  • Reassigning filteredDataSources won’t change the array that indexBlockData is iterating.
  • filterDataSources includes ds where endBlock >= height, so a destroyed ds with endBlock === blockHeight will still be included for this block.

Fix by removing the destroyed DS from filteredDataSources in place using object identity.

Apply this diff:

         vm.freeze(async (templateName: string, index: number) => {
           await this.dynamicDsService.destroyDynamicDatasource(templateName, blockHeight, index);

-          // Re-filter datasources to exclude the destroyed one
-          // The destroyed datasource now has endBlock set, so filterDataSources will exclude it
-          // Note: Reassigning filteredDataSources is intentional - subsequent handlers
-          // within the same block will see the updated filtered list
-          filteredDataSources = this.filterDataSources(blockHeight, filteredDataSources);
+          // Remove the destroyed DS from the current list IN PLACE so the rest of this block
+          // no longer schedules it. EndBlock handles exclusion from subsequent blocks.
+          const allDynamic = await this.dynamicDsService.getDynamicDatasources();
+          const destroyed = allDynamic[index] as DS | undefined;
+          if (destroyed) {
+            const pos = filteredDataSources.indexOf(destroyed);
+            if (pos !== -1) filteredDataSources.splice(pos, 1);
+          }
         }, 'destroyDynamicDatasource');

Run this script to confirm indexBlockData iterates the original array (so reassigning the variable is ineffective):


🏁 Script executed:

#!/bin/bash
# Look for indexBlockData implementations and how 'dataSources' is iterated
rg -nP -C3 '(?:async\s+)?indexBlockData\s*\(.*dataSources\s*:\s*[^\)]*\)' --type ts
rg -nP -C3 '\bfor\s*\(\s*const\s+\w+\s+of\s+dataSources\b|\bdataSources\.forEach\(' --type ts

Length of output: 2595


I need to gather more information about the indexing flow. Let me search for the complete context.

I need to examine the indexBlockData implementation and the filterDataSources logic to verify the claims.

Let me search directly in the codebase for the relevant implementations.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find indexBlockData implementation with context
rg -nA20 'indexBlockData' packages/node-core/src/indexer/indexer.manager.ts --type ts

Length of output: 2063


🏁 Script executed:

#!/bin/bash
# Find filterDataSources implementation with endBlock logic
rg -nA15 'filterDataSources' packages/node-core/src/indexer/indexer.manager.ts --type ts

Length of output: 2146


🏁 Script executed:

#!/bin/bash
# Get the full context around lines 100-160 in indexer.manager.ts
sed -n '100,160p' packages/node-core/src/indexer/indexer.manager.ts

Length of output: 2380


Let me check for all implementations of indexBlockData to ensure the pattern is consistent:


🏁 Script executed:

#!/bin/bash
# Find all indexBlockData implementations
rg -nB2 -A10 'indexBlockData\s*\(' packages/ --type ts -g '!*.spec.ts' | grep -A10 'for\|forEach'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Verify when vm.freeze callbacks are executed - search for where handlers use injected functions
rg -nC5 'destroyDynamicDatasource|createDynamicDatasource' packages/ --type ts -g '!*.spec.ts' | head -60

Length of output: 4941


The review comment is verified as correct and identifies a real bug.

Based on my analysis of the codebase:

  1. Reassignment ineffectiveness confirmed: The indexBlockData method iterates over filteredDataSources with for...of (line 193). Reassigning the variable inside the callback doesn't affect the ongoing iteration—only in-place modifications (like push at line 115) would work during iteration.

  2. Filter logic issue confirmed: The filterDataSources condition at line 158 is (ds.endBlock ?? Number.MAX_SAFE_INTEGER) >= nextProcessingHeight. When a DS is destroyed with endBlock === blockHeight, this condition evaluates to true, so the destroyed DS is NOT excluded for the current block.

  3. Fix is sound: Using splice() with indexOf() to remove the destroyed DS in-place would correctly remove it from the array during iteration, affecting subsequent handler executions in the same block.

🤖 Prompt for AI Agents
In packages/node-core/src/indexer/indexer.manager.ts around lines 124-134, the
current callback reassigns filteredDataSources after destroying a dynamic
datasource which doesn't affect an ongoing for...of iteration; replace that
reassignment with an in-place removal: locate the destroyed datasource in
filteredDataSources by matching templateName and index (or the datasource
identifier used elsewhere) and call filteredDataSources.splice(foundIndex, 1) so
subsequent handlers in the same block see it removed; do not reassign the
variable. Also verify and, if necessary, fix filterDataSources' condition so a
datasource with endBlock === blockHeight is excluded from current processing
(e.g., use > nextProcessingHeight or adjust the comparison) to avoid future
inconsistencies.

✅ Addressed in commit 1382702

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gmin2 it would be good to address this and to have a test that confirms the correct behaviour

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

return vm;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import {DatasourceParams, IDynamicDsService} from '../dynamic-ds.service';

export type HostDynamicDS<DS> = {
dynamicDsCreateDynamicDatasource: (params: DatasourceParams) => Promise<DS>;
dynamicDsDestroyDynamicDatasource: (templateName: string, currentBlockHeight: number) => Promise<void>;
dynamicDsGetDynamicDatasources: () => Promise<DS[]>;
};

export const hostDynamicDsKeys: (keyof HostDynamicDS<any>)[] = [
'dynamicDsCreateDynamicDatasource',
'dynamicDsDestroyDynamicDatasource',
'dynamicDsGetDynamicDatasources',
];

Expand All @@ -32,6 +34,10 @@ export class WorkerDynamicDsService<DS> implements IDynamicDsService<DS> {
return this.host.dynamicDsCreateDynamicDatasource(JSON.parse(JSON.stringify(params)));
}

async destroyDynamicDatasource(templateName: string, currentBlockHeight: number): Promise<void> {
return this.host.dynamicDsDestroyDynamicDatasource(templateName, currentBlockHeight);
}

async getDynamicDatasources(): Promise<DS[]> {
return this.host.dynamicDsGetDynamicDatasources();
}
Expand All @@ -40,6 +46,7 @@ export class WorkerDynamicDsService<DS> implements IDynamicDsService<DS> {
export function dynamicDsHostFunctions<DS>(dynamicDsService: IDynamicDsService<DS>): HostDynamicDS<DS> {
return {
dynamicDsCreateDynamicDatasource: dynamicDsService.createDynamicDatasource.bind(dynamicDsService),
dynamicDsDestroyDynamicDatasource: dynamicDsService.destroyDynamicDatasource.bind(dynamicDsService),
dynamicDsGetDynamicDatasources: dynamicDsService.getDynamicDatasources.bind(dynamicDsService),
};
}
3 changes: 2 additions & 1 deletion packages/types-core/src/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0

import type Pino from 'pino';
import {Cache, DynamicDatasourceCreator} from './interfaces';
import {Cache, DynamicDatasourceCreator, DynamicDatasourceDestructor} from './interfaces';
import {Store} from './store';

// base global
Expand All @@ -12,4 +12,5 @@ declare global {
const cache: Cache;
const chainId: string;
const createDynamicDatasource: DynamicDatasourceCreator;
const destroyDynamicDatasource: DynamicDatasourceDestructor;
}
1 change: 1 addition & 0 deletions packages/types-core/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0

export type DynamicDatasourceCreator = (name: string, args: Record<string, unknown>) => Promise<void>;
export type DynamicDatasourceDestructor = (name?: string) => Promise<void>;

export interface Cache<T extends Record<string, any> = Record<string, any>> {
set(key: keyof T, value: T[keyof T]): Promise<void>;
Expand Down