chore: package versions and dockerfile

Signed-off-by: mertmit <mertmit99@gmail.com>
This commit is contained in:
mertmit
2026-01-09 04:36:43 +03:00
parent 69a29568c7
commit c1739895df
17 changed files with 9538 additions and 1622 deletions

View File

@@ -48,6 +48,9 @@
"pnpm": {
"overrides": {
"**>ip": "npm:@eggjs/ip@latest",
"vue@*": "3.5.14",
"@vue/runtime-core@*": "3.5.14",
"@vue/runtime-dom@*": "3.5.14",
"@azure/msal-node": "^2.16.2",
"@babel/traverse@<7.23.2": ">=7.23.2",
"ajv@<6.12.3": ">=6.12.3",
@@ -65,11 +68,10 @@
"tar-fs@<2.1.2": ">=3.0.7",
"highlight.js@<9.18.5": ">=11.11.1",
"multer@1.4.4-lts.1": ">=2.0.1",
"vue-i8n@<9.14.3": ">=9.14.3",
"knex@<3.1.0": ">=3.1.0",
"cookie": ">=0.7.2",
"vue@<3": ">=3",
"@azure/identity@<4.2.1": ">=4.2.1",
"vue-i8n@<9.14.3": ">=9.14.3",
"cross-spawn@<7.0.5 >=7.0.0": ">=7.0.5",
"dset@<3.1.4": ">=3.1.4",
"http-proxy-middleware@<2.0.9": "2.0.9",
@@ -85,7 +87,8 @@
"@babel/helpers@<7.26.10": ">=7.26.10",
"vite@>=6.0.0 <=6.1.5": ">=6.1.6",
"vite@>=6.1.0 <6.1.4": ">=6.1.4",
"@types/mime": "npm:@types/mime@npm:nonexistent"
"@75lb/deep-merge@<=1.1.1": ">=1.1.2",
"@babel/runtime@<7.26.10": ">=7.26.10"
},
"onlyBuiltDependencies": [
"@nestjs/core",

View File

@@ -59,8 +59,6 @@ declare module 'vue' {
ASkeletonImage: typeof import('ant-design-vue/es')['SkeletonImage']
ASkeletonInput: typeof import('ant-design-vue/es')['SkeletonInput']
ASpin: typeof import('ant-design-vue/es')['Spin']
AStep: typeof import('ant-design-vue/es')['Step']
ASteps: typeof import('ant-design-vue/es')['Steps']
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
ASwitch: typeof import('ant-design-vue/es')['Switch']
ATabPane: typeof import('ant-design-vue/es')['TabPane']
@@ -111,7 +109,6 @@ declare module 'vue' {
MdiReload: typeof import('~icons/mdi/reload')['default']
MdiRocketLaunchOutline: typeof import('~icons/mdi/rocket-launch-outline')['default']
MdiScriptTextOutline: typeof import('~icons/mdi/script-text-outline')['default']
MdiShieldKeyOutline: typeof import('~icons/mdi/shield-key-outline')['default']
MdiStar: typeof import('~icons/mdi/star')['default']
MdiTableColumnPlusAfter: typeof import('~icons/mdi/table-column-plus-after')['default']
MdiThumbUp: typeof import('~icons/mdi/thumb-up')['default']

View File

@@ -37,27 +37,55 @@
"postinstall": "nuxt prepare"
},
"dependencies": {
"@aws-amplify/core": "^5.8.14",
"@aws-amplify/ui-vue": "^3.1.30",
"@ckpack/vue-color": "^1.6.0",
"@dagrejs/dagre": "^1.1.8",
"@floating-ui/vue": "^1.1.6",
"@iconify/vue": "^4.3.0",
"@pinia/nuxt": "^0.5.5",
"@productdevbook/chatwoot": "^2.0.0",
"@readme/httpsnippet": "^11.0.0",
"@sentry/vue": "^9.2.0",
"@stripe/stripe-js": "^5.10.0",
"@tiptap/extension-blockquote": "^2.11.5",
"@tiptap/extension-bold": "^2.11.5",
"@tiptap/extension-bubble-menu": "^2.11.5",
"@tiptap/extension-bullet-list": "^2.11.5",
"@tiptap/extension-code": "^2.11.5",
"@tiptap/extension-code-block": "^2.11.5",
"@tiptap/extension-color": "^2.11.5",
"@tiptap/extension-dropcursor": "^2.11.5",
"@tiptap/extension-hard-break": "^2.11.5",
"@tiptap/extension-heading": "^2.11.5",
"@tiptap/extension-horizontal-rule": "^2.11.5",
"@tiptap/extension-image": "^2.11.5",
"@tiptap/extension-italic": "^2.11.5",
"@tiptap/extension-link": "^2.11.5",
"@tiptap/extension-list-item": "^2.11.5",
"@tiptap/extension-mention": "^2.11.5",
"@tiptap/extension-ordered-list": "^2.11.5",
"@tiptap/extension-paragraph": "^2.11.5",
"@tiptap/extension-placeholder": "^2.11.5",
"@tiptap/extension-strike": "^2.11.5",
"@tiptap/extension-table": "^2.11.5",
"@tiptap/extension-table-cell": "^2.11.5",
"@tiptap/extension-table-header": "^2.11.5",
"@tiptap/extension-table-row": "^2.11.5",
"@tiptap/extension-task-list": "^2.11.5",
"@tiptap/extension-text": "^2.11.5",
"@tiptap/extension-text-style": "^2.11.5",
"@tiptap/extension-underline": "^2.11.5",
"@tiptap/html": "2.11.0",
"@tiptap/pm": "^2.11.5",
"@tiptap/starter-kit": "^2.11.5",
"@tiptap/suggestion": "^2.11.5",
"@tiptap/vue-3": "^2.11.5",
"@vue-flow/additional-components": "^1.3.3",
"@vue-flow/core": "^1.42.1",
"@vue-flow/background": "^1.3.2",
"@vue-flow/core": "^1.47.0",
"@vue-flow/minimap": "^1.5.4",
"@vue-flow/node-resizer": "^1.5.0",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"@vueuse/components": "^10.11.1",
@@ -66,23 +94,30 @@
"@vueuse/motion": "^2.2.6",
"@vvo/tzdb": "^6.183.0",
"ant-design-vue": "^3.2.20",
"chart.js": "^4.4.7",
"aws-amplify": "^5.3.27",
"company-email-validator": "^1.1.0",
"cron-parser": "^5.4.0",
"cronstrue": "^3.9.0",
"crossoriginworker": "^1.1.0",
"d3-scale": "^4.0.2",
"dagre": "^0.8.5",
"dayjs": "^1.11.13",
"dayjs": "^1.11.19",
"deep-object-diff": "^1.1.9",
"diff": "^7.0.0",
"echarts": "^5.6.0",
"embla-carousel-vue": "^8.5.2",
"emoji-mart-vue-fast": "^15.0.4",
"esbuild-wasm": "^0.25.5",
"fflate": "^0.8.2",
"file-saver": "^2.0.5",
"fuse.js": "^6.6.2",
"glob": "^10.4.5",
"grapheme-splitter": "^1.0.4",
"grid-layout-plus": "^1.1.0",
"html-entities": "^2.5.2",
"inflection": "^1.13.4",
"isomorphic-dompurify": "^2.25.0",
"jsbarcode": "^3.11.6",
"jsep": "^1.4.0",
"jwt-decode": "^3.1.2",
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
@@ -92,16 +127,22 @@
"markdown-it-regexp": "^0.4.0",
"markdown-it-task-lists": "^2.1.1",
"marked": "^4.3.0",
"mime-lite": "^1.0.3",
"monaco-editor": "^0.52.2",
"monaco-sql-languages": "^0.11.0",
"monacopilot": "^1.2.2",
"nc-analytics": "^0.0.6",
"nc-jsep": "^1.7.5",
"nocodb-sdk": "workspace:^",
"nocodb-sdk-v2": "workspace:^",
"papaparse": "^5.5.2",
"parse-github-url": "^1.0.3",
"pdfobject": "^2.3.0",
"pdfobject-vue": "^0.0.4",
"pinia": "^2.3.1",
"plyr": "^3.7.8",
"posthog-js": "^1.224.0",
"qrcode": "^1.5.4",
"readline": "^1.3.0",
"rehype-sanitize": "^6.0.0",
"rehype-stringify": "^10.0.1",
"remark-parse": "^11.0.0",
@@ -112,7 +153,6 @@
"splitpanes": "3.1.5",
"tinycolor2": "^1.6.0",
"tiptap-markdown": "^0.8.10",
"turndown": "^7.2.0",
"typesense": "^2.0.3",
"unified": "^11.0.5",
"unique-names-generator": "^4.7.1",
@@ -120,14 +160,13 @@
"validator": "^13.12.0",
"vue-advanced-cropper": "^2.8.9",
"vue-barcode-reader": "^1.0.3",
"vue-chartjs": "^5.3.2",
"vue-dompurify-html": "^5.3.0",
"vue-fullscreen": "^3.1.3",
"vue-github-button": "^3.1.3",
"vue-i18n": "^9.14.4",
"vue3-calendar-heatmap": "^2.0.5",
"vue3-contextmenu": "^0.2.12",
"vue-json-pretty": "^2.4.0",
"vue3-grid-layout-next": "^1.0.7",
"vue3-moveable": "^0.28.0",
"vue3-text-clamp": "^0.1.2",
"vuedraggable": "^4.1.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",

View File

@@ -1,6 +1,6 @@
import { acceptHMRUpdate } from 'pinia'
import type { IntegrationsType, SyncConfig } from 'nocodb-sdk'
import { ProjectSyncCreate, ProjectSyncProgressModal } from '#components'
// import { ProjectSyncCreate, ProjectSyncProgressModal } from '#components'
export interface SyncIntegrationConfig {
id?: string
@@ -13,270 +13,43 @@ export interface SyncIntegrationConfig {
}
export const useSyncStore = defineStore('sync', () => {
const { $api, $e } = useNuxtApp()
const bases = useBases()
const { isFeatureEnabled } = useBetaFeatureToggle()
const isSyncFeatureEnabled = computed(() => isEeUI)
const isSyncAdvancedFeaturesEnabled = computed(() => isFeatureEnabled(FEATURE_FLAG.SYNC_BETA_FEATURE))
const { activeWorkspaceId } = storeToRefs(useWorkspace())
const { activeProjectId } = storeToRefs(bases)
const { loadProjectTables } = useTablesStore()
const { showUpgradeToUseSync } = useEeConfig()
// State
const baseSyncs = ref<Map<string, SyncConfig[]>>(new Map())
const isLoadingSync = ref(false)
const isSyncFeatureEnabled = ref(false)
const isSyncAdvancedFeaturesEnabled = ref(false)
const activeBaseSyncs = computed(() => {
if (!activeProjectId.value) return []
return baseSyncs.value.get(activeProjectId.value) || []
})
// Getters
const activeBaseSyncs = computed(() => [])
// Actions
const loadSyncs = async (baseId: string, force = false) => {
if (!activeWorkspaceId.value) return []
const existingSyncs = baseSyncs.value.get(baseId)
if (existingSyncs && !force) {
return existingSyncs
}
try {
isLoadingSync.value = true
const syncList = await $api.internal.getOperation(activeWorkspaceId.value, baseId, {
operation: 'listSync',
})
if (syncList && Array.isArray(syncList)) {
baseSyncs.value.set(baseId, syncList)
}
return syncList
} catch (error) {
console.error('Error loading syncs:', error)
message.error(await extractSdkResponseErrorMsgv2(error as any))
} finally {
isLoadingSync.value = false
}
const loadSyncs = async (_baseId: string, _force = false) => {
return []
}
const readSync = async (syncConfigId: string) => {
if (!activeProjectId.value || !activeWorkspaceId.value || !syncConfigId) {
return null
}
let syncConfig: null | SyncConfig = null
if (baseSyncs.value.get(activeProjectId.value)?.find((sync) => sync.id === syncConfigId)) {
syncConfig = baseSyncs.value.get(activeProjectId.value)?.find((sync) => sync.id === syncConfigId) || null
}
try {
syncConfig =
syncConfig ||
(await $api.internal.getOperation(activeWorkspaceId.value, activeProjectId.value, {
operation: 'readSync',
id: syncConfigId,
}))
return syncConfig as SyncConfig
} catch (error) {
console.error('Error reading sync:', error)
message.error(await extractSdkResponseErrorMsgv2(error as any))
return null
} finally {
isLoadingSync.value = false
}
const readSync = async (_syncConfigId: string) => {
return null
}
const createSync = async (
baseId: string,
data: Partial<SyncConfig> & {
configs: Array<Partial<IntegrationConfig>>
},
) => {
if (!activeWorkspaceId.value || !baseId) return null
try {
const created = await $api.internal.postOperation(
activeWorkspaceId.value,
baseId,
{
operation: 'createSync',
},
data,
)
const curentBaseSyncs = baseSyncs.value.get(baseId) || []
curentBaseSyncs.push(created?.syncConfig)
baseSyncs.value.set(baseId, curentBaseSyncs)
await loadProjectTables(baseId, true)
$e('a:sync:create', {
sync_type: data.sync_type,
sync_category: data.sync_category,
sources: data.configs?.length || 0,
})
return created as { job: { id: string } }
} catch (error) {
console.error('Error creating sync:', error)
message.error(await extractSdkResponseErrorMsgv2(error as any))
throw error
}
const createSync = async (_baseId: string, _data: any) => {
return null
}
const updateSync = async (
id: string,
data: Partial<SyncConfig> & {
config?: SyncIntegrationConfig[]
},
) => {
if (!activeWorkspaceId.value || !activeProjectId.value) return null
try {
const result = await $api.internal.postOperation(
activeWorkspaceId.value,
activeProjectId.value,
{
operation: 'updateSync',
},
data,
)
if (result.syncConfig && result.syncConfig.id) {
const curentBaseSyncs = baseSyncs.value.get(activeProjectId.value) || []
const index = curentBaseSyncs.findIndex((sync) => sync.id === id)
if (index !== -1) {
curentBaseSyncs[index] = result.syncConfig
baseSyncs.value.set(activeProjectId.value, curentBaseSyncs)
}
}
$e('a:sync:update', {
sync_type: result.syncConfig?.sync_type,
sync_category: result.syncConfig?.sync_category,
})
return result
} catch (error) {
console.error('Error updating sync:', error)
message.error(await extractSdkResponseErrorMsgv2(error as any))
return null
}
const updateSync = async (_id: string, _data: any) => {
return null
}
const deleteSync = async (baseId: string, syncConfigId: string) => {
if (!activeWorkspaceId.value || !baseId) return null
try {
await $api.internal.postOperation(
activeWorkspaceId.value,
baseId,
{
operation: 'deleteSync',
},
{
id: syncConfigId,
},
)
const curentBaseSyncs = baseSyncs.value.get(baseId) || []
const index = curentBaseSyncs.findIndex((sync) => sync.id === syncConfigId)
if (index !== -1) {
curentBaseSyncs.splice(index, 1)
baseSyncs.value.set(baseId, curentBaseSyncs)
}
$e('a:sync:delete')
return true
} catch (error) {
console.error('Error deleting sync:', error)
message.error(await extractSdkResponseErrorMsgv2(error as any))
return false
}
const deleteSync = async (_baseId: string, _syncConfigId: string) => {
return null
}
const triggerSync = async (baseId: string, syncConfigId: string, bulk = false) => {
if (!activeWorkspaceId.value || !baseId) return null
try {
const syncData = await $api.internal.postOperation(
activeWorkspaceId.value,
baseId,
{
operation: 'triggerSync',
},
{
id: syncConfigId,
bulk,
},
)
$e('a:sync:trigger')
return syncData as { id: string }
} catch (error) {
console.error('Error triggering sync:', error)
message.error(await extractSdkResponseErrorMsgv2(error as any))
}
const triggerSync = async (_baseId: string, _syncConfigId: string, _bulk = false) => {
return null
}
async function openNewSyncCreateModal({ baseId }: { baseId?: string }) {
if (!baseId || showUpgradeToUseSync()) return
async function openNewSyncCreateModal(..._args: any[]) {}
$e('c:sync:open-create-modal')
const isDlgOpen = ref(true)
const { close } = useDialog(ProjectSyncCreate, {
'value': isDlgOpen,
'baseId': baseId,
'onUpdate:value': () => closeDialog(),
'onSyncCreated': async (jobId: string) => {
closeDialog(jobId)
},
})
async function closeDialog(jobId?: string) {
isDlgOpen.value = false
close(1000)
if (baseId && jobId) {
openSyncProgressModal({ baseId, jobId })
}
}
}
async function openSyncProgressModal({ baseId, jobId }: { baseId: string; jobId: string }) {
if (!baseId || !jobId) return
const isDlgOpen = ref(true)
const { close } = useDialog(ProjectSyncProgressModal, {
'modelValue': isDlgOpen,
'onUpdate:modelValue': () => closeDialog(),
'jobId': jobId,
'baseId': baseId,
})
function closeDialog() {
isDlgOpen.value = false
close(1000)
}
}
async function openSyncProgressModal(..._args: any[]) {}
return {
// State

View File

@@ -11,15 +11,16 @@
"test:coverage": "vitest run --coverage"
},
"dependencies": {
"ai": "^4.3.15",
"@ai-sdk/provider": "^3.0.0",
"ai": "^6.0.3",
"nocodb-sdk": "file:../../nocodb-sdk",
"zod": "^3.24.4"
"zod": "^3.25.76"
},
"devDependencies": {
"@types/node": "^20.17.46",
"@vitest/coverage-v8": "^3.1.3",
"@vitest/coverage-v8": "^3.1.4",
"rimraf": "^5.0.10",
"typescript": "^5.8.3",
"vitest": "^3.1.3"
"vitest": "^3.1.4"
}
}
}

View File

@@ -7,7 +7,6 @@ export * from './sync';
export * from './auth';
export * from './ai';
export * from './sdk';
export * from './workflow-node';
export { SCHEMA_TICKETING } from './sync/schema-ticketing';
export { SCHEMA_HRIS } from './sync/schema-hris';
export { SCHEMA_CRM } from './sync/schema-crm';

View File

@@ -1 +0,0 @@
export * from './types';

View File

@@ -1,287 +0,0 @@
import type { NocoSDK } from '../sdk';
export interface RecordField {
[key: string]: any;
}
export interface DataRecord {
id?: string | number;
fields: RecordField;
}
export interface DataRecordId {
id: string | number;
}
export interface DataRecordWithDeleted extends DataRecordId {
deleted: boolean;
}
export interface DataListResponse {
records?: DataRecord[];
record?: DataRecord | null;
next?: string;
prev?: string;
nestedNext?: string;
nestedPrev?: string;
}
export interface DataInsertRequest {
fields: RecordField;
}
export interface DataUpdateRequest {
id: string | number;
fields: RecordField;
}
export interface DataDeleteRequest {
id: string | number;
}
export interface DataListParams {
baseId?: string;
modelId: string;
query: any;
viewId?: string;
ignorePagination?: boolean;
req: NocoSDK.NcRequest;
}
export interface DataInsertParams {
baseId?: string;
viewId?: string;
modelId: string;
body: DataInsertRequest | DataInsertRequest[];
cookie: any;
}
export interface DataUpdateParams {
baseId?: string;
modelId: string;
viewId?: string;
body: DataUpdateRequest | DataUpdateRequest[];
cookie: any;
}
export interface DataDeleteParams {
baseId?: string;
modelId: string;
viewId?: string;
cookie: any;
body?: DataDeleteRequest | DataDeleteRequest[];
queryRecords?: string | string[];
}
export interface NestedDataListParams {
modelId: string;
rowId: string;
query: any;
viewId: string;
columnId: string;
req: NocoSDK.NcRequest;
}
export interface DataReadParams {
modelId: string;
rowId: string;
query: any;
viewId?: string;
req: NocoSDK.NcRequest;
}
export interface TransformRecordToV3Param {
context: NocoSDK.NcContext;
record: any;
primaryKey: NocoSDK.ColumnType;
primaryKeys?: NocoSDK.ColumnType[];
requestedFields?: string[];
columns?: NocoSDK.ColumnType[];
nestedLimit?: number;
skipSubstitutingColumnIds?: boolean;
depth?: number;
}
export interface TransformRecordsToV3FormatParam {
context: NocoSDK.NcContext;
records: any[];
primaryKey: NocoSDK.ColumnType;
primaryKeys?: NocoSDK.ColumnType[];
requestedFields?: string[];
columns?: NocoSDK.ColumnType[];
nestedLimit?: number;
skipSubstitutingColumnIds?: boolean;
depth?: number;
}
export type NestedLinkParams = {
modelId: string;
columnId: string;
rowId: string;
refRowIds:
| string
| string[]
| number
| number[]
| Record<string, any>
| Record<string, any>[];
query?: any;
cookie?: any;
viewId?: string;
};
export interface IDataV3Service {
transformRecordsToV3Format(
param: TransformRecordsToV3FormatParam,
): Promise<DataRecord[]>;
dataList<T extends boolean>(
context: NocoSDK.NcContext,
param: DataListParams,
pagination?: T,
): Promise<T extends true ? DataListResponse : DataRecord[]>;
dataInsert(
context: NocoSDK.NcContext,
param: DataInsertParams,
): Promise<{ records: DataRecord[] }>;
dataDelete(
context: NocoSDK.NcContext,
param: DataDeleteParams,
): Promise<{ records: DataRecordWithDeleted[] }>;
dataUpdate(
context: NocoSDK.NcContext,
param: DataUpdateParams,
): Promise<{ records: DataRecord[] }>;
nestedDataList(
context: NocoSDK.NcContext,
param: NestedDataListParams,
): Promise<DataListResponse>;
dataRead(
context: NocoSDK.NcContext,
param: DataReadParams,
): Promise<DataRecord>;
nestedLink(
context: NocoSDK.NcContext,
param: NestedLinkParams,
): Promise<{ success: boolean }>;
nestedUnlink(
context: NocoSDK.NcContext,
param: NestedLinkParams,
): Promise<{ success: boolean }>;
}
export interface ITablesService {
list(
context: NocoSDK.NcContext,
param: { base_id: string },
): Promise<Array<{ id: string; title: string; table_name: string }>>;
tableUpdate(
context: NocoSDK.NcContext,
param: {
tableId: any;
table: Partial<NocoSDK.TableReqType> & { base_id?: string };
baseId?: string;
user: NocoSDK.UserType;
req: NocoSDK.NcRequest;
},
): Promise<boolean>;
reorderTable(
context: NocoSDK.NcContext,
param: { tableId: string; order: any; req: NocoSDK.NcRequest },
): Promise<any>;
tableDelete(
context: NocoSDK.NcContext,
param: {
tableId: string;
user: NocoSDK.UserType;
forceDeleteRelations?: boolean;
forceDeleteSyncs?: boolean;
req?: any;
},
): Promise<any>;
getTableWithAccessibleViews(
context: NocoSDK.NcContext,
param: {
tableId: string;
user: NocoSDK.UserType;
},
): Promise<NocoSDK.TableType & {
views: Array<NocoSDK.ViewType>
columns: Array<NocoSDK.ColumnType>
}>;
getAccessibleTables(
context: NocoSDK.NcContext,
param: {
baseId: string;
sourceId?: string;
includeM2M?: boolean;
roles: Record<string, boolean>;
user: NocoSDK.UserType;
},
): Promise<NocoSDK.TableType[]>;
tableCreate(
context: NocoSDK.NcContext,
param: {
baseId: string;
sourceId?: string;
table: NocoSDK.TableReqType;
user: NocoSDK.UserType;
req: NocoSDK.NcRequest;
synced?: boolean;
apiVersion?: NocoSDK.NcApiVersion;
},
): Promise<NocoSDK.TableType>;
}
interface XcEmailAttachment {
/** Name that will be displayed to the recipient. Unicode is allowed. */
filename?: string;
/** Contents of the file */
content?: string | Buffer;
/** Filesystem path or URL (including data URIs). Recommended for large files. */
path?: string;
/** HTTP(S) URL that Nodemailer should fetch and attach */
href?: string;
/** Custom HTTP headers for href, for example { authorization: 'Bearer …' } */
httpHeaders?: object;
/** Explicit MIME type. Defaults to the type inferred from filename */
contentType?: string;
/** ContentDisposition header. Defaults to 'attachment' */
contentDisposition?: string;
/** ContentID for embedding the attachment inline in the HTML body */
cid?: string;
/** Encoding applied when content is a string (e.g. 'base64', 'hex') */
encoding?: string;
/** Custom headers for the individual MIME node */
headers?: object;
/** Advanced: Full prebuilt MIME node including headers. Overrides every other field. */
raw?: string;
}
interface RawMailParams {
to: string;
subject: string;
html: string;
text?: string;
attachments?: XcEmailAttachment[];
cc?: string | string[];
bcc?: string | string[];
}
export interface IMailService {
sendMailRaw(param: RawMailParams): Promise<boolean>;
}

View File

@@ -1,264 +0,0 @@
import { IntegrationWrapper } from '../integration';
import { AuthIntegration } from '../auth';
import { NocoSDK } from '../sdk';
import { IDataV3Service, ITablesService, IMailService } from './nocodb.interface';
import { WorkflowNodeDefinition, WorkflowNodeCategory, WorkflowNodeCategoryType, VariableDefinition, TriggerActivationType, LoopContext } from 'nocodb-sdk'
export interface WorkflowNodeLog {
level: 'info' | 'warn' | 'error';
message: string;
ts?: number;
data?: any;
}
export interface WorkflowNodeRunContext<TConfig = any> {
workspaceId: string;
baseId: string;
testMode?: boolean;
user?: {
id: string;
email?: string;
display_name?: string;
};
inputs: {
config: TConfig;
title?: string;
};
/**
* Load an integration by ID (AI, Auth, or any other integration type).
* Returns an Integration wrapper containing the integration.
*
* @param integrationId - The ID of the integration to load
* @returns Promise resolving to Integration wrapper
*
* @example
* ```typescript
* // Loading an Auth integration
* const auth = await ctx.getIntegration(config.authIntegrationId);
* const data = await auth.use(async (client) => {
* return client.api.getData();
* });
*
* // Loading an AI integration with type
* const ai = await ctx.getIntegration<AiIntegration>(config.aiIntegrationId);
* const result = await integration.generateText({ prompt: 'Hello' });
* ```
*/
getIntegration?: <T = any>(
integrationId: string
) => Promise<T>;
}
/**
* Context provided when activating external webhook triggers
*/
export interface WorkflowActivationContext {
/** The webhook URL that external services should call */
webhookUrl: string;
/** Workflow ID */
workflowId: string;
/** Trigger node ID in the workflow */
nodeId: string;
}
/**
* State returned from onActivateHook that will be passed to onDeactivateHook
* Store any data needed for cleanup (e.g., external webhook IDs, secrets)
*/
export type WorkflowActivationState = Record<string, any>;
export interface WorkflowNodeResult {
outputs: Record<string, unknown>;
metrics?: Record<string, number>;
logs?: WorkflowNodeLog[];
status?: 'success' | 'pending' | 'skipped' | 'error' | 'running';
error?: { message: string; code?: string; data?: any };
loopContext?: LoopContext;
}
export interface WorkflowNodeValidationResult {
valid: boolean;
errors?: { path?: string; message: string }[];
warnings?: { path?: string; message: string }[];
}
export interface NocoDBContext {
context: NocoSDK.NcContext;
dataService: IDataV3Service;
tablesService: ITablesService;
user: NocoSDK.UserType;
mailService: IMailService;
getBaseSchema: () => Promise<any>;
getAccessToken: () => string;
}
export interface WorkflowNodeConfig {
_nocodb: NocoDBContext;
}
export {
WorkflowNodeCategory,
WorkflowNodeCategoryType,
WorkflowNodeDefinition,
TriggerActivationType,
}
export abstract class WorkflowNodeIntegration<TConfig extends WorkflowNodeConfig = WorkflowNodeConfig> extends IntegrationWrapper<TConfig> {
protected get nocodb(): NocoDBContext {
return this.config._nocodb;
}
/**
* Stored integration loader function from execution context.
* Set by the workflow executor before node execution.
* @internal
*/
protected _integrationLoader?: <T = any>(
integrationId: string
) => Promise<T>;
/**
* Set the integration loader function for this node instance.
* Called by the workflow executor before node execution.
* @internal
*/
public setIntegrationLoader(
loader: <T = any>(integrationId: string) => Promise<T>
) {
this._integrationLoader = loader;
}
/**
* Load an integration by ID (AI, Auth, or any other integration type).
* Use this in run(), fetchOptions(), or other methods that need to access integrations.
*
* @param integrationId - The ID of the integration to load
* @returns Promise resolving to AuthIntegration wrapper containing the integration
* @throws Error if integration loader is not available
*
* @example
* ```typescript
* // Loading an Auth integration
* async run(ctx: WorkflowNodeRunContext) {
* const auth = await this.getIntegration(this.config.authIntegrationId);
* const data = await auth.use(async (client) => {
* return client.api.getData();
* });
* }
*
* // Loading an AI integration with type
* async run(ctx: WorkflowNodeRunContext) {
* const ai = await this.getIntegration<AiIntegration>(this.config.aiIntegrationId);
* const result = await ai.generateText({ prompt: 'Hello' });
* }
* ```
*/
protected async getIntegration<T = any>(
integrationId: string
): Promise<T> {
if (!this._integrationLoader) {
throw new Error('Integration loader not available. This node must be executed within a workflow context.');
}
return this._integrationLoader<T>(integrationId);
}
public abstract definition(): Promise<WorkflowNodeDefinition>;
public async validate(_config: TConfig): Promise<WorkflowNodeValidationResult> {
return { valid: true };
}
public abstract run(ctx: WorkflowNodeRunContext): Promise<WorkflowNodeResult>;
public async fetchOptions(
_key: string,
): Promise<unknown> {
return []
}
/**
* Generate input variables from node configuration
* Called when config changes (e.g., table selected)
* Optional - implement if node has configurable inputs
*
* @param context - Variable generator context with database access and node graph
* @param runtimeInputs - Optional runtime data with interpolated config and actual outputs
*/
public async generateInputVariables?(
context: NocoSDK.VariableGeneratorContext,
runtimeInputs?: any,
): Promise<VariableDefinition[]>;
/**
* Generate output variables from node definition
* Called after node definition or test execution
* Optional - implement if node produces structured output
*
* @param context - Variable generator context with database access and node graph
* @param runtimeInputs - Optional runtime data with interpolated config and actual outputs
*/
public async generateOutputVariables?(
context: NocoSDK.VariableGeneratorContext,
runtimeInputs?: any,
): Promise<VariableDefinition[]>;
/**
* Called when workflow is published/enabled
* Use for: registering webhooks, establishing connections, subscribing to events
*
* @param context - Activation context with webhook URL and workflow info
* @returns State object that will be passed to onDeactivateHook for cleanup
*
* @example GitHub webhook
* ```typescript
* async onActivateHook(context: WorkflowActivationContext) {
* const auth = await this.getIntegration<AuthIntegration>(this.config.authIntegrationId);
* const webhook = await auth.use(async (client) => {
* return client.repos.createWebhook({
* owner: this.config.owner,
* repo: this.config.repo,
* config: { url: context.webhookUrl, content_type: 'json' },
* events: this.config.events,
* });
* });
* return { webhookId: webhook.data.id, createdAt: Date.now() };
* }
* ```
*/
public async onActivateHook?(
context: WorkflowActivationContext
): Promise<WorkflowActivationState | void>;
/**
* Called when workflow is unpublished/disabled
* Use for: cleanup, unregistering webhooks, closing connections
*
* @param context - Same context from activation
* @param state - The state object returned from onActivateHook()
*
* @example GitHub webhook cleanup
* ```typescript
* async onDeactivateHook(context: WorkflowActivationContext, state?: WorkflowActivationState) {
* if (!state?.webhookId) return;
* const auth = await this.getIntegration<AuthIntegration>(this.config.authIntegrationId);
* await auth.use(async (client) => {
* await client.repos.deleteWebhook({
* owner: this.config.owner,
* repo: this.config.repo,
* hook_id: state.webhookId,
* });
* });
* }
* ```
*/
public async onDeactivateHook?(
context: WorkflowActivationContext,
state?: WorkflowActivationState
): Promise<void>;
}

File diff suppressed because it is too large Load Diff

View File

@@ -39,10 +39,19 @@
"preinstall": "npx only-allow pnpm"
},
"dependencies": {
"@vue-flow/core": "^1.47.0",
"acorn-loose": "^8.4.0",
"acorn-walk": "^8.3.4",
"axios": "^1.9.0",
"chevrotain": "^10.5.0",
"dayjs": "^1.11.13",
"jsep": "^1.4.0",
"dayjs": "^1.11.19",
"fast-deep-equal": "^3.1.3",
"nc-jsep": "^1.7.5",
"nc-jsep-plugin-arrow": "^1.7.5",
"nc-jsep-plugin-object": "^1.7.5",
"nc-jsep-plugin-template": "^1.7.5",
"nc-jsep-plugin-ternary": "^1.7.5",
"rfdc": "^1.4.1",
"validator": "^13.12.0"
},
"devDependencies": {
@@ -78,4 +87,4 @@
"prettier": {
"singleQuote": true
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,20 +3,25 @@
################
# NocoDB Builder
################
FROM node:22-alpine AS builder
FROM node:22-slim AS builder
WORKDIR /usr/src/app
# Install node-gyp dependencies and other build tools
RUN apk add --no-cache \
g++ \
make \
py3-setuptools \
python3
# Install dependencies required for node-gyp and other build tools
RUN apt-get update && apt-get install -y \
python3 \
python3-distutils \
python-is-python3 \
make \
g++ \
libssl-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
RUN python3 --version && python --version
# Install pnpm
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
# Copy application dependency manifests to the container image
# Copy application dependency manifests to the container image.
COPY --link ./package.json ./package.json
COPY --link ./docker/main.js ./docker/index.js
COPY --link ./docker/start-local.sh /usr/src/appEntry/start.sh
@@ -29,15 +34,15 @@ RUN echo "node-linker=hoisted" > .npmrc
# Install production dependencies, reduce node_modules size with modclean,
# remove sqlite deps, and add execute permission to start.sh
RUN pnpm uninstall nocodb-sdk
RUN pnpm install --prod --shamefully-hoist --reporter=silent \
&& pnpm dlx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**,@azure/msal-node/dist/**,@react-email/**,jsdom/**" --run \
RUN pnpm install --prod --shamefully-hoist \
&& pnpm dlx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**,@azure/msal-node/dist/**,@react-email/**,@linear/**,jsdom/**" --run \
&& rm -rf ./node_modules/sqlite3/deps \
&& chmod +x /usr/src/appEntry/start.sh
########
# Runner
########
FROM alpine:3.20
FROM node:22-slim
WORKDIR /usr/src/app
ENV NC_DOCKER=0.6 \
@@ -45,11 +50,14 @@ ENV NC_DOCKER=0.6 \
NODE_ENV=production \
PORT=8080
RUN apk add --update --no-cache \
curl \
# Install additional runtime dependencies
RUN apt-get update && apt-get install -y \
dumb-init \
jq \
nodejs
curl \
wget \
&& curl -L "https://github.com/TomWright/dasel/releases/download/v2.8.1/dasel_linux_$(dpkg --print-architecture)" -o /usr/local/bin/dasel \
&& chmod +x /usr/local/bin/dasel \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Copy production code & main entry file
COPY --link --from=builder /usr/src/app/ /usr/src/app/

View File

@@ -48,12 +48,31 @@
"mail": "email dev --dir src/services/mail/templates --port 8001"
},
"dependencies": {
"@ai-sdk/amazon-bedrock": "^4.0.3",
"@ai-sdk/anthropic": "^3.0.1",
"@ai-sdk/azure": "^3.0.1",
"@ai-sdk/deepseek": "^2.0.1",
"@ai-sdk/google": "^3.0.1",
"@ai-sdk/groq": "^3.0.1",
"@ai-sdk/openai": "^3.0.1",
"@ai-sdk/openai-compatible": "^0.2.14",
"@ai-sdk/provider": "^3.0.0",
"@aws-sdk/client-cognito-identity-provider": "^3.816.0",
"@aws-sdk/client-kinesis": "^3.817.0",
"@aws-sdk/client-s3": "^3.743.0",
"@aws-sdk/client-ses": "^3.743.0",
"@aws-sdk/client-sns": "^3.743.0",
"@aws-sdk/lib-storage": "^3.743.0",
"@aws-sdk/s3-request-presigner": "^3.743.0",
"@clickhouse/client": "^1.11.1",
"@databricks/sql": "^1.11.0",
"@e2b/code-interpreter": "^1.5.1",
"@gitbeaker/rest": "^43.8.0",
"@google-cloud/storage": "^7.15.0",
"@modelcontextprotocol/sdk": "^1.13.3",
"@govtechsg/passport-openidconnect": "^1.0.3",
"@linear/sdk": "^40.0.0",
"@microsoft/microsoft-graph-client": "^3.0.7",
"@modelcontextprotocol/sdk": "^1.18.2",
"@napi-rs/canvas": "^0.1.77",
"@nest-lab/throttler-storage-redis": "^1.1.0",
"@nestjs/bull": "^10.2.3",
@@ -64,17 +83,25 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.4.19",
"@nestjs/platform-socket.io": "^10.4.19",
"@nestjs/schedule": "^6.0.0",
"@nestjs/throttler": "^6.4.0",
"@nestjs/websockets": "^10.4.19",
"@node-saml/passport-saml": "^5.0.1",
"@octokit/plugin-throttling": "^11.0.3",
"@octokit/rest": "^20.0.0",
"@react-email/components": "0.0.41",
"@react-email/render": "^1.1.2",
"@sentry/nestjs": "^9.27.0",
"@slack/web-api": "^7.11.0",
"@socket.io/redis-adapter": "^8.3.0",
"@types/chai": "^4.3.20",
"ai": "^6.0.3",
"airtable": "^0.12.2",
"ajv": "^8.17.1",
"ajv-formats": "^2.1.1",
"auto-bind": "^4.0.0",
"aws-jwt-verify": "^4.0.1",
"aws-kcl": "^2.2.7",
"axios": "^1.9.0",
"bcryptjs": "^2.4.3",
"bignumber.js": "^9.1.2",
@@ -83,13 +110,14 @@
"clear": "^0.1.0",
"colors": "^1.4.0",
"compare-versions": "^6.1.1",
"consola": "^3.4.0",
"content-disposition": "^0.5.4",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"cron-parser": "^5.2.0",
"cron-parser": "^5.4.0",
"crypto-js": "^4.2.0",
"dataloader": "^2.2.3",
"dayjs": "^1.11.13",
"dayjs": "^1.11.19",
"debug": "^4.4.0",
"deep-object-diff": "^1.1.9",
"dotenv": "^8.6.0",
@@ -99,10 +127,13 @@
"fast-deep-equal": "^3.1.3",
"fast-levenshtein": "^2.0.6",
"fs-extra": "^9.1.0",
"get-port": "5.1.1",
"glob": "^10.4.5",
"googleapis": "^169.0.0",
"handlebars": "^4.7.8",
"handlebars-helpers-v2": "^2.2.0",
"html-to-json-parser": "^2.0.1",
"i": "^0.3.7",
"iconv-lite": "^0.6.3",
"import-fresh": "^3.3.1",
"inflection": "^1.13.4",
@@ -110,11 +141,13 @@
"ioredis-mock": "8.9.0",
"is-docker": "^2.2.1",
"isomorphic-dompurify": "^2.25.0",
"jsep": "^1.4.0",
"jira-client": "^8.2.2",
"json5": "^2.2.3",
"jsonfile": "^6.1.0",
"jsonwebtoken": "^9.0.2",
"knex": "3.1.0",
"knex-databricks": "link:../nc-knex-dialects/knex-databricks",
"knex-snowflake": "link:../nc-knex-dialects/knex-snowflake",
"list-github-dir-content": "^3.0.0",
"lodash": "^4.17.21",
"mailersend": "^1.5.0",
@@ -122,14 +155,22 @@
"mime": "3.0.0",
"minio": "^8.0.4",
"mkdirp": "^2.1.6",
"monacopilot": "^1.2.2",
"multer": "^2.0.1",
"mysql2": "^3.14.1",
"nanoid": "^3.3.8",
"nc-jsep": "^1.7.5",
"nc-lib-gui": "0.265.1",
"nestjs-pino": "^3.5.0",
"net": "^1.0.2",
"nocodb-sdk": "workspace:^",
"node-sql-parser": "^5.3.6",
"nodemailer": "^6.10.0",
"npm": "^11.3.0",
"object-hash": "^3.0.0",
"object-sizeof": "^2.6.5",
"octokit": "3.2.2",
"openai": "^5.8.2",
"os-locale": "^6.0.2",
"p-queue": "^6.6.2",
"papaparse": "^5.5.2",
@@ -140,38 +181,46 @@
"passport-http": "^0.3.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"passport-saml-metadata": "^5.0.0",
"pdf-parse": "^1.1.1",
"pdfjs-dist": "^5.4.54",
"pg": "^8.13.1",
"pg-protocol": "^1.7.0",
"pino-http": "^8.6.1",
"posthog-node": "^3.6.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"redlock": "^5.0.0-beta.2",
"reflect-metadata": "^0.2.2",
"request-filtering-agent": "^1.1.2",
"request-ip": "^3.3.0",
"resumable-stream": "^2.2.1",
"rfdc": "^1.4.1",
"rxjs": "^7.8.1",
"sharp": "0.33.4",
"slash": "^3.0.0",
"slug": "^8.2.3",
"snowflake-sdk": "^2.1.0",
"socket.io": "^4.8.1",
"sqlite3": "^5.1.7",
"stream-json": "^1.9.1",
"stripe": "^18.2.1",
"tinycolor2": "^1.6.0",
"twilio": "^4.23.0",
"unpdf": "^1.2.1",
"unstructured-client": "^0.16.0",
"uuid": "^11.1.0",
"validator": "^13.12.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
"zod": "^3.25.7"
"zod": "^3.25.76"
},
"devDependencies": {
"@nestjs/cli": "^11.0.7",
"@nestjs/schematics": "^10.2.3",
"@nestjs/testing": "^10.4.15",
"@nestjsplus/dyn-schematics": "^1.0.12",
"@rspack/cli": "^1.4.6",
"@rspack/core": "^1.4.6",
"@rspack/cli": "^1.6.7",
"@rspack/core": "^1.6.7",
"@swc-node/register": "^1.10.10",
"@types/content-disposition": "^0.5.8",
"@types/ejs": "^3.1.5",
@@ -179,7 +228,7 @@
"@types/jest": "^29.5.14",
"@types/mocha": "^10.0.10",
"@types/multer": "^1.4.12",
"@types/node": "^22.13.1",
"@types/node": "^22.15.21",
"@types/passport-google-oauth20": "^2.0.16",
"@types/passport-jwt": "^4.0.1",
"@types/react": "^19.0.10",
@@ -205,8 +254,8 @@
"run-script-webpack-plugin": "0.2.2",
"semver": "^7.5.4",
"supertest": "^7.1.1",
"ts-checker-rspack-plugin": "^1.1.4",
"ts-jest": "29.1.2",
"ts-checker-rspack-plugin": "^1.2.1",
"ts-jest": "29.2.5",
"typescript": "^5.7.3"
}
}
}

View File

@@ -8,7 +8,7 @@ import dotenv from 'dotenv';
import requestIp from 'request-ip';
import cookieParser from 'cookie-parser';
import { NcDebug } from 'nc-gui/utils/debug';
import { definePDFJSModule } from 'unpdf';
// import { definePDFJSModule } from 'unpdf';
import type { INestApplication } from '@nestjs/common';
import type { MetaService } from '~/meta/meta.service';
import type { IEventEmitter } from '~/modules/event-emitter/event-emitter.interface';
@@ -162,9 +162,10 @@ export default class Noco {
}
try {
this.canvas = await import('@napi-rs/canvas');
await definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'));
this.isPdfjsInitialized = true;
// TODO: enable later cc @DarkPhoenix2704
// this.canvas = await import('@napi-rs/canvas');
// await definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'));
// this.isPdfjsInitialized = true;
} catch (e) {
console.error(e);
console.error(

View File

@@ -3,6 +3,10 @@
!!! Do not edit this file manually !!!
*/
import type { IntegrationEntry } from '@noco-local-integrations/core';
export default [] as IntegrationEntry[];
export default [
] as IntegrationEntry[];

8584
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff