封装创建 table 的模块

This commit is contained in:
2025-11-21 16:41:57 +08:00
parent f5c59e584a
commit de1b221bc5
13 changed files with 1073 additions and 41 deletions

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
NOCODB_URL=http://localhost:8080
NOCODB_API_KEY=xxxxyyyyzzzz

View File

@@ -1,6 +1,6 @@
{
"name": "@kevisual/noco",
"version": "0.0.2",
"version": "0.0.3",
"description": "",
"main": "index.js",
"scripts": {
@@ -24,8 +24,10 @@
"packageManager": "pnpm@10.23.0",
"type": "module",
"devDependencies": {
"@kevisual/dts": "^0.0.3",
"@kevisual/types": "^0.0.10",
"@kevisual/use-config": "^1.0.19",
"@types/bun": "^1.3.2",
"@types/node": "^24.10.1",
"nocodb-sdk": "^0.265.1"
},

504
pnpm-lock.yaml generated
View File

@@ -8,12 +8,18 @@ importers:
.:
devDependencies:
'@kevisual/dts':
specifier: ^0.0.3
version: 0.0.3(typescript@5.9.3)
'@kevisual/types':
specifier: ^0.0.10
version: 0.0.10
'@kevisual/use-config':
specifier: ^1.0.19
version: 1.0.19(dotenv@16.6.1)
'@types/bun':
specifier: ^1.3.2
version: 1.3.2(@types/react@19.2.6)
'@types/node':
specifier: ^24.10.1
version: 24.10.1
@@ -23,6 +29,14 @@ importers:
packages:
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.28.5':
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
'@chevrotain/cst-dts-gen@10.5.0':
resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==}
@@ -35,6 +49,13 @@ packages:
'@chevrotain/utils@10.5.0':
resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==}
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
'@kevisual/dts@0.0.3':
resolution: {integrity: sha512-4T/m2LqhtwWEW+lWmg7jLxKFW7VtIAftsWFDDZvh10bZunqFf8iXxChHcVSQWikghJb4cq1IkWzPkvc2l+Asdw==}
hasBin: true
'@kevisual/load@0.0.6':
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
@@ -46,15 +67,182 @@ packages:
peerDependencies:
dotenv: ^16.4.7
'@rollup/plugin-commonjs@28.0.9':
resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==}
engines: {node: '>=16.0.0 || 14 >= 14.17'}
peerDependencies:
rollup: ^2.68.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
'@rollup/plugin-node-resolve@16.0.3':
resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^2.78.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
'@rollup/plugin-typescript@12.3.0':
resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^2.14.0||^3.0.0||^4.0.0
tslib: '*'
typescript: '>=3.7.0'
peerDependenciesMeta:
rollup:
optional: true
tslib:
optional: true
'@rollup/pluginutils@5.3.0':
resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
'@rollup/rollup-android-arm-eabi@4.53.3':
resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.53.3':
resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.53.3':
resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.53.3':
resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.53.3':
resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.53.3':
resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==}
cpu: [x64]
os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.53.3':
resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-arm64-musl@4.53.3':
resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-loong64-gnu@4.53.3':
resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
cpu: [loong64]
os: [linux]
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
cpu: [ppc64]
os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.53.3':
resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.53.3':
resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
cpu: [s390x]
os: [linux]
'@rollup/rollup-linux-x64-gnu@4.53.3':
resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
cpu: [x64]
os: [linux]
'@rollup/rollup-linux-x64-musl@4.53.3':
resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
cpu: [x64]
os: [linux]
'@rollup/rollup-openharmony-arm64@4.53.3':
resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==}
cpu: [arm64]
os: [openharmony]
'@rollup/rollup-win32-arm64-msvc@4.53.3':
resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.53.3':
resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-gnu@4.53.3':
resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==}
cpu: [x64]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.53.3':
resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==}
cpu: [x64]
os: [win32]
'@types/bun@1.3.2':
resolution: {integrity: sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/node@24.10.1':
resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==}
'@types/react@19.2.6':
resolution: {integrity: sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==}
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
axios@1.11.0:
resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==}
bun-types@1.3.2:
resolution: {integrity: sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg==}
peerDependencies:
'@types/react': ^19
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
@@ -66,9 +254,19 @@ packages:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
dayjs@1.11.13:
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@@ -97,9 +295,21 @@ packages:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
follow-redirects@1.15.11:
resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
engines: {node: '>=4.0'}
@@ -113,6 +323,11 @@ packages:
resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
engines: {node: '>= 6'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@@ -140,6 +355,19 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
is-core-module@2.16.1:
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
engines: {node: '>= 0.4'}
is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
jsep@1.4.0:
resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==}
engines: {node: '>= 10.16.0'}
@@ -147,6 +375,9 @@ packages:
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@@ -163,12 +394,51 @@ packages:
resolution: {integrity: sha512-RD5rOiCrHu5ImFxElTpHPdNFaoF74O00ixauQr/XkzjMRvI3yVw6xFHdxb5bFoLbeee0/7kYpOmrPSbCNQ/YMA==}
engines: {node: '>=18'}
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
picomatch@4.0.3:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
regexp-to-ast@0.5.0:
resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==}
resolve@1.22.11:
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
engines: {node: '>= 0.4'}
hasBin: true
rollup-plugin-dts@6.2.3:
resolution: {integrity: sha512-UgnEsfciXSPpASuOelix7m4DrmyQgiaWBnvI0TM4GxuDh5FkqW8E5hu57bCxXB90VvR1WNfLV80yEDN18UogSA==}
engines: {node: '>=16'}
peerDependencies:
rollup: ^3.29.4 || ^4
typescript: ^4.5 || ^5.0
rollup@4.53.3:
resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
@@ -178,6 +448,16 @@ packages:
snapshots:
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
optional: true
'@babel/helper-validator-identifier@7.28.5':
optional: true
'@chevrotain/cst-dts-gen@10.5.0':
dependencies:
'@chevrotain/gast': 10.5.0
@@ -193,6 +473,19 @@ snapshots:
'@chevrotain/utils@10.5.0': {}
'@jridgewell/sourcemap-codec@1.5.5': {}
'@kevisual/dts@0.0.3(typescript@5.9.3)':
dependencies:
'@rollup/plugin-commonjs': 28.0.9(rollup@4.53.3)
'@rollup/plugin-node-resolve': 16.0.3(rollup@4.53.3)
'@rollup/plugin-typescript': 12.3.0(rollup@4.53.3)(tslib@2.8.1)(typescript@5.9.3)
rollup: 4.53.3
rollup-plugin-dts: 6.2.3(rollup@4.53.3)(typescript@5.9.3)
tslib: 2.8.1
transitivePeerDependencies:
- typescript
'@kevisual/load@0.0.6':
dependencies:
eventemitter3: 5.0.1
@@ -204,10 +497,129 @@ snapshots:
'@kevisual/load': 0.0.6
dotenv: 16.6.1
'@rollup/plugin-commonjs@28.0.9(rollup@4.53.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
commondir: 1.0.1
estree-walker: 2.0.2
fdir: 6.5.0(picomatch@4.0.3)
is-reference: 1.2.1
magic-string: 0.30.21
picomatch: 4.0.3
optionalDependencies:
rollup: 4.53.3
'@rollup/plugin-node-resolve@16.0.3(rollup@4.53.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
'@types/resolve': 1.20.2
deepmerge: 4.3.1
is-module: 1.0.0
resolve: 1.22.11
optionalDependencies:
rollup: 4.53.3
'@rollup/plugin-typescript@12.3.0(rollup@4.53.3)(tslib@2.8.1)(typescript@5.9.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
resolve: 1.22.11
typescript: 5.9.3
optionalDependencies:
rollup: 4.53.3
tslib: 2.8.1
'@rollup/pluginutils@5.3.0(rollup@4.53.3)':
dependencies:
'@types/estree': 1.0.8
estree-walker: 2.0.2
picomatch: 4.0.3
optionalDependencies:
rollup: 4.53.3
'@rollup/rollup-android-arm-eabi@4.53.3':
optional: true
'@rollup/rollup-android-arm64@4.53.3':
optional: true
'@rollup/rollup-darwin-arm64@4.53.3':
optional: true
'@rollup/rollup-darwin-x64@4.53.3':
optional: true
'@rollup/rollup-freebsd-arm64@4.53.3':
optional: true
'@rollup/rollup-freebsd-x64@4.53.3':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.53.3':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.53.3':
optional: true
'@rollup/rollup-linux-arm64-musl@4.53.3':
optional: true
'@rollup/rollup-linux-loong64-gnu@4.53.3':
optional: true
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.53.3':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.53.3':
optional: true
'@rollup/rollup-linux-x64-gnu@4.53.3':
optional: true
'@rollup/rollup-linux-x64-musl@4.53.3':
optional: true
'@rollup/rollup-openharmony-arm64@4.53.3':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.53.3':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.53.3':
optional: true
'@rollup/rollup-win32-x64-gnu@4.53.3':
optional: true
'@rollup/rollup-win32-x64-msvc@4.53.3':
optional: true
'@types/bun@1.3.2(@types/react@19.2.6)':
dependencies:
bun-types: 1.3.2(@types/react@19.2.6)
transitivePeerDependencies:
- '@types/react'
'@types/estree@1.0.8': {}
'@types/node@24.10.1':
dependencies:
undici-types: 7.16.0
'@types/react@19.2.6':
dependencies:
csstype: 3.2.3
'@types/resolve@1.20.2': {}
asynckit@0.4.0: {}
axios@1.11.0:
@@ -218,6 +630,11 @@ snapshots:
transitivePeerDependencies:
- debug
bun-types@1.3.2(@types/react@19.2.6):
dependencies:
'@types/node': 24.10.1
'@types/react': 19.2.6
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
@@ -236,8 +653,14 @@ snapshots:
dependencies:
delayed-stream: 1.0.0
commondir@1.0.1: {}
csstype@3.2.3: {}
dayjs@1.11.13: {}
deepmerge@4.3.1: {}
delayed-stream@1.0.0: {}
dotenv@16.6.1: {}
@@ -263,8 +686,14 @@ snapshots:
has-tostringtag: 1.0.2
hasown: 2.0.2
estree-walker@2.0.2: {}
eventemitter3@5.0.1: {}
fdir@6.5.0(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
follow-redirects@1.15.11: {}
form-data@4.0.4:
@@ -275,6 +704,9 @@ snapshots:
hasown: 2.0.2
mime-types: 2.1.35
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {}
get-intrinsic@1.3.0:
@@ -307,10 +739,27 @@ snapshots:
dependencies:
function-bind: 1.1.2
is-core-module@2.16.1:
dependencies:
hasown: 2.0.2
is-module@1.0.0: {}
is-reference@1.2.1:
dependencies:
'@types/estree': 1.0.8
js-tokens@4.0.0:
optional: true
jsep@1.4.0: {}
lodash@4.17.21: {}
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
math-intrinsics@1.1.0: {}
mime-db@1.52.0: {}
@@ -329,10 +778,65 @@ snapshots:
transitivePeerDependencies:
- debug
path-parse@1.0.7: {}
picocolors@1.1.1:
optional: true
picomatch@4.0.3: {}
proxy-from-env@1.1.0: {}
regexp-to-ast@0.5.0: {}
resolve@1.22.11:
dependencies:
is-core-module: 2.16.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
rollup-plugin-dts@6.2.3(rollup@4.53.3)(typescript@5.9.3):
dependencies:
magic-string: 0.30.21
rollup: 4.53.3
typescript: 5.9.3
optionalDependencies:
'@babel/code-frame': 7.27.1
rollup@4.53.3:
dependencies:
'@types/estree': 1.0.8
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.53.3
'@rollup/rollup-android-arm64': 4.53.3
'@rollup/rollup-darwin-arm64': 4.53.3
'@rollup/rollup-darwin-x64': 4.53.3
'@rollup/rollup-freebsd-arm64': 4.53.3
'@rollup/rollup-freebsd-x64': 4.53.3
'@rollup/rollup-linux-arm-gnueabihf': 4.53.3
'@rollup/rollup-linux-arm-musleabihf': 4.53.3
'@rollup/rollup-linux-arm64-gnu': 4.53.3
'@rollup/rollup-linux-arm64-musl': 4.53.3
'@rollup/rollup-linux-loong64-gnu': 4.53.3
'@rollup/rollup-linux-ppc64-gnu': 4.53.3
'@rollup/rollup-linux-riscv64-gnu': 4.53.3
'@rollup/rollup-linux-riscv64-musl': 4.53.3
'@rollup/rollup-linux-s390x-gnu': 4.53.3
'@rollup/rollup-linux-x64-gnu': 4.53.3
'@rollup/rollup-linux-x64-musl': 4.53.3
'@rollup/rollup-openharmony-arm64': 4.53.3
'@rollup/rollup-win32-arm64-msvc': 4.53.3
'@rollup/rollup-win32-ia32-msvc': 4.53.3
'@rollup/rollup-win32-x64-gnu': 4.53.3
'@rollup/rollup-win32-x64-msvc': 4.53.3
fsevents: 2.3.3
supports-preserve-symlinks-flag@1.0.0: {}
tslib@2.8.1: {}
typescript@5.9.3: {}
undici-types@7.16.0: {}
validator@13.15.15: {}

200
readme.md
View File

@@ -1,22 +1,200 @@
# nocodb api sdk
# NocoDB API SDK
一个轻量级的 NocoDB API SDK支持表记录操作和 Base 管理功能。
## 功能特性
- 📋 **记录操作**: 完整的 CRUD 操作支持
- 🗄️ **Base 管理**: 创建、列出、更新、删除 Bases
- 🔗 **关联数据**: 支持链接字段操作
- 📊 **统计信息**: 获取 Base 和记录统计
- 🎯 **类型安全**: 完整的 TypeScript 类型定义
## 快速开始
### 基本用法
```ts
const nocoAPi = new NocoApi({
baseURL: config.NOCODB_URL,
token: config.NOCODB_API_KEY,
import { NocoApi } from '@kevisual/noco';
const nocoApi = new NocoApi({
baseURL: 'https://your-nocodb-instance.com',
token: 'your-api-token',
table: 'your-table-name' // 可选,用于记录操作
});
const listResult = await nocoAPi.record.list();
await nocoAPi.record.update({ id: 1, Title: '123' });
// 记录操作
const listResult = await nocoApi.record.list();
await nocoApi.record.update({ Id: 1, Title: '更新的标题' });
```
## nocodb的资料地址
### Base 管理
### meta
```ts
// 列出所有 Bases
const bases = await nocoApi.meta.bases.list();
console.log('所有 Bases:', bases.list);
// 创建新的 Base
const newBase = await nocoApi.meta.bases.create({
title: '我的新项目',
description: '项目描述',
color: '#ff6b35'
});
// 获取 Base 信息
const baseInfo = await nocoApi.meta.bases.get('base-id');
// 更新 Base
await nocoApi.meta.bases.update('base-id', {
title: '更新的项目名',
description: '更新的描述'
});
// 删除 Base
await nocoApi.meta.bases.delete('base-id');
```
### 高级功能
```ts
// 复制 Base
const duplicatedBase = await nocoApi.meta.bases.duplicate('base-id', {
title: '复制的项目',
description: '这是一个复制的项目'
});
// 获取 Base 统计信息
const stats = await nocoApi.meta.bases.getStats('base-id');
// 导入/导出 Base
await nocoApi.meta.bases.importBase(importData);
const exportData = await nocoApi.meta.bases.export('base-id');
```
## API 参考
### NocoApi 构造函数选项
```ts
type NocoApiOptions = {
table?: string; // 表名(用于记录操作)
token?: string; // API 令牌
baseURL?: string; // NocoDB 实例 URL
};
```
### Base 操作类型
```ts
type BaseInfo = {
id?: string;
title: string;
description?: string;
config?: Record<string, any>;
color?: string;
meta?: Record<string, any>;
order?: number;
prefix?: string;
status?: string;
type?: string;
created_at?: string;
updated_at?: string;
};
type CreateBaseData = {
title: string;
description?: string;
color?: string;
meta?: Record<string, any>;
config?: Record<string, any>;
};
```
### 记录操作
```ts
// 查询参数
type QueryParams = {
fields?: string | string[]; // 选择字段
sort?: string | string[]; // 排序
where?: string; // 查询条件
offset?: number; // 偏移量
limit?: number; // 限制数量
viewId?: string; // 视图 ID
};
// 列出记录
await nocoApi.record.list<T>(params);
// 创建记录
await nocoApi.record.create(data);
// 读取记录
await nocoApi.record.read(id);
// 更新记录
await nocoApi.record.update(data);
// 删除记录
await nocoApi.record.delete({ Id: id });
// 获取记录数量
await nocoApi.record.count();
```
### 链接字段操作
```ts
// 列出链接记录
await nocoApi.record.listLinks(linkFieldId, recordId);
// 更新链接
await nocoApi.record.updateLinks(linkFieldId, recordId, data);
// 删除链接
await nocoApi.record.deleteLinks(linkFieldId, recordId);
```
## 独立使用 Meta API
```ts
import { MetaBases } from '@kevisual/noco';
const metaBases = new MetaBases({
token: 'your-api-token',
baseURL: 'https://your-nocodb-instance.com'
});
const bases = await metaBases.list();
```
## 错误处理
```ts
try {
const result = await nocoApi.meta.bases.create({
title: '新项目'
});
if (result.code === 200) {
console.log('创建成功:', result.data);
} else {
console.error('创建失败:', result.message);
}
} catch (error) {
console.error('请求错误:', error);
}
```
## 参考资料
### Meta API
https://nocodb.com/apis/v2/meta
### data
### Data API
https://nocodb.com/apis/v2/data
https://nocodb.com/apis/v2/data
## 许可证
MIT

View File

@@ -54,3 +54,16 @@ export class Query {
});
}
}
export type ResponseList<T = any> = {
code: number;
list: T[];
pageInfo?: {
totalRows?: number;
page?: number;
pageSize?: number;
isFirstPage?: boolean;
isLastPage?: boolean;
};
};

View File

@@ -1 +1,5 @@
export * from './base.ts';
export * from './record.ts';
export * from './api.ts';
export * from './main.ts';
export * from './meta/index.ts';

73
src/main.ts Normal file
View File

@@ -0,0 +1,73 @@
import { Query } from './api.ts';
import { Meta } from './meta/index.ts';
import { Record } from './record.ts';
export type NocoApiOptions = {
table?: string;
token?: string;
baseURL?: string;
};
export class NocoApi {
query: Query;
record: Record;
meta: Meta;
constructor(options?: NocoApiOptions) {
const table = options?.table;
const token = options?.token;
const baseURL = options?.baseURL;
this.query = new Query({ baseURL, token });
this.record = new Record(this.query, table);
this.meta = new Meta({ query: this.query });
}
/**
*
* @param baseId
* @param data
*/
async createExampleTable(baseId: string, data?: ExampleTableData) {
const defaultColumns = [{
title: 'Title',
uidt: 'SingleLineText',
description: '标题列',
},
{
title: 'Summary',
uidt: 'LongText',
description: '摘要列',
},
{
title: 'Tags',
uidt: 'MultiSelect',
description: '标签列',
},
{
title: 'Description',
uidt: 'LongText',
description: '描述列',
},
{
title: 'Link',
uidt: 'URL',
description: '链接列',
}]
const columns = data?.columns || [];
for (const col of defaultColumns) {
if (!columns.find(c => c.title === col.title)) {
columns.push(col);
}
}
const res = await this.meta.tables.createTable(baseId, {
title: data?.title || '基本表',
description: data?.description || '',
columns: columns
})
return res;
}
}
export type ExampleTableData = {
title?: string;
description?: string;
columns?: any[];
}

95
src/meta/base.ts Normal file
View File

@@ -0,0 +1,95 @@
import { Query } from '../api.ts';
export type BaseOptions = {
query: Query;
};
export type BaseInfo = {
id?: string;
title: string;
description?: string;
config?: Record<string, any>;
color?: string;
meta?: Record<string, any>;
order?: number;
prefix?: string;
status?: string;
type?: string;
created_at?: string;
updated_at?: string;
};
export type CreateBaseData = {
title: string;
description?: string;
color?: string;
meta?: Record<string, any>;
config?: Record<string, any>;
};
export type UpdateBaseData = {
id?: string;
title?: string;
description?: string;
color?: string;
meta?: Record<string, any>;
config?: Record<string, any>;
};
export type BaseListResult = {
code: number;
list: BaseInfo[];
pageInfo?: {
totalRows?: number;
page?: number;
pageSize?: number;
isFirstPage?: boolean;
isLastPage?: boolean;
};
};
export type BaseResult = {
code: number;
data?: BaseInfo;
message?: string;
};
/**
* NocoDB Base 管理服务
* @url https://nocodb.com/apis/v2/meta
*/
export class MetaBases {
query: Query;
constructor(options?: BaseOptions) {
this.query = options?.query;
}
/**
* 列出所有 bases
*/
async list(workspaceId: string): Promise<BaseListResult> {
return this.query.makeRequest(`/api/v2/meta/workspaces/${workspaceId}/bases`, {
method: 'GET',
});
}
/**
* 创建新的 base
*/
async create(data: CreateBaseData): Promise<BaseResult> {
return this.query.makeRequest('/api/v2/meta/bases', {
method: 'POST',
data,
});
}
/**
* 获取指定 base 的信息
*/
async get(baseId: string): Promise<BaseResult> {
return this.query.makeRequest(`/api/v2/meta/bases/${baseId}`, {
method: 'GET',
});
}
}

24
src/meta/index.ts Normal file
View File

@@ -0,0 +1,24 @@
import { Query } from '../api.ts';
import { MetaBases, BaseOptions } from './base.ts';
import { MetaTables } from './tables.ts';
export type MetaOptions = {
query: Query;
};
/**
* NocoDB Meta API 管理类
* 统一管理所有的 meta 相关操作
*/
export class Meta {
query: Query;
bases: MetaBases;
tables: MetaTables;
constructor(options?: MetaOptions) {
this.query = options?.query;
this.bases = new MetaBases({ query: this.query });
this.tables = new MetaTables({ query: this.query });
}
}
// 重新导出所有 meta 相关的类型和类
export * from './base.ts';

95
src/meta/tables.ts Normal file
View File

@@ -0,0 +1,95 @@
import { Query, ResponseList } from '../api.ts';
export type BaseOptions = {
query: Query;
};
type TableMetaInfo = {
id: string;
source_id: string;
base_id: string;
table_name: string;
title: string;
type: string;
meta: any;
schema: any;
enabled: boolean;
mm: boolean;
tags: string | null;
pinned: boolean | null;
deleted: boolean | null;
order: number;
created_at: string;
updated_at: string;
description: string;
synced: boolean;
created_by: string | null;
owned_by: string | null;
uuid: string | null;
password: string | null;
fk_custom_url_id: string | null;
}
export class MetaTables {
query: Query;
constructor(options?: BaseOptions) {
this.query = options?.query;
}
/**
* 列出所有 tables
*/
async list(baseId: string): Promise<ResponseList<TableMetaInfo>> {
return this.query.makeRequest(`/api/v2/meta/bases/${baseId}/tables`, {
method: 'GET',
});
}
async createTable(baseId: string, data: CreateTableData): Promise<{ code: number; data: TableMetaInfo }> {
return this.query.makeRequest(`/api/v2/meta/bases/${baseId}/tables`, {
method: 'POST',
data,
});
}
async getTableMeta(tableId: string): Promise<{ code: number; data: TableMetaInfo }> {
return this.query.makeRequest(`/api/v2/meta/tables/${tableId}`, {
method: 'GET',
});
}
async createColumn(tableId: string, data: any): Promise<{ code: number; data: any }> {
return this.query.makeRequest(`/api/v2/meta/tables/${tableId}/columns`, {
method: 'POST',
data,
});
}
}
export type CreateColumnData = {
title: string;
uidt?: ColumnTypes
description?: string;
}
export const columnTypes = [
'SingleLineText',
'LongText',
'URL',
'Email',
'Number',
'SingleSelect',
'MultiSelect',
'DateTime',
'Time',
'Date',
'Checkbox',
'JSON'
] as const;
export type ColumnTypes = typeof columnTypes[number];
export type CreateTableData = {
table_name?: string;
title: string;
description?: string;
columns: CreateColumnData[];
[key: string]: any;
}

View File

@@ -1,21 +1,5 @@
import { Query } from './api.ts';
export type NocoApiOptions = {
table?: string;
token?: string;
baseURL?: string;
};
export class NocoApi {
query: Query;
record: Record;
constructor(options?: NocoApiOptions) {
const table = options.table;
const token = options.token;
const baseURL = options.baseURL;
this.query = new Query({ baseURL, token });
this.record = new Record(this.query, table);
}
}
import { Query } from './api.ts';
type QueryParams = {
/**
* fields=field1,field2
@@ -49,7 +33,7 @@ type Id = string | number;
/**
* @url https://nocodb.com/apis/v2/data#tag/Table-Records
*/
class Record {
export class Record {
query: Query;
table: string;
constructor(query: Query, table: string) {
@@ -109,13 +93,3 @@ class Record {
}
/**
* TODO
* @url https://nocodb.com/apis/v2/meta
*/
class Meta {
bases: string;
constructor() {
this.bases = '';
}
}

14
test/common.ts Normal file
View File

@@ -0,0 +1,14 @@
import { NocoApi } from './../src/main.ts';
import { useConfig } from '@kevisual/use-config'
export const config = useConfig()
// # 签到表
const table = 'mcby44q8zrayvn9'
export const nocoApi = new NocoApi({
baseURL: config.NOCODB_URL || 'http://localhost:8080',
token: config.NOCODB_API_KEY || '',
table,
});
// console.log('nocoApi', await nocoApi.record.list())

54
test/list-base.ts Normal file
View File

@@ -0,0 +1,54 @@
import { nocoApi } from "./common";
import bun from 'bun'
// const res = await nocoApi.meta.bases.list('')
// console.log('bases list', res);
// AI id
const baseId = 'pypv3deh9qzol7q'
const startId = 'prg9dee7ldbemzd'
// const res = await nocoApi.meta.tables.list(baseId)
// console.log('tables list', res);
const tableId = 'm9rcgc95ev9d1uo'
// const tableMeta = await nocoApi.meta.tables.getTableMeta(tableId)
// console.log('tableMeta', tableMeta);
// bun.write('meta.json', JSON.stringify(tableMeta, null, 2))
const newTables = await nocoApi.meta.tables.createTable(startId, {
title: '测试表3',
description: '这是一个测试表3',
columns: [
{
title: 'Title',
uidt: 'SingleLineText',
description: '标题列',
},
{
title: 'Summary',
uidt: 'LongText',
description: '摘要列',
},
{
title: 'Tags',
uidt: 'MultiSelect',
description: '标签列',
},
{
title: 'Description',
uidt: 'LongText',
description: '描述列',
},
{
title: 'Link',
uidt: 'URL',
description: '链接列',
},
]
})
console.log('newTables', newTables);