mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
feat(editor): Add boilerplate for SQLite WASM integration and runData worker (no-changelog) (#18959)
This commit is contained in:
@@ -48,6 +48,7 @@
|
||||
"@n8n/utils": "workspace:*",
|
||||
"@replit/codemirror-indentation-markers": "^6.5.3",
|
||||
"@sentry/vue": "catalog:frontend",
|
||||
"@sqlite.org/sqlite-wasm": "3.50.4-build1",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@typescript/vfs": "^1.6.0",
|
||||
"@vue-flow/background": "^1.3.2",
|
||||
|
||||
48
packages/frontend/editor-ui/src/workers/database.ts
Normal file
48
packages/frontend/editor-ui/src/workers/database.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';
|
||||
import type { Promiser, DbId } from '@sqlite.org/sqlite-wasm';
|
||||
|
||||
export type DatabaseTable = {
|
||||
name: string;
|
||||
schema: string;
|
||||
};
|
||||
|
||||
export type DatabaseConfig = {
|
||||
filename: `file:${string}.sqlite3?vfs=opfs`;
|
||||
tables: Record<string, DatabaseTable>;
|
||||
};
|
||||
|
||||
export async function initializeDatabase(config: DatabaseConfig) {
|
||||
// Initialize the SQLite worker
|
||||
const promiser: Promiser = await new Promise((resolve) => {
|
||||
const _promiser = sqlite3Worker1Promiser({
|
||||
onready: () => resolve(_promiser),
|
||||
});
|
||||
});
|
||||
|
||||
if (!promiser) throw new Error('Failed to initialize promiser');
|
||||
|
||||
// Get configuration and open database
|
||||
const cfg = await promiser('config-get', {});
|
||||
const openResponse = await promiser('open', {
|
||||
filename: config.filename,
|
||||
});
|
||||
|
||||
if (openResponse.type === 'error') {
|
||||
throw new Error(openResponse.result.message);
|
||||
}
|
||||
|
||||
const dbId: DbId = openResponse.result.dbId;
|
||||
|
||||
for (const table of Object.values(config.tables)) {
|
||||
await promiser('exec', {
|
||||
dbId,
|
||||
sql: table.schema,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
promiser,
|
||||
dbId,
|
||||
cfg,
|
||||
};
|
||||
}
|
||||
19
packages/frontend/editor-ui/src/workers/run-data/db.ts
Normal file
19
packages/frontend/editor-ui/src/workers/run-data/db.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { DatabaseConfig } from '@/workers/database';
|
||||
|
||||
export const databaseConfig: DatabaseConfig = {
|
||||
filename: 'file:n8n.sqlite3?vfs=opfs',
|
||||
tables: {
|
||||
executions: {
|
||||
name: 'executions',
|
||||
schema: `
|
||||
CREATE TABLE IF NOT EXISTS executions (
|
||||
id INTEGER PRIMARY KEY,
|
||||
workflow_id INTEGER NOT NULL,
|
||||
data TEXT CHECK (json_valid(data)) NOT NULL,
|
||||
workflow TEXT CHECK (json_valid(workflow)) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
@@ -0,0 +1,8 @@
|
||||
import * as Comlink from 'comlink';
|
||||
import type { RunDataWorker } from '@/workers/run-data/worker';
|
||||
|
||||
const worker = new Worker(new URL('./worker.ts', import.meta.url), {
|
||||
type: 'module',
|
||||
});
|
||||
|
||||
export const runDataWorker = Comlink.wrap<RunDataWorker>(worker);
|
||||
30
packages/frontend/editor-ui/src/workers/run-data/worker.ts
Normal file
30
packages/frontend/editor-ui/src/workers/run-data/worker.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import * as Comlink from 'comlink';
|
||||
import { databaseConfig } from '@/workers/run-data/db';
|
||||
import { initializeDatabase } from '@/workers/database';
|
||||
import type { Promiser, DbId } from '@sqlite.org/sqlite-wasm';
|
||||
|
||||
const state: {
|
||||
initialized: boolean;
|
||||
promiser: Promiser | undefined;
|
||||
dbId: DbId;
|
||||
} = {
|
||||
initialized: false,
|
||||
promiser: undefined,
|
||||
dbId: undefined,
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
async initialize() {
|
||||
if (state.initialized) return;
|
||||
|
||||
const { promiser, dbId } = await initializeDatabase(databaseConfig);
|
||||
|
||||
state.promiser = promiser;
|
||||
state.dbId = dbId;
|
||||
state.initialized = true;
|
||||
},
|
||||
};
|
||||
|
||||
export type RunDataWorker = typeof actions;
|
||||
|
||||
Comlink.expose(actions);
|
||||
96
packages/frontend/editor-ui/src/workers/sqlite-wasm.d.ts
vendored
Normal file
96
packages/frontend/editor-ui/src/workers/sqlite-wasm.d.ts
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
import type { Worker } from 'node:worker_threads';
|
||||
|
||||
declare module '@sqlite.org/sqlite-wasm' {
|
||||
type OnreadyFunction = () => void;
|
||||
|
||||
export type Sqlite3Worker1PromiserConfig = {
|
||||
onready?: OnreadyFunction;
|
||||
worker?: Worker | (() => Worker);
|
||||
generateMessageId?: (messageObject: unknown) => string;
|
||||
debug?: (...args: any[]) => void;
|
||||
onunhandled?: (event: MessageEvent) => void;
|
||||
};
|
||||
|
||||
export type DbId = string | undefined;
|
||||
|
||||
export type PromiserMethods = {
|
||||
'config-get': {
|
||||
args: Record<string, never>;
|
||||
result: {
|
||||
dbID: DbId;
|
||||
version: {
|
||||
libVersion: string;
|
||||
sourceId: string;
|
||||
libVersionNumber: number;
|
||||
downloadVersion: number;
|
||||
};
|
||||
bigIntEnabled: boolean;
|
||||
opfsEnabled: boolean;
|
||||
vfsList: string[];
|
||||
};
|
||||
};
|
||||
open: {
|
||||
args: Partial<{
|
||||
filename?: string;
|
||||
vfs?: string;
|
||||
}>;
|
||||
result: {
|
||||
dbId: DbId;
|
||||
filename: string;
|
||||
persistent: boolean;
|
||||
vfs: string;
|
||||
};
|
||||
};
|
||||
exec: {
|
||||
args: {
|
||||
sql: string;
|
||||
dbId?: DbId;
|
||||
bind?: unknown[];
|
||||
returnValue?: string;
|
||||
};
|
||||
result: {
|
||||
dbId: DbId;
|
||||
sql: string;
|
||||
bind: unknown[];
|
||||
returnValue: string;
|
||||
resultRows?: unknown[][];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type PromiserResponseSuccess<T extends keyof PromiserMethods> = {
|
||||
type: T;
|
||||
result: PromiserMethods[T]['result'];
|
||||
messageId: string;
|
||||
dbId: DbId;
|
||||
workerReceivedTime: number;
|
||||
workerRespondTime: number;
|
||||
departureTime: number;
|
||||
};
|
||||
|
||||
export type PromiserResponseError = {
|
||||
type: 'error';
|
||||
result: {
|
||||
operation: string;
|
||||
message: string;
|
||||
errorClass: string;
|
||||
input: object;
|
||||
stack: unknown[];
|
||||
};
|
||||
messageId: string;
|
||||
dbId: DbId;
|
||||
};
|
||||
|
||||
export type PromiserResponse<T extends keyof PromiserMethods> =
|
||||
| PromiserResponseSuccess<T>
|
||||
| PromiserResponseError;
|
||||
|
||||
export type Promiser = <T extends keyof PromiserMethods>(
|
||||
messageType: T,
|
||||
messageArguments: PromiserMethods[T]['args'],
|
||||
) => Promise<PromiserResponse<T>>;
|
||||
|
||||
export function sqlite3Worker1Promiser(
|
||||
config?: Sqlite3Worker1PromiserConfig | OnreadyFunction,
|
||||
): Promiser;
|
||||
}
|
||||
Reference in New Issue
Block a user