From 525e249d41085592b4c9d56ee27cb12f6ae6fd65 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 12 Dec 2024 18:14:53 +0000 Subject: [PATCH 001/173] First pass at migrating to AWS SDK v3. --- packages/backend-core/package.json | 5 +- .../src/objectStore/buckets/app.ts | 8 +- .../src/objectStore/buckets/global.ts | 8 +- .../src/objectStore/buckets/plugins.ts | 22 +- .../src/objectStore/buckets/tests/app.spec.ts | 8 +- .../objectStore/buckets/tests/global.spec.ts | 8 +- .../src/objectStore/objectStore.ts | 177 ++- .../backend-core/src/objectStore/utils.ts | 9 +- packages/cli/src/backups/objectStore.ts | 25 +- packages/server/package.json | 5 +- .../server/src/api/controllers/application.ts | 2 +- .../src/api/controllers/static/index.ts | 26 +- .../src/automations/tests/createRow.spec.ts | 18 +- packages/server/src/integrations/dynamodb.ts | 38 +- packages/server/src/integrations/s3.ts | 57 +- .../server/src/integrations/utils/utils.ts | 2 +- .../src/utilities/rowProcessor/index.ts | 14 +- .../src/api/controllers/global/configs.ts | 46 +- yarn.lock | 1143 ++++++++++++++++- 19 files changed, 1352 insertions(+), 269 deletions(-) diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 3e1b5f324b..4339ee0a94 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -30,6 +30,9 @@ "test:watch": "jest --watchAll" }, "dependencies": { + "@aws-sdk/client-s3": "3.709.0", + "@aws-sdk/lib-storage": "3.709.0", + "@aws-sdk/s3-request-presigner": "3.709.0", "@budibase/nano": "10.1.5", "@budibase/pouchdb-replication-stream": "1.2.11", "@budibase/shared-core": "*", @@ -76,6 +79,7 @@ "@types/chance": "1.1.3", "@types/cookies": "0.7.8", "@types/jest": "29.5.5", + "@types/koa": "2.13.4", "@types/lodash": "4.14.200", "@types/node-fetch": "2.6.4", "@types/pouchdb": "6.4.2", @@ -83,7 +87,6 @@ "@types/semver": "7.3.7", "@types/tar-fs": "2.0.1", "@types/uuid": "8.3.4", - "@types/koa": "2.13.4", "chance": "1.1.8", "ioredis-mock": "8.9.0", "jest": "29.7.0", diff --git a/packages/backend-core/src/objectStore/buckets/app.ts b/packages/backend-core/src/objectStore/buckets/app.ts index 43bc965c65..dbf49ca994 100644 --- a/packages/backend-core/src/objectStore/buckets/app.ts +++ b/packages/backend-core/src/objectStore/buckets/app.ts @@ -13,7 +13,7 @@ export function clientLibraryPath(appId: string) { * due to issues with the domain we were unable to continue doing this - keeping * incase we are able to switch back to CDN path again in future. */ -export function clientLibraryCDNUrl(appId: string, version: string) { +export async function clientLibraryCDNUrl(appId: string, version: string) { let file = clientLibraryPath(appId) if (env.CLOUDFRONT_CDN) { // append app version to bust the cache @@ -24,7 +24,7 @@ export function clientLibraryCDNUrl(appId: string, version: string) { // file is public return cloudfront.getUrl(file) } else { - return objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, file) + return await objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, file) } } @@ -44,10 +44,10 @@ export function clientLibraryUrl(appId: string, version: string) { return `/api/assets/client?${qs.encode(qsParams)}` } -export function getAppFileUrl(s3Key: string) { +export async function getAppFileUrl(s3Key: string) { if (env.CLOUDFRONT_CDN) { return cloudfront.getPresignedUrl(s3Key) } else { - return objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, s3Key) + return await objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, s3Key) } } diff --git a/packages/backend-core/src/objectStore/buckets/global.ts b/packages/backend-core/src/objectStore/buckets/global.ts index 69e201bb98..29c3347b05 100644 --- a/packages/backend-core/src/objectStore/buckets/global.ts +++ b/packages/backend-core/src/objectStore/buckets/global.ts @@ -5,7 +5,11 @@ import * as cloudfront from "../cloudfront" // URLs -export const getGlobalFileUrl = (type: string, name: string, etag?: string) => { +export const getGlobalFileUrl = async ( + type: string, + name: string, + etag?: string +) => { let file = getGlobalFileS3Key(type, name) if (env.CLOUDFRONT_CDN) { if (etag) { @@ -13,7 +17,7 @@ export const getGlobalFileUrl = (type: string, name: string, etag?: string) => { } return cloudfront.getPresignedUrl(file) } else { - return objectStore.getPresignedUrl(env.GLOBAL_BUCKET_NAME, file) + return await objectStore.getPresignedUrl(env.GLOBAL_BUCKET_NAME, file) } } diff --git a/packages/backend-core/src/objectStore/buckets/plugins.ts b/packages/backend-core/src/objectStore/buckets/plugins.ts index 02be9345ab..131f180f48 100644 --- a/packages/backend-core/src/objectStore/buckets/plugins.ts +++ b/packages/backend-core/src/objectStore/buckets/plugins.ts @@ -6,23 +6,25 @@ import { Plugin } from "@budibase/types" // URLS -export function enrichPluginURLs(plugins?: Plugin[]): Plugin[] { +export async function enrichPluginURLs(plugins?: Plugin[]): Promise { if (!plugins || !plugins.length) { return [] } - return plugins.map(plugin => { - const jsUrl = getPluginJSUrl(plugin) - const iconUrl = getPluginIconUrl(plugin) - return { ...plugin, jsUrl, iconUrl } - }) + return await Promise.all( + plugins.map(async plugin => { + const jsUrl = await getPluginJSUrl(plugin) + const iconUrl = await getPluginIconUrl(plugin) + return { ...plugin, jsUrl, iconUrl } + }) + ) } -function getPluginJSUrl(plugin: Plugin) { +async function getPluginJSUrl(plugin: Plugin) { const s3Key = getPluginJSKey(plugin) return getPluginUrl(s3Key) } -function getPluginIconUrl(plugin: Plugin): string | undefined { +async function getPluginIconUrl(plugin: Plugin) { const s3Key = getPluginIconKey(plugin) if (!s3Key) { return @@ -30,11 +32,11 @@ function getPluginIconUrl(plugin: Plugin): string | undefined { return getPluginUrl(s3Key) } -function getPluginUrl(s3Key: string) { +async function getPluginUrl(s3Key: string) { if (env.CLOUDFRONT_CDN) { return cloudfront.getPresignedUrl(s3Key) } else { - return objectStore.getPresignedUrl(env.PLUGIN_BUCKET_NAME, s3Key) + return await objectStore.getPresignedUrl(env.PLUGIN_BUCKET_NAME, s3Key) } } diff --git a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts index 4a132ce54d..1aeba8f2c2 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts @@ -109,9 +109,9 @@ describe("app", () => { ) }) - it("gets url with cloudfront + s3", () => { + it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - const url = getAppFileUrl() + const url = await getAppFileUrl() // omit rest of signed params expect( url.includes("http://cf.example.com/app_123/attachments/image.jpeg?") @@ -146,8 +146,8 @@ describe("app", () => { it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - await testEnv.withTenant(() => { - const url = getAppFileUrl() + await testEnv.withTenant(async () => { + const url = await getAppFileUrl() // omit rest of signed params expect( url.includes( diff --git a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts index 148a4c80bf..be459a7a23 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts @@ -24,9 +24,9 @@ describe("global", () => { expect(url).toBe("http://s3.example.com/global/settings/logoUrl") }) - it("gets url with cloudfront + s3", () => { + it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - const url = getGlobalFileUrl() + const url = await getGlobalFileUrl() // omit rest of signed params expect( url.includes("http://cf.example.com/settings/logoUrl?etag=etag&") @@ -59,8 +59,8 @@ describe("global", () => { it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - await testEnv.withTenant(tenantId => { - const url = getGlobalFileUrl() + await testEnv.withTenant(async tenantId => { + const url = await getGlobalFileUrl() // omit rest of signed params expect( url.includes( diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index 79875b5e99..6acf2e21ae 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -1,6 +1,15 @@ const sanitize = require("sanitize-s3-objectkey") -import AWS from "aws-sdk" +import { + HeadObjectCommandOutput, + PutObjectCommandInput, + S3, + S3ClientConfig, + GetObjectCommand, + _Object as S3Object, +} from "@aws-sdk/client-s3" +import { Upload } from "@aws-sdk/lib-storage" +import { getSignedUrl } from "@aws-sdk/s3-request-presigner" import stream, { Readable } from "stream" import fetch from "node-fetch" import tar from "tar-fs" @@ -13,7 +22,6 @@ import { bucketTTLConfig, budibaseTempDir } from "./utils" import { v4 } from "uuid" import { APP_PREFIX, APP_DEV_PREFIX } from "../db" import fsp from "fs/promises" -import { HeadObjectOutput } from "aws-sdk/clients/s3" import { ReadableStream } from "stream/web" const streamPipeline = promisify(stream.pipeline) @@ -84,26 +92,24 @@ export function sanitizeBucket(input: string) { * @constructor */ export function ObjectStore( - bucket: string, opts: { presigning: boolean } = { presigning: false } ) { - const config: AWS.S3.ClientConfiguration = { - s3ForcePathStyle: true, - signatureVersion: "v4", - apiVersion: "2006-03-01", - accessKeyId: env.MINIO_ACCESS_KEY, - secretAccessKey: env.MINIO_SECRET_KEY, + const config: S3ClientConfig = { + forcePathStyle: true, + credentials: { + accessKeyId: env.MINIO_ACCESS_KEY!, + secretAccessKey: env.MINIO_SECRET_KEY!, + }, region: env.AWS_REGION, } - if (bucket) { - config.params = { - Bucket: sanitizeBucket(bucket), - } - } // for AWS Credentials using temporary session token if (!env.MINIO_ENABLED && env.AWS_SESSION_TOKEN) { - config.sessionToken = env.AWS_SESSION_TOKEN + config.credentials = { + accessKeyId: env.MINIO_ACCESS_KEY!, + secretAccessKey: env.MINIO_SECRET_KEY!, + sessionToken: env.AWS_SESSION_TOKEN, + } } // custom S3 is in use i.e. minio @@ -119,7 +125,7 @@ export function ObjectStore( } } - return new AWS.S3(config) + return new S3(config) } /** @@ -132,7 +138,9 @@ export async function createBucketIfNotExists( ): Promise<{ created: boolean; exists: boolean }> { bucketName = sanitizeBucket(bucketName) try { - await client + await // The `.promise()` call might be on an JS SDK v2 client API. + // If yes, please remove .promise(). If not, remove this comment. + client .headBucket({ Bucket: bucketName, }) @@ -147,11 +155,13 @@ export async function createBucketIfNotExists( return { created: false, exists: true } } else if (doesntExist || noAccess) { if (doesntExist) { - promises[bucketName] = client - .createBucket({ - Bucket: bucketName, - }) - .promise() + promises[bucketName] = // The `.promise()` call might be on an JS SDK v2 client API. + // If yes, please remove .promise(). If not, remove this comment. + client + .createBucket({ + Bucket: bucketName, + }) + .promise() await promises[bucketName] delete promises[bucketName] return { created: true, exists: false } @@ -180,12 +190,12 @@ export async function upload({ const fileBytes = path ? (await fsp.open(path)).createReadStream() : body - const objectStore = ObjectStore(bucketName) + const objectStore = ObjectStore() const bucketCreated = await createBucketIfNotExists(objectStore, bucketName) if (ttl && bucketCreated.created) { let ttlConfig = bucketTTLConfig(bucketName, ttl) - await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise() + await objectStore.putBucketLifecycleConfiguration(ttlConfig) } let contentType = type @@ -194,11 +204,12 @@ export async function upload({ ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt } - const config: any = { + const config: PutObjectCommandInput = { // windows file paths need to be converted to forward slashes for s3 + Bucket: sanitizeBucket(bucketName), Key: sanitizeKey(filename), - Body: fileBytes, - ContentType: contentType, + Body: fileBytes as stream.Readable | Buffer, + ContentType: contentType!, } if (metadata && typeof metadata === "object") { // remove any nullish keys from the metadata object, as these may be considered invalid @@ -207,10 +218,15 @@ export async function upload({ delete metadata[key] } } - config.Metadata = metadata + config.Metadata = metadata as Record } - return objectStore.upload(config).promise() + const upload = new Upload({ + client: objectStore, + params: config, + }) + + return upload.done() } /** @@ -229,12 +245,12 @@ export async function streamUpload({ throw new Error("Stream to upload is invalid/undefined") } const extension = filename.split(".").pop() - const objectStore = ObjectStore(bucketName) + const objectStore = ObjectStore() const bucketCreated = await createBucketIfNotExists(objectStore, bucketName) if (ttl && bucketCreated.created) { let ttlConfig = bucketTTLConfig(bucketName, ttl) - await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise() + await objectStore.putBucketLifecycleConfiguration(ttlConfig) } // Set content type for certain known extensions @@ -267,13 +283,15 @@ export async function streamUpload({ ...extra, } - const details = await objectStore.upload(params).promise() - const headDetails = await objectStore - .headObject({ - Bucket: bucket, - Key: objKey, - }) - .promise() + const upload = new Upload({ + client: objectStore, + params, + }) + const details = await upload.done() + const headDetails = await objectStore.headObject({ + Bucket: bucket, + Key: objKey, + }) return { ...details, ContentLength: headDetails.ContentLength, @@ -284,35 +302,42 @@ export async function streamUpload({ * retrieves the contents of a file from the object store, if it is a known content type it * will be converted, otherwise it will be returned as a buffer stream. */ -export async function retrieve(bucketName: string, filepath: string) { - const objectStore = ObjectStore(bucketName) +export async function retrieve( + bucketName: string, + filepath: string +): Promise { + const objectStore = ObjectStore() const params = { Bucket: sanitizeBucket(bucketName), Key: sanitizeKey(filepath), } - const response: any = await objectStore.getObject(params).promise() + const response = await objectStore.getObject(params) + if (!response.Body) { + throw new Error("Unable to retrieve object") + } // currently these are all strings if (STRING_CONTENT_TYPES.includes(response.ContentType)) { - return response.Body.toString("utf8") + return response.Body.toString() } else { - return response.Body + return response.Body as stream.Readable } } -export async function listAllObjects(bucketName: string, path: string) { - const objectStore = ObjectStore(bucketName) +export async function listAllObjects( + bucketName: string, + path: string +): Promise { + const objectStore = ObjectStore() const list = (params: ListParams = {}) => { - return objectStore - .listObjectsV2({ - ...params, - Bucket: sanitizeBucket(bucketName), - Prefix: sanitizeKey(path), - }) - .promise() + return objectStore.listObjectsV2({ + ...params, + Bucket: sanitizeBucket(bucketName), + Prefix: sanitizeKey(path), + }) } let isTruncated = false, token, - objects: AWS.S3.Types.Object[] = [] + objects: Object[] = [] do { let params: ListParams = {} if (token) { @@ -331,18 +356,19 @@ export async function listAllObjects(bucketName: string, path: string) { /** * Generate a presigned url with a default TTL of 1 hour */ -export function getPresignedUrl( +export async function getPresignedUrl( bucketName: string, key: string, durationSeconds = 3600 ) { - const objectStore = ObjectStore(bucketName, { presigning: true }) + const objectStore = ObjectStore({ presigning: true }) const params = { Bucket: sanitizeBucket(bucketName), Key: sanitizeKey(key), - Expires: durationSeconds, } - const url = objectStore.getSignedUrl("getObject", params) + const url = await getSignedUrl(objectStore, new GetObjectCommand(params), { + expiresIn: durationSeconds, + }) if (!env.MINIO_ENABLED) { // return the full URL to the client @@ -366,7 +392,11 @@ export async function retrieveToTmp(bucketName: string, filepath: string) { filepath = sanitizeKey(filepath) const data = await retrieve(bucketName, filepath) const outputPath = join(budibaseTempDir(), v4()) - fs.writeFileSync(outputPath, data) + if (data instanceof stream.Readable) { + data.pipe(fs.createWriteStream(outputPath)) + } else { + fs.writeFileSync(outputPath, data) + } return outputPath } @@ -408,17 +438,17 @@ export async function retrieveDirectory(bucketName: string, path: string) { * Delete a single file. */ export async function deleteFile(bucketName: string, filepath: string) { - const objectStore = ObjectStore(bucketName) + const objectStore = ObjectStore() await createBucketIfNotExists(objectStore, bucketName) const params = { Bucket: bucketName, Key: sanitizeKey(filepath), } - return objectStore.deleteObject(params).promise() + return objectStore.deleteObject(params) } export async function deleteFiles(bucketName: string, filepaths: string[]) { - const objectStore = ObjectStore(bucketName) + const objectStore = ObjectStore() await createBucketIfNotExists(objectStore, bucketName) const params = { Bucket: bucketName, @@ -426,7 +456,7 @@ export async function deleteFiles(bucketName: string, filepaths: string[]) { Objects: filepaths.map((path: any) => ({ Key: sanitizeKey(path) })), }, } - return objectStore.deleteObjects(params).promise() + return objectStore.deleteObjects(params) } /** @@ -438,13 +468,16 @@ export async function deleteFolder( ): Promise { bucketName = sanitizeBucket(bucketName) folder = sanitizeKey(folder) - const client = ObjectStore(bucketName) + const client = ObjectStore() const listParams = { Bucket: bucketName, Prefix: folder, } - const existingObjectsResponse = await client.listObjects(listParams).promise() + const existingObjectsResponse = + await // The `.promise()` call might be on an JS SDK v2 client API. + // If yes, please remove .promise(). If not, remove this comment. + client.listObjects(listParams) if (existingObjectsResponse.Contents?.length === 0) { return } @@ -459,7 +492,7 @@ export async function deleteFolder( deleteParams.Delete.Objects.push({ Key: content.Key }) }) - const deleteResponse = await client.deleteObjects(deleteParams).promise() + const deleteResponse = await client.deleteObjects(deleteParams) // can only empty 1000 items at once if (deleteResponse.Deleted?.length === 1000) { return deleteFolder(bucketName, folder) @@ -534,29 +567,33 @@ export async function getReadStream( ): Promise { bucketName = sanitizeBucket(bucketName) path = sanitizeKey(path) - const client = ObjectStore(bucketName) + const client = ObjectStore() const params = { Bucket: bucketName, Key: path, } - return client.getObject(params).createReadStream() + const response = await client.getObject(params) + if (!response.Body || !(response.Body instanceof stream.Readable)) { + throw new Error("Unable to retrieve stream - invalid response") + } + return response.Body } export async function getObjectMetadata( bucket: string, path: string -): Promise { +): Promise { bucket = sanitizeBucket(bucket) path = sanitizeKey(path) - const client = ObjectStore(bucket) + const client = ObjectStore() const params = { Bucket: bucket, Key: path, } try { - return await client.headObject(params).promise() + return await client.headObject(params) } catch (err: any) { throw new Error("Unable to retrieve metadata from object") } diff --git a/packages/backend-core/src/objectStore/utils.ts b/packages/backend-core/src/objectStore/utils.ts index 30c2fefbf1..2a9dd26e02 100644 --- a/packages/backend-core/src/objectStore/utils.ts +++ b/packages/backend-core/src/objectStore/utils.ts @@ -2,7 +2,10 @@ import path, { join } from "path" import { tmpdir } from "os" import fs from "fs" import env from "../environment" -import { PutBucketLifecycleConfigurationRequest } from "aws-sdk/clients/s3" +import { + LifecycleRule, + PutBucketLifecycleConfigurationCommandInput, +} from "@aws-sdk/client-s3" import * as objectStore from "./objectStore" import { AutomationAttachment, @@ -43,8 +46,8 @@ export function budibaseTempDir() { export const bucketTTLConfig = ( bucketName: string, days: number -): PutBucketLifecycleConfigurationRequest => { - const lifecycleRule = { +): PutBucketLifecycleConfigurationCommandInput => { + const lifecycleRule: LifecycleRule = { ID: `${bucketName}-ExpireAfter${days}days`, Prefix: "", Status: "Enabled", diff --git a/packages/cli/src/backups/objectStore.ts b/packages/cli/src/backups/objectStore.ts index 2a24199603..34e231b87b 100644 --- a/packages/cli/src/backups/objectStore.ts +++ b/packages/cli/src/backups/objectStore.ts @@ -3,6 +3,7 @@ import fs from "fs" import { join } from "path" import { TEMP_DIR, MINIO_DIR } from "./utils" import { progressBar } from "../utils" +import * as stream from "node:stream" const { ObjectStoreBuckets, @@ -20,15 +21,21 @@ export async function exportObjects() { let fullList: any[] = [] let errorCount = 0 for (let bucket of bucketList) { - const client = ObjectStore(bucket) + const client = ObjectStore() try { - await client.headBucket().promise() + await client.headBucket({ + Bucket: bucket, + }) } catch (err) { errorCount++ continue } - const list = (await client.listObjectsV2().promise()) as { Contents: any[] } - fullList = fullList.concat(list.Contents.map(el => ({ ...el, bucket }))) + const list = await client.listObjectsV2({ + Bucket: bucket, + }) + fullList = fullList.concat( + list.Contents?.map(el => ({ ...el, bucket })) || [] + ) } if (errorCount === bucketList.length) { throw new Error("Unable to access MinIO/S3 - check environment config.") @@ -43,7 +50,13 @@ export async function exportObjects() { const dirs = possiblePath.slice(0, possiblePath.length - 1) fs.mkdirSync(join(path, object.bucket, ...dirs), { recursive: true }) } - fs.writeFileSync(join(path, object.bucket, ...possiblePath), data) + if (data instanceof stream.Readable) { + data.pipe( + fs.createWriteStream(join(path, object.bucket, ...possiblePath)) + ) + } else { + fs.writeFileSync(join(path, object.bucket, ...possiblePath), data) + } bar.update(++count) } bar.stop() @@ -60,7 +73,7 @@ export async function importObjects() { const bar = progressBar(total) let count = 0 for (let bucket of buckets) { - const client = ObjectStore(bucket) + const client = ObjectStore() await createBucketIfNotExists(client, bucket) const files = await uploadDirectory(bucket, join(path, bucket), "/") count += files.length diff --git a/packages/server/package.json b/packages/server/package.json index 1dd3df1d73..7431d0ad54 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -50,6 +50,10 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "10.0.3", + "@aws-sdk/client-dynamodb": "3.709.0", + "@aws-sdk/client-s3": "3.709.0", + "@aws-sdk/lib-dynamodb": "3.709.0", + "@aws-sdk/s3-request-presigner": "3.709.0", "@azure/msal-node": "^2.5.1", "@budibase/backend-core": "*", "@budibase/client": "*", @@ -70,7 +74,6 @@ "airtable": "0.12.2", "arangojs": "7.2.0", "archiver": "7.0.1", - "aws-sdk": "2.1692.0", "bcrypt": "5.1.0", "bcryptjs": "2.4.3", "bson": "^6.9.0", diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index d032f14150..d05f6f2eaa 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -225,7 +225,7 @@ export async function fetchAppPackage( const license = await licensing.cache.getCachedLicense() // Enrich plugin URLs - application.usedPlugins = objectStore.enrichPluginURLs( + application.usedPlugins = await objectStore.enrichPluginURLs( application.usedPlugins ) diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 0dd5e77c50..8b5c61e875 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -18,7 +18,8 @@ import { objectStore, utils, } from "@budibase/backend-core" -import AWS from "aws-sdk" +import { getSignedUrl } from "@aws-sdk/s3-request-presigner" +import { PutObjectCommand, S3 } from "@aws-sdk/client-s3" import fs from "fs" import sdk from "../../../sdk" import * as pro from "@budibase/pro" @@ -128,9 +129,9 @@ export const uploadFile = async function ( return { size: file.size, name: file.name, - url: objectStore.getAppFileUrl(s3Key), + url: await objectStore.getAppFileUrl(s3Key), extension, - key: response.Key, + key: response.Key!, } }) ) @@ -210,11 +211,11 @@ export const serveApp = async function (ctx: UserCtx) { usedPlugins: plugins, favicon: branding.faviconUrl !== "" - ? objectStore.getGlobalFileUrl("settings", "faviconUrl") + ? await objectStore.getGlobalFileUrl("settings", "faviconUrl") : "", logo: config?.logoUrl !== "" - ? objectStore.getGlobalFileUrl("settings", "logoUrl") + ? await objectStore.getGlobalFileUrl("settings", "logoUrl") : "", appMigrating: needMigrations, nonce: ctx.state.nonce, @@ -243,7 +244,7 @@ export const serveApp = async function (ctx: UserCtx) { metaDescription: branding?.metaDescription || "", favicon: branding.faviconUrl !== "" - ? objectStore.getGlobalFileUrl("settings", "faviconUrl") + ? await objectStore.getGlobalFileUrl("settings", "faviconUrl") : "", }) @@ -334,16 +335,17 @@ export const getSignedUploadURL = async function ( ctx.throw(400, "bucket and key values are required") } try { - const s3 = new AWS.S3({ + const s3 = new S3({ region: awsRegion, endpoint: datasource?.config?.endpoint || undefined, - accessKeyId: datasource?.config?.accessKeyId as string, - secretAccessKey: datasource?.config?.secretAccessKey as string, - apiVersion: "2006-03-01", - signatureVersion: "v4", + + credentials: { + accessKeyId: datasource?.config?.accessKeyId as string, + secretAccessKey: datasource?.config?.secretAccessKey as string, + }, }) const params = { Bucket: bucket, Key: key } - signedUrl = s3.getSignedUrl("putObject", params) + signedUrl = await getSignedUrl(s3, new PutObjectCommand(params)) if (datasource?.config?.endpoint) { publicUrl = `${datasource.config.endpoint}/${bucket}/${key}` } else { diff --git a/packages/server/src/automations/tests/createRow.spec.ts b/packages/server/src/automations/tests/createRow.spec.ts index bd78de2217..42b69324e2 100644 --- a/packages/server/src/automations/tests/createRow.spec.ts +++ b/packages/server/src/automations/tests/createRow.spec.ts @@ -154,11 +154,12 @@ describe("test the create row action", () => { expect(result.steps[1].outputs.row.file_attachment[0]).toHaveProperty("key") let s3Key = result.steps[1].outputs.row.file_attachment[0].key - const client = objectStore.ObjectStore(objectStore.ObjectStoreBuckets.APPS) + const client = objectStore.ObjectStore() - const objectData = await client - .headObject({ Bucket: objectStore.ObjectStoreBuckets.APPS, Key: s3Key }) - .promise() + const objectData = await client.headObject({ + Bucket: objectStore.ObjectStoreBuckets.APPS, + Key: s3Key, + }) expect(objectData).toBeDefined() expect(objectData.ContentLength).toBeGreaterThan(0) @@ -229,11 +230,12 @@ describe("test the create row action", () => { ) let s3Key = result.steps[1].outputs.row.single_file_attachment.key - const client = objectStore.ObjectStore(objectStore.ObjectStoreBuckets.APPS) + const client = objectStore.ObjectStore() - const objectData = await client - .headObject({ Bucket: objectStore.ObjectStoreBuckets.APPS, Key: s3Key }) - .promise() + const objectData = await client.headObject({ + Bucket: objectStore.ObjectStoreBuckets.APPS, + Key: s3Key, + }) expect(objectData).toBeDefined() expect(objectData.ContentLength).toBeGreaterThan(0) diff --git a/packages/server/src/integrations/dynamodb.ts b/packages/server/src/integrations/dynamodb.ts index 424a3dfce0..96941ebb0e 100644 --- a/packages/server/src/integrations/dynamodb.ts +++ b/packages/server/src/integrations/dynamodb.ts @@ -7,9 +7,15 @@ import { ConnectionInfo, } from "@budibase/types" -import AWS from "aws-sdk" +import { + DynamoDBDocument, + PutCommandInput, + GetCommandInput, + UpdateCommandInput, + DeleteCommandInput, +} from "@aws-sdk/lib-dynamodb" +import { DynamoDB } from "@aws-sdk/client-dynamodb" import { AWS_REGION } from "../constants" -import { DocumentClient } from "aws-sdk/clients/dynamodb" interface DynamoDBConfig { region: string @@ -151,7 +157,7 @@ class DynamoDBIntegration implements IntegrationBase { region: config.region || AWS_REGION, endpoint: config.endpoint || undefined, } - this.client = new AWS.DynamoDB.DocumentClient(this.config) + this.client = DynamoDBDocument.from(new DynamoDB(this.config)) } async testConnection() { @@ -159,8 +165,8 @@ class DynamoDBIntegration implements IntegrationBase { connected: false, } try { - const scanRes = await new AWS.DynamoDB(this.config).listTables().promise() - response.connected = !!scanRes.$response + const scanRes = await new DynamoDB(this.config).listTables() + response.connected = !!scanRes.$metadata } catch (e: any) { response.error = e.message as string } @@ -169,13 +175,13 @@ class DynamoDBIntegration implements IntegrationBase { async create(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.put(params).promise() + return this.client.put(params) } async read(query: { table: string; json: object; index: null | string }) { @@ -184,7 +190,7 @@ class DynamoDBIntegration implements IntegrationBase { IndexName: query.index ? query.index : undefined, ...query.json, } - const response = await this.client.query(params).promise() + const response = await this.client.query(params) if (response.Items) { return response.Items } @@ -197,7 +203,7 @@ class DynamoDBIntegration implements IntegrationBase { IndexName: query.index ? query.index : undefined, ...query.json, } - const response = await this.client.scan(params).promise() + const response = await this.client.scan(params) if (response.Items) { return response.Items } @@ -208,40 +214,40 @@ class DynamoDBIntegration implements IntegrationBase { const params = { TableName: query.table, } - return new AWS.DynamoDB(this.config).describeTable(params).promise() + return new DynamoDB(this.config).describeTable(params) } async get(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.get(params).promise() + return this.client.get(params) } async update(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.update(params).promise() + return this.client.update(params) } async delete(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.delete(params).promise() + return this.client.delete(params) } } diff --git a/packages/server/src/integrations/s3.ts b/packages/server/src/integrations/s3.ts index 0b7d774048..488c22835a 100644 --- a/packages/server/src/integrations/s3.ts +++ b/packages/server/src/integrations/s3.ts @@ -7,8 +7,9 @@ import { ConnectionInfo, } from "@budibase/types" -import AWS from "aws-sdk" +import { S3 } from "@aws-sdk/client-s3" import csv from "csvtojson" +import stream from "stream" interface S3Config { region: string @@ -167,7 +168,7 @@ class S3Integration implements IntegrationBase { delete this.config.endpoint } - this.client = new AWS.S3(this.config) + this.client = new S3(this.config) } async testConnection() { @@ -175,7 +176,7 @@ class S3Integration implements IntegrationBase { connected: false, } try { - await this.client.listBuckets().promise() + await this.client.listBuckets() response.connected = true } catch (e: any) { response.error = e.message as string @@ -209,7 +210,7 @@ class S3Integration implements IntegrationBase { LocationConstraint: query.location, } } - return await this.client.createBucket(params).promise() + return await this.client.createBucket(params) } async read(query: { @@ -220,37 +221,39 @@ class S3Integration implements IntegrationBase { maxKeys: number prefix: string }) { - const response = await this.client - .listObjects({ - Bucket: query.bucket, - Delimiter: query.delimiter, - Marker: query.marker, - MaxKeys: query.maxKeys, - Prefix: query.prefix, - }) - .promise() + const response = await this.client.listObjects({ + Bucket: query.bucket, + Delimiter: query.delimiter, + Marker: query.marker, + MaxKeys: query.maxKeys, + Prefix: query.prefix, + }) return response.Contents } async readCsv(query: { bucket: string; key: string }) { - const stream = this.client - .getObject({ - Bucket: query.bucket, - Key: query.key, - }) - .createReadStream() + const response = await this.client.getObject({ + Bucket: query.bucket, + Key: query.key, + }) + + const fileStream = response.Body?.transformToWebStream() + + if (!fileStream || !(fileStream instanceof stream.Readable)) { + throw new Error("Unable to retrieve CSV - invalid stream") + } let csvError = false return new Promise((resolve, reject) => { - stream.on("error", (err: Error) => { + fileStream.on("error", (err: Error) => { reject(err) }) const response = csv() - .fromStream(stream) + .fromStream(fileStream) .on("error", () => { csvError = true }) - stream.on("finish", () => { + fileStream.on("finish", () => { resolve(response) }) }).catch(err => { @@ -263,12 +266,10 @@ class S3Integration implements IntegrationBase { } async delete(query: { bucket: string; delete: string }) { - return await this.client - .deleteObjects({ - Bucket: query.bucket, - Delete: JSON.parse(query.delete), - }) - .promise() + return await this.client.deleteObjects({ + Bucket: query.bucket, + Delete: JSON.parse(query.delete), + }) } } diff --git a/packages/server/src/integrations/utils/utils.ts b/packages/server/src/integrations/utils/utils.ts index 315a8010e8..db9148ae90 100644 --- a/packages/server/src/integrations/utils/utils.ts +++ b/packages/server/src/integrations/utils/utils.ts @@ -430,7 +430,7 @@ export async function handleFileResponse( size = details.ContentLength } } - presignedUrl = objectStore.getPresignedUrl(bucket, key) + presignedUrl = await objectStore.getPresignedUrl(bucket, key) return { data: { size, diff --git a/packages/server/src/utilities/rowProcessor/index.ts b/packages/server/src/utilities/rowProcessor/index.ts index 14b524fd95..7c01c54f13 100644 --- a/packages/server/src/utilities/rowProcessor/index.ts +++ b/packages/server/src/utilities/rowProcessor/index.ts @@ -359,9 +359,9 @@ export async function coreOutputProcessing( if (row[property] == null) { continue } - const process = (attachment: RowAttachment) => { + const process = async (attachment: RowAttachment) => { if (!attachment.url && attachment.key) { - attachment.url = objectStore.getAppFileUrl(attachment.key) + attachment.url = await objectStore.getAppFileUrl(attachment.key) } return attachment } @@ -369,11 +369,13 @@ export async function coreOutputProcessing( row[property] = JSON.parse(row[property]) } if (Array.isArray(row[property])) { - row[property].forEach((attachment: RowAttachment) => { - process(attachment) - }) + await Promise.all( + row[property].map((attachment: RowAttachment) => + process(attachment) + ) + ) } else { - process(row[property]) + await process(row[property]) } } } else if ( diff --git a/packages/worker/src/api/controllers/global/configs.ts b/packages/worker/src/api/controllers/global/configs.ts index a10fce35f6..4ee8dcbb24 100644 --- a/packages/worker/src/api/controllers/global/configs.ts +++ b/packages/worker/src/api/controllers/global/configs.ts @@ -322,27 +322,27 @@ export async function save( } } -function enrichOIDCLogos(oidcLogos: OIDCLogosConfig) { +async function enrichOIDCLogos(oidcLogos: OIDCLogosConfig) { if (!oidcLogos) { return } - oidcLogos.config = Object.keys(oidcLogos.config || {}).reduce( - (acc: any, key: string) => { - if (!key.endsWith("Etag")) { - const etag = oidcLogos.config[`${key}Etag`] - const objectStoreUrl = objectStore.getGlobalFileUrl( - oidcLogos.type, - key, - etag - ) - acc[key] = objectStoreUrl - } else { - acc[key] = oidcLogos.config[key] - } - return acc - }, - {} - ) + const newConfig: Record = {} + const keys = Object.keys(oidcLogos.config || {}) + + for (const key of keys) { + if (!key.endsWith("Etag")) { + const etag = oidcLogos.config[`${key}Etag`] + const objectStoreUrl = await objectStore.getGlobalFileUrl( + oidcLogos.type, + key, + etag + ) + newConfig[key] = objectStoreUrl + } else { + newConfig[key] = oidcLogos.config[key] + } + } + oidcLogos.config = newConfig } export async function find(ctx: UserCtx) { @@ -370,7 +370,7 @@ export async function find(ctx: UserCtx) { async function handleConfigType(type: ConfigType, config: Config) { if (type === ConfigType.OIDC_LOGOS) { - enrichOIDCLogos(config) + await enrichOIDCLogos(config) } else if (type === ConfigType.AI) { await handleAIConfig(config) } @@ -396,7 +396,7 @@ export async function publicOidc(ctx: Ctx) { const oidcCustomLogos = await configs.getOIDCLogosDoc() if (oidcCustomLogos) { - enrichOIDCLogos(oidcCustomLogos) + await enrichOIDCLogos(oidcCustomLogos) } if (!oidcConfig) { @@ -427,7 +427,7 @@ export async function publicSettings( // enrich the logo url - empty url means deleted if (config.logoUrl && config.logoUrl !== "") { - config.logoUrl = objectStore.getGlobalFileUrl( + config.logoUrl = await objectStore.getGlobalFileUrl( "settings", "logoUrl", config.logoUrlEtag @@ -437,7 +437,7 @@ export async function publicSettings( // enrich the favicon url - empty url means deleted const faviconUrl = branding.faviconUrl && branding.faviconUrl !== "" - ? objectStore.getGlobalFileUrl( + ? await objectStore.getGlobalFileUrl( "settings", "faviconUrl", branding.faviconUrlEtag @@ -522,7 +522,7 @@ export async function upload(ctx: UserCtx) { ctx.body = { message: "File has been uploaded and url stored to config.", - url: objectStore.getGlobalFileUrl(type, name, etag), + url: await objectStore.getGlobalFileUrl(type, name, etag), } } diff --git a/yarn.lock b/yarn.lock index aa409fe4a1..657a551f1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,6 +150,121 @@ "@smithy/util-utf8" "^2.0.0" tslib "^2.6.2" +"@aws-sdk/client-dynamodb@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-dynamodb/-/client-dynamodb-3.709.0.tgz#589cfab9d27f7d0d2056f72e4674315ccd98b6bc" + integrity sha512-p/GVuEgfPccFUm5lxr7EPi5gQAsUO4SDdKcIV+v/dNwtH2SXEgnFN0o1TEIJtuVY3BsQyXyR1aMjeQ81O832kw== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/client-sso-oidc" "3.709.0" + "@aws-sdk/client-sts" "3.709.0" + "@aws-sdk/core" "3.709.0" + "@aws-sdk/credential-provider-node" "3.709.0" + "@aws-sdk/middleware-endpoint-discovery" "3.709.0" + "@aws-sdk/middleware-host-header" "3.709.0" + "@aws-sdk/middleware-logger" "3.709.0" + "@aws-sdk/middleware-recursion-detection" "3.709.0" + "@aws-sdk/middleware-user-agent" "3.709.0" + "@aws-sdk/region-config-resolver" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-endpoints" "3.709.0" + "@aws-sdk/util-user-agent-browser" "3.709.0" + "@aws-sdk/util-user-agent-node" "3.709.0" + "@smithy/config-resolver" "^3.0.13" + "@smithy/core" "^2.5.5" + "@smithy/fetch-http-handler" "^4.1.2" + "@smithy/hash-node" "^3.0.11" + "@smithy/invalid-dependency" "^3.0.11" + "@smithy/middleware-content-length" "^3.0.13" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/middleware-retry" "^3.0.30" + "@smithy/middleware-serde" "^3.0.11" + "@smithy/middleware-stack" "^3.0.11" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/node-http-handler" "^3.3.2" + "@smithy/protocol-http" "^4.1.8" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/url-parser" "^3.0.11" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.30" + "@smithy/util-defaults-mode-node" "^3.0.30" + "@smithy/util-endpoints" "^2.1.7" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-retry" "^3.0.11" + "@smithy/util-utf8" "^3.0.0" + "@smithy/util-waiter" "^3.2.0" + "@types/uuid" "^9.0.1" + tslib "^2.6.2" + uuid "^9.0.1" + +"@aws-sdk/client-s3@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.709.0.tgz#ae27e18c5ced29f0d24857e4a28fb6947cdba3a4" + integrity sha512-IvC7coELoQ4YenTdULArVdL5yk6jNRVUALX1aqv9JlPdrXxb3Om6YrM9e7AlSTLxrULTsAe1ubm8i/DmcSY/Ng== + dependencies: + "@aws-crypto/sha1-browser" "5.2.0" + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/client-sso-oidc" "3.709.0" + "@aws-sdk/client-sts" "3.709.0" + "@aws-sdk/core" "3.709.0" + "@aws-sdk/credential-provider-node" "3.709.0" + "@aws-sdk/middleware-bucket-endpoint" "3.709.0" + "@aws-sdk/middleware-expect-continue" "3.709.0" + "@aws-sdk/middleware-flexible-checksums" "3.709.0" + "@aws-sdk/middleware-host-header" "3.709.0" + "@aws-sdk/middleware-location-constraint" "3.709.0" + "@aws-sdk/middleware-logger" "3.709.0" + "@aws-sdk/middleware-recursion-detection" "3.709.0" + "@aws-sdk/middleware-sdk-s3" "3.709.0" + "@aws-sdk/middleware-ssec" "3.709.0" + "@aws-sdk/middleware-user-agent" "3.709.0" + "@aws-sdk/region-config-resolver" "3.709.0" + "@aws-sdk/signature-v4-multi-region" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-endpoints" "3.709.0" + "@aws-sdk/util-user-agent-browser" "3.709.0" + "@aws-sdk/util-user-agent-node" "3.709.0" + "@aws-sdk/xml-builder" "3.709.0" + "@smithy/config-resolver" "^3.0.13" + "@smithy/core" "^2.5.5" + "@smithy/eventstream-serde-browser" "^3.0.14" + "@smithy/eventstream-serde-config-resolver" "^3.0.11" + "@smithy/eventstream-serde-node" "^3.0.13" + "@smithy/fetch-http-handler" "^4.1.2" + "@smithy/hash-blob-browser" "^3.1.10" + "@smithy/hash-node" "^3.0.11" + "@smithy/hash-stream-node" "^3.1.10" + "@smithy/invalid-dependency" "^3.0.11" + "@smithy/md5-js" "^3.0.11" + "@smithy/middleware-content-length" "^3.0.13" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/middleware-retry" "^3.0.30" + "@smithy/middleware-serde" "^3.0.11" + "@smithy/middleware-stack" "^3.0.11" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/node-http-handler" "^3.3.2" + "@smithy/protocol-http" "^4.1.8" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/url-parser" "^3.0.11" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.30" + "@smithy/util-defaults-mode-node" "^3.0.30" + "@smithy/util-endpoints" "^2.1.7" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-retry" "^3.0.11" + "@smithy/util-stream" "^3.3.2" + "@smithy/util-utf8" "^3.0.0" + "@smithy/util-waiter" "^3.2.0" + tslib "^2.6.2" + "@aws-sdk/client-s3@^3.388.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.693.0.tgz#188b621498ffaeb7b1ea5794f61e3e8d9a4bcac2" @@ -259,6 +374,51 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@aws-sdk/client-sso-oidc@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.709.0.tgz#959e4df4070f1d059d8d0cd5b9028d9a46ac7ecf" + integrity sha512-1w6egz17QQy661lNCRmZZlqIANEbD6g2VFAQIJbVwSiu7brg+GUns+mT1eLLLHAMQc1sL0Ds8/ybSK2SrgGgIA== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.709.0" + "@aws-sdk/credential-provider-node" "3.709.0" + "@aws-sdk/middleware-host-header" "3.709.0" + "@aws-sdk/middleware-logger" "3.709.0" + "@aws-sdk/middleware-recursion-detection" "3.709.0" + "@aws-sdk/middleware-user-agent" "3.709.0" + "@aws-sdk/region-config-resolver" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-endpoints" "3.709.0" + "@aws-sdk/util-user-agent-browser" "3.709.0" + "@aws-sdk/util-user-agent-node" "3.709.0" + "@smithy/config-resolver" "^3.0.13" + "@smithy/core" "^2.5.5" + "@smithy/fetch-http-handler" "^4.1.2" + "@smithy/hash-node" "^3.0.11" + "@smithy/invalid-dependency" "^3.0.11" + "@smithy/middleware-content-length" "^3.0.13" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/middleware-retry" "^3.0.30" + "@smithy/middleware-serde" "^3.0.11" + "@smithy/middleware-stack" "^3.0.11" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/node-http-handler" "^3.3.2" + "@smithy/protocol-http" "^4.1.8" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/url-parser" "^3.0.11" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.30" + "@smithy/util-defaults-mode-node" "^3.0.30" + "@smithy/util-endpoints" "^2.1.7" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-retry" "^3.0.11" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@aws-sdk/client-sso@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.693.0.tgz#9cd5e07e57013b8c7980512810d775d7b6f67e36" @@ -303,6 +463,50 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@aws-sdk/client-sso@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.709.0.tgz#b5b29161e07af6f82afd7a6e750c09b0158d19e3" + integrity sha512-Qxeo8cN0jNy6Wnbqq4wucffAGJM6sJjofoTgNtPA6cC7sPYx7aYC6OAAAo6NaMRY+WywOKdS9Wgjx2QYRxKx7w== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.709.0" + "@aws-sdk/middleware-host-header" "3.709.0" + "@aws-sdk/middleware-logger" "3.709.0" + "@aws-sdk/middleware-recursion-detection" "3.709.0" + "@aws-sdk/middleware-user-agent" "3.709.0" + "@aws-sdk/region-config-resolver" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-endpoints" "3.709.0" + "@aws-sdk/util-user-agent-browser" "3.709.0" + "@aws-sdk/util-user-agent-node" "3.709.0" + "@smithy/config-resolver" "^3.0.13" + "@smithy/core" "^2.5.5" + "@smithy/fetch-http-handler" "^4.1.2" + "@smithy/hash-node" "^3.0.11" + "@smithy/invalid-dependency" "^3.0.11" + "@smithy/middleware-content-length" "^3.0.13" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/middleware-retry" "^3.0.30" + "@smithy/middleware-serde" "^3.0.11" + "@smithy/middleware-stack" "^3.0.11" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/node-http-handler" "^3.3.2" + "@smithy/protocol-http" "^4.1.8" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/url-parser" "^3.0.11" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.30" + "@smithy/util-defaults-mode-node" "^3.0.30" + "@smithy/util-endpoints" "^2.1.7" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-retry" "^3.0.11" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@aws-sdk/client-sts@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.693.0.tgz#9e2c418f4850269635632bee4d1a31057c04bcc5" @@ -349,6 +553,52 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@aws-sdk/client-sts@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.709.0.tgz#b9ad3c9c6419d0d149b28cdd6c115cc40c4e7906" + integrity sha512-cBAvlPg6yslXNL385UUGFPw+XY+lA9BzioNdIFkMo3fEUlTShogTtiWz4LsyLHoN6LhKojssP9DSmmWKWjCZIw== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/client-sso-oidc" "3.709.0" + "@aws-sdk/core" "3.709.0" + "@aws-sdk/credential-provider-node" "3.709.0" + "@aws-sdk/middleware-host-header" "3.709.0" + "@aws-sdk/middleware-logger" "3.709.0" + "@aws-sdk/middleware-recursion-detection" "3.709.0" + "@aws-sdk/middleware-user-agent" "3.709.0" + "@aws-sdk/region-config-resolver" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-endpoints" "3.709.0" + "@aws-sdk/util-user-agent-browser" "3.709.0" + "@aws-sdk/util-user-agent-node" "3.709.0" + "@smithy/config-resolver" "^3.0.13" + "@smithy/core" "^2.5.5" + "@smithy/fetch-http-handler" "^4.1.2" + "@smithy/hash-node" "^3.0.11" + "@smithy/invalid-dependency" "^3.0.11" + "@smithy/middleware-content-length" "^3.0.13" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/middleware-retry" "^3.0.30" + "@smithy/middleware-serde" "^3.0.11" + "@smithy/middleware-stack" "^3.0.11" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/node-http-handler" "^3.3.2" + "@smithy/protocol-http" "^4.1.8" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/url-parser" "^3.0.11" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.30" + "@smithy/util-defaults-mode-node" "^3.0.30" + "@smithy/util-endpoints" "^2.1.7" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-retry" "^3.0.11" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@aws-sdk/core@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.693.0.tgz#437969dd740895a59863d737bad14646bc2e1725" @@ -366,6 +616,23 @@ fast-xml-parser "4.4.1" tslib "^2.6.2" +"@aws-sdk/core@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.709.0.tgz#d2b3d5b90f6614e3afc109ebdcaaedbb54c2d68b" + integrity sha512-7kuSpzdOTAE026j85wq/fN9UDZ70n0OHw81vFqMWwlEFtm5IQ/MRCLKcC4HkXxTdfy1PqFlmoXxWqeBa15tujw== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/core" "^2.5.5" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/property-provider" "^3.1.11" + "@smithy/protocol-http" "^4.1.8" + "@smithy/signature-v4" "^4.2.4" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/util-middleware" "^3.0.11" + fast-xml-parser "4.4.1" + tslib "^2.6.2" + "@aws-sdk/credential-provider-env@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.693.0.tgz#f97feed9809fe2800216943470015fdaaba47c4f" @@ -377,6 +644,17 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-env@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.709.0.tgz#a7f75375d8a413f9ab2bc42f743b943da6d3362d" + integrity sha512-ZMAp9LSikvHDFVa84dKpQmow6wsg956Um20cKuioPpX2GGreJFur7oduD+tRJT6FtIOHn+64YH+0MwiXLhsaIQ== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/property-provider" "^3.1.11" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/credential-provider-http@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.693.0.tgz#5caad0ac47eded1edeb63f907280580ccfaadba3" @@ -393,6 +671,22 @@ "@smithy/util-stream" "^3.3.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-http@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.709.0.tgz#a378cbcc4cf373cc277944f1e84e9952f3884f5d" + integrity sha512-lIS7XLwCOyJnLD70f+VIRr8DNV1HPQe9oN6aguYrhoczqz7vDiVZLe3lh714cJqq9rdxzFypK5DqKHmcscMEPQ== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/fetch-http-handler" "^4.1.2" + "@smithy/node-http-handler" "^3.3.2" + "@smithy/property-provider" "^3.1.11" + "@smithy/protocol-http" "^4.1.8" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/util-stream" "^3.3.2" + tslib "^2.6.2" + "@aws-sdk/credential-provider-ini@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.693.0.tgz#b4557ac1092657660a15c9bd55e17c27f79ec621" @@ -411,6 +705,24 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-ini@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.709.0.tgz#b01c68d98ce4cc48f79405234e32a9de2f943ea1" + integrity sha512-qCF8IIGcPoUp+Ib3ANhbF5gElxFd+kIrtv2/1tKdvhudMANstQbMiWV0LTH47ZZR6c3as4iSrm09NZnpEoD/pA== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/credential-provider-env" "3.709.0" + "@aws-sdk/credential-provider-http" "3.709.0" + "@aws-sdk/credential-provider-process" "3.709.0" + "@aws-sdk/credential-provider-sso" "3.709.0" + "@aws-sdk/credential-provider-web-identity" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/credential-provider-imds" "^3.2.8" + "@smithy/property-provider" "^3.1.11" + "@smithy/shared-ini-file-loader" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/credential-provider-node@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.693.0.tgz#c5ceac64a69304d5b4db3fd68473480cafddb4a9" @@ -429,6 +741,24 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-node@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.709.0.tgz#270a31aae394e6c8fe7d3fdd0b92e7c3a863b933" + integrity sha512-4HRX9KYWPSjO5O/Vg03YAsebKpvTjTvpK1n7zHYBmlLMBLxUrVsL1nNKKC5p2/7OW3RL8XR1ki3QkoV7kGRxUQ== + dependencies: + "@aws-sdk/credential-provider-env" "3.709.0" + "@aws-sdk/credential-provider-http" "3.709.0" + "@aws-sdk/credential-provider-ini" "3.709.0" + "@aws-sdk/credential-provider-process" "3.709.0" + "@aws-sdk/credential-provider-sso" "3.709.0" + "@aws-sdk/credential-provider-web-identity" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/credential-provider-imds" "^3.2.8" + "@smithy/property-provider" "^3.1.11" + "@smithy/shared-ini-file-loader" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/credential-provider-process@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.693.0.tgz#e84e945f1a148f06ff697608d5309e73347e5aa9" @@ -441,6 +771,18 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-process@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.709.0.tgz#2521f810590f0874c54cc842d3d56f455a728325" + integrity sha512-IAC+jPlGQII6jhIylHOwh3RgSobqlgL59nw2qYTURr8hMCI0Z1p5y2ee646HTVt4WeCYyzUAXfxr6YI/Vitv+Q== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/property-provider" "^3.1.11" + "@smithy/shared-ini-file-loader" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/credential-provider-sso@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.693.0.tgz#72767389f533d9d17a14af63daaafcc8368ab43a" @@ -455,6 +797,20 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-sso@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.709.0.tgz#f0cb855eed86748ff0c9afa06b3a234fb04b3206" + integrity sha512-rYdTDOxazS2GdGScelsRK5CAkktRLCCdRjlwXaxrcW57j749hEqxcF5uTv9RD6WBwInfedcSywErNZB+hylQlg== + dependencies: + "@aws-sdk/client-sso" "3.709.0" + "@aws-sdk/core" "3.709.0" + "@aws-sdk/token-providers" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/property-provider" "^3.1.11" + "@smithy/shared-ini-file-loader" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/credential-provider-web-identity@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.693.0.tgz#b6133b5ef9d3582e36e02e9c66766714ff672a11" @@ -466,6 +822,50 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/credential-provider-web-identity@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.709.0.tgz#c2b03541cb57ae4c7d6abdca98f99a6a56833ea6" + integrity sha512-2lbDfE0IQ6gma/7BB2JpkjW5G0wGe4AS0x80oybYAYYviJmUtIR3Cn2pXun6bnAWElt4wYKl4su7oC36rs5rNA== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/property-provider" "^3.1.11" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + +"@aws-sdk/endpoint-cache@3.693.0": + version "3.693.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/endpoint-cache/-/endpoint-cache-3.693.0.tgz#4b3f0bbc16dc2907e1b977e3d8ddfc7ba008fd12" + integrity sha512-/zK0ZZncBf5FbTfo8rJMcQIXXk4Ibhe5zEMiwFNivVPR2uNC0+oqfwXz7vjxwY0t6BPE3Bs4h9uFEz4xuGCY6w== + dependencies: + mnemonist "0.38.3" + tslib "^2.6.2" + +"@aws-sdk/lib-dynamodb@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.709.0.tgz#fd90b76bce67af1a3079524710f7bc19647829ad" + integrity sha512-piIyvQ1DhoUEosKmjGnMxLClUb9tv5rPPZfgh9J4MmSygsYbE9HvC3tstje0xUudVZjsmzZpNyibl/n0LA0gdQ== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/util-dynamodb" "3.709.0" + "@smithy/core" "^2.5.5" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + +"@aws-sdk/lib-storage@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/lib-storage/-/lib-storage-3.709.0.tgz#2b12e558880418c3348cbd8f1e4e7f8db424b7b7" + integrity sha512-TnP+QSsWdiaQYS5HuB3n9H947z49m6qSEv5fth4L9xinBldLepLyyF+cua3/GlagkWqpxcATISgR9pE1PB0mhQ== + dependencies: + "@smithy/abort-controller" "^3.1.9" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/smithy-client" "^3.5.0" + buffer "5.6.0" + events "3.3.0" + stream-browserify "3.0.0" + tslib "^2.6.2" + "@aws-sdk/middleware-bucket-endpoint@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.693.0.tgz#e4823a40935d34f5e58a4fbc830d8ff92e44fc99" @@ -479,6 +879,31 @@ "@smithy/util-config-provider" "^3.0.0" tslib "^2.6.2" +"@aws-sdk/middleware-bucket-endpoint@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.709.0.tgz#a69bdebfebb7b5b174d3a396f2361f5025d168f4" + integrity sha512-03+tJOd7KIZOiqWH7Z8BOfQIWkKJgjcpKOJKZ6FR2KjWGUOE1G+bo11wF4UuHQ0RmpKnApt+pQghZmSnE7WEeg== + dependencies: + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-arn-parser" "3.693.0" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + "@smithy/util-config-provider" "^3.0.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-endpoint-discovery@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.709.0.tgz#d5866603f2515f0da2c84ead99cd25b806d8ee5b" + integrity sha512-6CSHoAy3sVBJdeGiBpoRqVHpqLPqv5QuDxKsEMHoGdbGATmffyn2whTFfo5hfRYsN9WPz/XxUX2iynqQCnlrzw== + dependencies: + "@aws-sdk/endpoint-cache" "3.693.0" + "@aws-sdk/types" "3.709.0" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/middleware-expect-continue@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.693.0.tgz#d8696cee9ebea1d973d8daf872fd913b41d62cf0" @@ -489,6 +914,16 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/middleware-expect-continue@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.709.0.tgz#a7fec776da9de32e15088badfc09d69118f5d5ab" + integrity sha512-Tbl/DFvE4rHl8lMb9IzetwK4tf5R3VeHZkvEXQalsWoK0tbEQ8kXWi7wAYO4qbE7bFVvaxKX+irjJjTxf3BrCQ== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/middleware-flexible-checksums@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.693.0.tgz#80f07802d98ff33a6899a09c59cf51aab426aaac" @@ -508,6 +943,25 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@aws-sdk/middleware-flexible-checksums@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.709.0.tgz#f0fb543c2db724cb43bae215ff0aea942d06a967" + integrity sha512-wbYm9tkyCaqMeU82yjaXw7V5BxCSlSLNupENW63LC7Fvyo/aQzj6LjSMHcBpR2QwjBEhXCtF47L7aQ8SPTNhdw== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@aws-crypto/crc32c" "5.2.0" + "@aws-crypto/util" "5.2.0" + "@aws-sdk/core" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/is-array-buffer" "^3.0.0" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-stream" "^3.3.2" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@aws-sdk/middleware-host-header@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.693.0.tgz#69322909c0792df1e6be7c7fb5e2b6f76090a55c" @@ -518,6 +972,16 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/middleware-host-header@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.709.0.tgz#f44f5c62f9bd7e5a443603fed68143d2d9725219" + integrity sha512-8gQYCYAaIw4lOCd5WYdf15Y/61MgRsAnrb2eiTl+icMlUOOzl8aOl5iDwm/Idp0oHZTflwxM4XSvGXO83PRWcw== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/middleware-location-constraint@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.693.0.tgz#1856eaaad64d41d1f8fa53ced58a6c7cf5eccc6e" @@ -527,6 +991,15 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/middleware-location-constraint@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.709.0.tgz#4437d3d3cfbbdfca60664b1f237d600b94fd06a5" + integrity sha512-5YQWPXfZq7OE0jB2G0PP8K10GBod/YPJXb+1CfJS6FbQaglRoIm8KZmVEvJNnptSKyGtE62veeCcCQcfAUfFig== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/middleware-logger@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.693.0.tgz#fc10294e6963f8e5d58ba1ededd891e999f544a9" @@ -536,6 +1009,15 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/middleware-logger@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.709.0.tgz#b9a0b016b7ae09cb502cc4faf45964d4b5745824" + integrity sha512-jDoGSccXv9zebnpUoisjWd5u5ZPIalrmm6TjvPzZ8UqzQt3Beiz0tnQwmxQD6KRc7ADweWP5Ntiqzbw9xpVajg== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/middleware-recursion-detection@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.693.0.tgz#88a8157293775e7116707da26501da4b5e042f51" @@ -546,6 +1028,16 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/middleware-recursion-detection@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.709.0.tgz#d7dc253d4858d496caeb12dd6cddd87b250fb98b" + integrity sha512-PObL/wLr4lkfbQ0yXUWaoCWu/jcwfwZzCjsUiXW/H6hW9b/00enZxmx7OhtJYaR6xmh/Lcx5wbhIoDCbzdv0tw== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/middleware-sdk-s3@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.693.0.tgz#e0850854d5079f372786b2ccfe85729caa7a49d8" @@ -566,6 +1058,26 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@aws-sdk/middleware-sdk-s3@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.709.0.tgz#b6f22c77e64760869eb06255af58376f879742b2" + integrity sha512-FwtOG9t9xsLoLOQZ6qAdsWOjx9dsO6t28IjIDV1l6Ixiu2oC0Yks7goONjJUH0IDE4pDDDGzmuq0sn1XtHhheA== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-arn-parser" "3.693.0" + "@smithy/core" "^2.5.5" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/protocol-http" "^4.1.8" + "@smithy/signature-v4" "^4.2.4" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/util-config-provider" "^3.0.0" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-stream" "^3.3.2" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@aws-sdk/middleware-ssec@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.693.0.tgz#2ff779147d188090b3a6cda3ed12ca4085220a73" @@ -575,6 +1087,15 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/middleware-ssec@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.709.0.tgz#bbf5253cdce45ed2759a108fd924fff4b8e049d5" + integrity sha512-2muiLe7YkmlwZp2SKz+goZrDThGfRq3o0FcJF3Puc0XGmcEPEDjih537mCoTrGgcXNFlBc7YChd84r3t72ySaQ== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/middleware-user-agent@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.693.0.tgz#4b55cfab3fc7e671b08e1ea63a98e45a1e13e6a5" @@ -588,6 +1109,19 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/middleware-user-agent@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.709.0.tgz#2a467f14b3f4a9270bcdfde32e3d4e38701aaafe" + integrity sha512-ooc9ZJvgkjPhi9q05XwSfNTXkEBEIfL4hleo5rQBKwHG3aTHvwOM7LLzhdX56QZVa6sorPBp6fwULuRDSqiQHw== + dependencies: + "@aws-sdk/core" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-endpoints" "3.709.0" + "@smithy/core" "^2.5.5" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/node-http-handler@^3.374.0": version "3.374.0" resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.374.0.tgz#8cd58b4d9814713e26034c12eabc119c113a5bc4" @@ -608,6 +1142,32 @@ "@smithy/util-middleware" "^3.0.9" tslib "^2.6.2" +"@aws-sdk/region-config-resolver@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.709.0.tgz#64547b333842e5804e1793e4d6d29578c0b34a68" + integrity sha512-/NoCAMEVKAg3kBKOrNtgOfL+ECt6nrl+L7q2SyYmrcY4tVCmwuECVqewQaHc03fTnJijfKLccw0Fj+6wOCnB6w== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/types" "^3.7.2" + "@smithy/util-config-provider" "^3.0.0" + "@smithy/util-middleware" "^3.0.11" + tslib "^2.6.2" + +"@aws-sdk/s3-request-presigner@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.709.0.tgz#d3c9d881158bdece69863be318d49e9d7d2c512f" + integrity sha512-WYmXU2ur/z6xBX9TcGwSWlSiS8rxrRl2f1HJXZzgSu9FWZ7fJssoQGvrk/w64wjNq1tEzKbd1iWXw9s9qexT3g== + dependencies: + "@aws-sdk/signature-v4-multi-region" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@aws-sdk/util-format-url" "3.709.0" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/protocol-http" "^4.1.8" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/signature-v4-multi-region@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.693.0.tgz#85bd90bb78be1a98d5a5ca41033cb0703146c2c4" @@ -620,6 +1180,18 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/signature-v4-multi-region@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.709.0.tgz#0c6f9d3e2978158163b63a4085356616237223c9" + integrity sha512-m0vhJEy6SLbjL11K9cHzX/ZhCIj//1GkTbYk2d4tTQFSuPyJEkjmoeHk9dYm2mJy0wH48j29OJadI1JUsR5bOw== + dependencies: + "@aws-sdk/middleware-sdk-s3" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/protocol-http" "^4.1.8" + "@smithy/signature-v4" "^4.2.4" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/token-providers@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.693.0.tgz#5ce7d6aa7a3437d4abdc0dca1be47f5158d15c85" @@ -631,6 +1203,17 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/token-providers@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.709.0.tgz#56305ab187660a711fd172c329dc953ca754fa80" + integrity sha512-q5Ar6k71nci43IbULFgC8a89d/3EHpmd7HvBzqVGRcHnoPwh8eZDBfbBXKH83NGwcS1qPSRYiDbVfeWPm4/1jA== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/property-provider" "^3.1.11" + "@smithy/shared-ini-file-loader" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/types@3.692.0", "@aws-sdk/types@^3.222.0": version "3.692.0" resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.692.0.tgz#c8f6c75b6ad659865b72759796d4d92c1b72069b" @@ -639,6 +1222,14 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/types@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.709.0.tgz#f8d7ab07e253d3ed0e3b360e09fc67c7430a73b9" + integrity sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/util-arn-parser@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.693.0.tgz#8dae27eb822ab4f88be28bb3c0fc11f1f13d3948" @@ -646,6 +1237,13 @@ dependencies: tslib "^2.6.2" +"@aws-sdk/util-dynamodb@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-dynamodb/-/util-dynamodb-3.709.0.tgz#12ced0849ff8f1ac8a1921f97fdb57813f22ec14" + integrity sha512-rGr9+Po6Ma2BHV2hIhfXdn8hWxLtmgFzFRqqtxOlRRIDN55wkb2AYXz/ydzf4kgb+PzT8sQxtn6hf7pDkl+yAg== + dependencies: + tslib "^2.6.2" + "@aws-sdk/util-endpoints@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.693.0.tgz#99f56f83fc25bdc3321f5871d6354abd56768891" @@ -656,6 +1254,26 @@ "@smithy/util-endpoints" "^2.1.5" tslib "^2.6.2" +"@aws-sdk/util-endpoints@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.709.0.tgz#32dfe339d78b699ada68392bbb3bec25441bae5c" + integrity sha512-Mbc7AtL5WGCTKC16IGeUTz+sjpC3ptBda2t0CcK0kMVw3THDdcSq6ZlNKO747cNqdbwUvW34oHteUiHv4/z88Q== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/types" "^3.7.2" + "@smithy/util-endpoints" "^2.1.7" + tslib "^2.6.2" + +"@aws-sdk/util-format-url@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-format-url/-/util-format-url-3.709.0.tgz#6ac420c297cae442f6d4065214eefc0d977e1a10" + integrity sha512-HGR11hx1KeFfoub/TACf+Yyal37lR85791Di2QPaElQThaqztLlppxale3EohKboOFf7Q/zvslJyM0fmgrlpQw== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/querystring-builder" "^3.0.11" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/util-locate-window@^3.0.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz#1160f6d055cf074ca198eb8ecf89b6311537ad6c" @@ -673,6 +1291,16 @@ bowser "^2.11.0" tslib "^2.6.2" +"@aws-sdk/util-user-agent-browser@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.709.0.tgz#ad6e867bdd348923ec10ddd6c37740ce0986cd8f" + integrity sha512-/rL2GasJzdTWUURCQKFldw2wqBtY4k4kCiA2tVZSKg3y4Ey7zO34SW8ebaeCE2/xoWOyLR2/etdKyphoo4Zrtg== + dependencies: + "@aws-sdk/types" "3.709.0" + "@smithy/types" "^3.7.2" + bowser "^2.11.0" + tslib "^2.6.2" + "@aws-sdk/util-user-agent-node@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.693.0.tgz#b26c806faa2001d4fa1d515b146eeff411513dd9" @@ -684,6 +1312,17 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/util-user-agent-node@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.709.0.tgz#7ff5a508bcad49963a550acadcced43d7af9960d" + integrity sha512-trBfzSCVWy7ILgqhEXgiuM7hfRCw4F4a8IK90tjk9YL0jgoJ6eJuOp7+DfCtHJaygoBxD3cdMFkOu+lluFmGBA== + dependencies: + "@aws-sdk/middleware-user-agent" "3.709.0" + "@aws-sdk/types" "3.709.0" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@aws-sdk/xml-builder@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.693.0.tgz#709a46a3335b71144d9f7917a7cb3033b5a04e82" @@ -692,6 +1331,14 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" +"@aws-sdk/xml-builder@3.709.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.709.0.tgz#5841faa1e78afcea064557a1a56709978b325758" + integrity sha512-2GPCwlNxeHspoK/Mc8nbk9cBOkSpp3j2SJUQmFnyQK6V/pR6II2oPRyZkMomug1Rc10hqlBHByMecq4zhV2uUw== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@azure/abort-controller@^1.0.0", "@azure/abort-controller@^1.0.4": version "1.1.0" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249" @@ -2088,47 +2735,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@3.2.26": - version "0.0.0" - dependencies: - "@budibase/nano" "10.1.5" - "@budibase/pouchdb-replication-stream" "1.2.11" - "@budibase/shared-core" "*" - "@budibase/types" "*" - "@techpass/passport-openidconnect" "0.3.3" - aws-cloudfront-sign "3.0.2" - aws-sdk "2.1692.0" - bcrypt "5.1.0" - bcryptjs "2.4.3" - bull "4.10.1" - correlation-id "4.0.0" - dd-trace "5.26.0" - dotenv "16.0.1" - google-auth-library "^8.0.1" - google-spreadsheet "npm:@budibase/google-spreadsheet@4.1.5" - ioredis "5.3.2" - joi "17.6.0" - jsonwebtoken "9.0.2" - knex "2.4.2" - koa-passport "^6.0.0" - koa-pino-logger "4.0.0" - lodash "4.17.21" - node-fetch "2.6.7" - passport-google-oauth "2.0.0" - passport-local "1.0.0" - passport-oauth2-refresh "^2.1.0" - pino "8.11.0" - pino-http "8.3.3" - posthog-node "4.0.1" - pouchdb "9.0.0" - pouchdb-find "9.0.0" - redlock "4.2.0" - rotating-file-stream "3.1.0" - sanitize-s3-objectkey "0.0.1" - semver "^7.5.4" - tar-fs "2.1.1" - uuid "^8.3.2" - "@budibase/handlebars-helpers@^0.13.2": version "0.13.2" resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.13.2.tgz#73ab51c464e91fd955b429017648e0257060db77" @@ -2172,15 +2778,15 @@ through2 "^2.0.0" "@budibase/pro@npm:@budibase/pro@latest": - version "3.2.26" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.26.tgz#3525535e07827ff820eefeeb94ad9e0e818ac698" - integrity sha512-+V04NbKSBN3Up6vcyBFFpecQ3MrJvVuXN74JE9yLj+KVxQXJ1kwCrMgea/XyJomSc72PWb9sQzXADWTe5i5STA== + version "3.2.28" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.28.tgz#59b5b37225715bb8fbf5b1c5c989140b10b58710" + integrity sha512-eDPeZpYFRZYQhCulcQAUwFoPk68c8+K9mIsB6QD3oMHmHTDA1P2ZcXvLNqDTIqHB94DqnWinqDf4hTuGYApgPA== dependencies: "@anthropic-ai/sdk" "^0.27.3" - "@budibase/backend-core" "3.2.26" - "@budibase/shared-core" "3.2.26" - "@budibase/string-templates" "3.2.26" - "@budibase/types" "3.2.26" + "@budibase/backend-core" "*" + "@budibase/shared-core" "*" + "@budibase/string-templates" "*" + "@budibase/types" "*" "@koa/router" "13.1.0" bull "4.10.1" dd-trace "5.26.0" @@ -2193,25 +2799,6 @@ scim-patch "^0.8.1" scim2-parse-filter "^0.2.8" -"@budibase/shared-core@3.2.26": - version "0.0.0" - dependencies: - "@budibase/types" "*" - cron-validate "1.4.5" - -"@budibase/string-templates@3.2.26": - version "0.0.0" - dependencies: - "@budibase/handlebars-helpers" "^0.13.2" - dayjs "^1.10.8" - handlebars "^4.7.8" - lodash.clonedeep "^4.5.0" - -"@budibase/types@3.2.26": - version "0.0.0" - dependencies: - scim-patch "^0.8.1" - "@bull-board/api@5.10.2": version "5.10.2" resolved "https://registry.yarnpkg.com/@bull-board/api/-/api-5.10.2.tgz#ae8ff6918b23897bf879a6ead3683f964374c4b3" @@ -4284,6 +4871,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/abort-controller@^3.1.9": + version "3.1.9" + resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-3.1.9.tgz#47d323f754136a489e972d7fd465d534d72fcbff" + integrity sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/chunked-blob-reader-native@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-3.0.1.tgz#39045ed278ee1b6f4c12715c7565678557274c29" @@ -4310,6 +4905,17 @@ "@smithy/util-middleware" "^3.0.10" tslib "^2.6.2" +"@smithy/config-resolver@^3.0.13": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-3.0.13.tgz#653643a77a33d0f5907a5e7582353886b07ba752" + integrity sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg== + dependencies: + "@smithy/node-config-provider" "^3.1.12" + "@smithy/types" "^3.7.2" + "@smithy/util-config-provider" "^3.0.0" + "@smithy/util-middleware" "^3.0.11" + tslib "^2.6.2" + "@smithy/core@^2.5.2", "@smithy/core@^2.5.3": version "2.5.3" resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.5.3.tgz#1d5723f676b0d6ec08c515272f0ac03aa59fac72" @@ -4324,6 +4930,20 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@smithy/core@^2.5.5": + version "2.5.5" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.5.5.tgz#c75b15caee9e58c800db3e6b99e9e373532d394a" + integrity sha512-G8G/sDDhXA7o0bOvkc7bgai6POuSld/+XhNnWAbpQTpLv2OZPvyqQ58tLPPlz0bSNsXktldDDREIv1LczFeNEw== + dependencies: + "@smithy/middleware-serde" "^3.0.11" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-stream" "^3.3.2" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@smithy/credential-provider-imds@^3.2.6", "@smithy/credential-provider-imds@^3.2.7": version "3.2.7" resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.7.tgz#6eedf87ba0238723ec46d8ce0f18e276685a702d" @@ -4335,6 +4955,27 @@ "@smithy/url-parser" "^3.0.10" tslib "^2.6.2" +"@smithy/credential-provider-imds@^3.2.8": + version "3.2.8" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz#27ed2747074c86a7d627a98e56f324a65cba88de" + integrity sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw== + dependencies: + "@smithy/node-config-provider" "^3.1.12" + "@smithy/property-provider" "^3.1.11" + "@smithy/types" "^3.7.2" + "@smithy/url-parser" "^3.0.11" + tslib "^2.6.2" + +"@smithy/eventstream-codec@^3.1.10": + version "3.1.10" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-3.1.10.tgz#0c1a3457e7a23b71cd71525ceb668f8569a84dad" + integrity sha512-323B8YckSbUH0nMIpXn7HZsAVKHYHFUODa8gG9cHo0ySvA1fr5iWaNT+iIL0UCqUzG6QPHA3BSsBtRQou4mMqQ== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@smithy/types" "^3.7.2" + "@smithy/util-hex-encoding" "^3.0.0" + tslib "^2.6.2" + "@smithy/eventstream-codec@^3.1.9": version "3.1.9" resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-3.1.9.tgz#4271354e75e57d30771fca307da403896c657430" @@ -4354,6 +4995,23 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/eventstream-serde-browser@^3.0.14": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.14.tgz#0c3584c7cde2e210aacdfbbd2b57c1d7e2ca3b95" + integrity sha512-kbrt0vjOIihW3V7Cqj1SXQvAI5BR8SnyQYsandva0AOR307cXAc+IhPngxIPslxTLfxwDpNu0HzCAq6g42kCPg== + dependencies: + "@smithy/eventstream-serde-universal" "^3.0.13" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + +"@smithy/eventstream-serde-config-resolver@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.11.tgz#5edceba836debea165ea93145231036f6286d67c" + integrity sha512-P2pnEp4n75O+QHjyO7cbw/vsw5l93K/8EWyjNCAAybYwUmj3M+hjSQZ9P5TVdUgEG08ueMAP5R4FkuSkElZ5tQ== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/eventstream-serde-config-resolver@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.10.tgz#5c0b2ae0bb8e11cfa77851098e46f7350047ec8d" @@ -4371,6 +5029,15 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/eventstream-serde-node@^3.0.13": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.13.tgz#5aebd7b553becee277e411a2b69f6af8c9d7b3a6" + integrity sha512-zqy/9iwbj8Wysmvi7Lq7XFLeDgjRpTbCfwBhJa8WbrylTAHiAu6oQTwdY7iu2lxigbc9YYr9vPv5SzYny5tCXQ== + dependencies: + "@smithy/eventstream-serde-universal" "^3.0.13" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/eventstream-serde-universal@^3.0.12": version "3.0.12" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.12.tgz#803d7beb29a3de4a64e91af97331a4654741c35f" @@ -4380,6 +5047,15 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/eventstream-serde-universal@^3.0.13": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.13.tgz#609c922ea14a0a3eed23a28ac110344c935704eb" + integrity sha512-L1Ib66+gg9uTnqp/18Gz4MDpJPKRE44geOjOQ2SVc0eiaO5l255ADziATZgjQjqumC7yPtp1XnjHlF1srcwjKw== + dependencies: + "@smithy/eventstream-codec" "^3.1.10" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/fetch-http-handler@^4.1.0", "@smithy/fetch-http-handler@^4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.1.tgz#cead80762af4cdea11e7eeb627ea1c4835265dfa" @@ -4391,6 +5067,27 @@ "@smithy/util-base64" "^3.0.0" tslib "^2.6.2" +"@smithy/fetch-http-handler@^4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.2.tgz#f034ff16416b37d92908a1381ef5fddbf4ef1879" + integrity sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA== + dependencies: + "@smithy/protocol-http" "^4.1.8" + "@smithy/querystring-builder" "^3.0.11" + "@smithy/types" "^3.7.2" + "@smithy/util-base64" "^3.0.0" + tslib "^2.6.2" + +"@smithy/hash-blob-browser@^3.1.10": + version "3.1.10" + resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.10.tgz#985e308189c2687a15004152b97506882ffb2b13" + integrity sha512-elwslXOoNunmfS0fh55jHggyhccobFkexLYC1ZeZ1xP2BTSrcIBaHV2b4xUQOdctrSNOpMqOZH1r2XzWTEhyfA== + dependencies: + "@smithy/chunked-blob-reader" "^4.0.0" + "@smithy/chunked-blob-reader-native" "^3.0.1" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/hash-blob-browser@^3.1.8": version "3.1.9" resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.9.tgz#1f2c3ef6afbb0ce3e58a0129753850bb9267aae8" @@ -4401,6 +5098,16 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/hash-node@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-3.0.11.tgz#99e09ead3fc99c8cd7ca0f254ea0e35714f2a0d3" + integrity sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA== + dependencies: + "@smithy/types" "^3.7.2" + "@smithy/util-buffer-from" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@smithy/hash-node@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-3.0.10.tgz#93c857b4bff3a48884886440fd9772924887e592" @@ -4411,6 +5118,15 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@smithy/hash-stream-node@^3.1.10": + version "3.1.10" + resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-3.1.10.tgz#94716b4556f4ccf2807e605f47bb5b018ed7dfb0" + integrity sha512-olomK/jZQ93OMayW1zfTHwcbwBdhcZOHsyWyiZ9h9IXvc1mCD/VuvzbLb3Gy/qNJwI4MANPLctTp2BucV2oU/Q== + dependencies: + "@smithy/types" "^3.7.2" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@smithy/hash-stream-node@^3.1.8": version "3.1.9" resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-3.1.9.tgz#97eb416811b7e7b9d036f0271588151b619759e9" @@ -4420,6 +5136,14 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@smithy/invalid-dependency@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz#8144d7b0af9d34ab5f672e1f674f97f8740bb9ae" + integrity sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/invalid-dependency@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-3.0.10.tgz#8616dee555916c24dec3e33b1e046c525efbfee3" @@ -4442,6 +5166,15 @@ dependencies: tslib "^2.6.2" +"@smithy/md5-js@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-3.0.11.tgz#27e4dab616348ff94aed24dc75e4017c582df40f" + integrity sha512-3NM0L3i2Zm4bbgG6Ymi9NBcxXhryi3uE8fIfHJZIOfZVxOkGdjdgjR9A06SFIZCfnEIWKXZdm6Yq5/aPXFFhsQ== + dependencies: + "@smithy/types" "^3.7.2" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@smithy/md5-js@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-3.0.10.tgz#52ab927cf03cd1d24fed82d8ba936faf5632436e" @@ -4460,6 +5193,15 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/middleware-content-length@^3.0.13": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz#6e08fe52739ac8fb3996088e0f8837e4b2ea187f" + integrity sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw== + dependencies: + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/middleware-endpoint@^3.2.2", "@smithy/middleware-endpoint@^3.2.3": version "3.2.3" resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.3.tgz#7dd3df0052fc55891522631a7751e613b6efd68a" @@ -4474,6 +5216,20 @@ "@smithy/util-middleware" "^3.0.10" tslib "^2.6.2" +"@smithy/middleware-endpoint@^3.2.5": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.5.tgz#bdcfdf1f342cf933b0b8a709996f9a8fbb8148f4" + integrity sha512-VhJNs/s/lyx4weiZdXSloBgoLoS8osV0dKIain8nGmx7of3QFKu5BSdEuk1z/U8x9iwes1i+XCiNusEvuK1ijg== + dependencies: + "@smithy/core" "^2.5.5" + "@smithy/middleware-serde" "^3.0.11" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/shared-ini-file-loader" "^3.1.12" + "@smithy/types" "^3.7.2" + "@smithy/url-parser" "^3.0.11" + "@smithy/util-middleware" "^3.0.11" + tslib "^2.6.2" + "@smithy/middleware-retry@^3.0.26": version "3.0.27" resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.27.tgz#2e4dda420178835cd2d416479505d313b601ba21" @@ -4489,6 +5245,21 @@ tslib "^2.6.2" uuid "^9.0.1" +"@smithy/middleware-retry@^3.0.30": + version "3.0.30" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.30.tgz#2580322d0d28ad782b5b8c07c150b14efdc3b2f9" + integrity sha512-6323RL2BvAR3VQpTjHpa52kH/iSHyxd/G9ohb2MkBk2Ucu+oMtRXT8yi7KTSIS9nb58aupG6nO0OlXnQOAcvmQ== + dependencies: + "@smithy/node-config-provider" "^3.1.12" + "@smithy/protocol-http" "^4.1.8" + "@smithy/service-error-classification" "^3.0.11" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-retry" "^3.0.11" + tslib "^2.6.2" + uuid "^9.0.1" + "@smithy/middleware-serde@^3.0.10", "@smithy/middleware-serde@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-3.0.10.tgz#5f6c0b57b10089a21d355bd95e9b7d40378454d7" @@ -4497,6 +5268,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/middleware-serde@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz#c7d54e0add4f83e05c6878a011fc664e21022f12" + integrity sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/middleware-stack@^3.0.10", "@smithy/middleware-stack@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-3.0.10.tgz#73e2fde5d151440844161773a17ee13375502baf" @@ -4505,6 +5284,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/middleware-stack@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz#453af2096924e4064d9da4e053cfdf65d9a36acc" + integrity sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/node-config-provider@^3.1.10", "@smithy/node-config-provider@^3.1.11": version "3.1.11" resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-3.1.11.tgz#95feba85a5cb3de3fe9adfff1060b35fd556d023" @@ -4515,6 +5302,16 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/node-config-provider@^3.1.12": + version "3.1.12" + resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz#1b1d674fc83f943dc7b3017e37f16f374e878a6c" + integrity sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ== + dependencies: + "@smithy/property-provider" "^3.1.11" + "@smithy/shared-ini-file-loader" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/node-http-handler@^1.0.2": version "1.1.0" resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-1.1.0.tgz#887cee930b520e08043c9f41e463f8d8f5dae127" @@ -4537,6 +5334,17 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/node-http-handler@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-3.3.2.tgz#b34685863b74dabdaf7860aa81b42d0d5437c7e0" + integrity sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA== + dependencies: + "@smithy/abort-controller" "^3.1.9" + "@smithy/protocol-http" "^4.1.8" + "@smithy/querystring-builder" "^3.0.11" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/property-provider@^3.1.10", "@smithy/property-provider@^3.1.9": version "3.1.10" resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-3.1.10.tgz#ae00447c1060c194c3e1b9475f7c8548a70f8486" @@ -4545,6 +5353,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/property-provider@^3.1.11": + version "3.1.11" + resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-3.1.11.tgz#161cf1c2a2ada361e417382c57f5ba6fbca8acad" + integrity sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/protocol-http@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-1.2.0.tgz#a554e4dabb14508f0bc2cdef9c3710e2b294be04" @@ -4561,6 +5377,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/protocol-http@^4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-4.1.8.tgz#0461758671335f65e8ff3fc0885ab7ed253819c9" + integrity sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/querystring-builder@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-1.1.0.tgz#de6306104640ade34e59be33949db6cc64aa9d7f" @@ -4579,6 +5403,15 @@ "@smithy/util-uri-escape" "^3.0.0" tslib "^2.6.2" +"@smithy/querystring-builder@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz#2ed04adbe725671824c5613d0d6f9376d791a909" + integrity sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg== + dependencies: + "@smithy/types" "^3.7.2" + "@smithy/util-uri-escape" "^3.0.0" + tslib "^2.6.2" + "@smithy/querystring-parser@^3.0.10": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-3.0.10.tgz#62db744a1ed2cf90f4c08d2c73d365e033b4a11c" @@ -4587,6 +5420,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/querystring-parser@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz#9d3177ea19ce8462f18d9712b395239e1ca1f969" + integrity sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/service-error-classification@^3.0.10": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-3.0.10.tgz#941c549daf0e9abb84d3def1d9e1e3f0f74f5ba6" @@ -4594,6 +5435,13 @@ dependencies: "@smithy/types" "^3.7.1" +"@smithy/service-error-classification@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz#d3d7fc0aacd2e60d022507367e55c7939e5bcb8a" + integrity sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog== + dependencies: + "@smithy/types" "^3.7.2" + "@smithy/shared-ini-file-loader@^3.1.10", "@smithy/shared-ini-file-loader@^3.1.11": version "3.1.11" resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.11.tgz#0b4f98c4a66480956fbbefc4627c5dc09d891aea" @@ -4602,6 +5450,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/shared-ini-file-loader@^3.1.12": + version "3.1.12" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz#d98b1b663eb18935ce2cbc79024631d34f54042a" + integrity sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/signature-v4@^4.2.2": version "4.2.3" resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-4.2.3.tgz#abbca5e5fe9158422b3125b2956791a325a27f22" @@ -4616,6 +5472,20 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@smithy/signature-v4@^4.2.4": + version "4.2.4" + resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-4.2.4.tgz#3501d3d09fd82768867bfc00a7be4bad62f62f4d" + integrity sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA== + dependencies: + "@smithy/is-array-buffer" "^3.0.0" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + "@smithy/util-hex-encoding" "^3.0.0" + "@smithy/util-middleware" "^3.0.11" + "@smithy/util-uri-escape" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@smithy/smithy-client@^3.4.3", "@smithy/smithy-client@^3.4.4": version "3.4.4" resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.4.4.tgz#460870dc97d945fa2f390890359cf09d01131e0f" @@ -4629,6 +5499,19 @@ "@smithy/util-stream" "^3.3.1" tslib "^2.6.2" +"@smithy/smithy-client@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.5.0.tgz#65cff262801b009998c1196764ee69929ee06f8a" + integrity sha512-Y8FeOa7gbDfCWf7njrkoRATPa5eNLUEjlJS5z5rXatYuGkCb80LbHcu8AQR8qgAZZaNHCLyo2N+pxPsV7l+ivg== + dependencies: + "@smithy/core" "^2.5.5" + "@smithy/middleware-endpoint" "^3.2.5" + "@smithy/middleware-stack" "^3.0.11" + "@smithy/protocol-http" "^4.1.8" + "@smithy/types" "^3.7.2" + "@smithy/util-stream" "^3.3.2" + tslib "^2.6.2" + "@smithy/types@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@smithy/types/-/types-1.2.0.tgz#9dc65767b0ee3d6681704fcc67665d6fc9b6a34e" @@ -4643,6 +5526,13 @@ dependencies: tslib "^2.6.2" +"@smithy/types@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-3.7.2.tgz#05cb14840ada6f966de1bf9a9c7dd86027343e10" + integrity sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg== + dependencies: + tslib "^2.6.2" + "@smithy/url-parser@^3.0.10", "@smithy/url-parser@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-3.0.10.tgz#f389985a79766cff4a99af14979f01a17ce318da" @@ -4652,6 +5542,15 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/url-parser@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-3.0.11.tgz#e5f5ffabfb6230159167cf4cc970705fca6b8b2d" + integrity sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw== + dependencies: + "@smithy/querystring-parser" "^3.0.11" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/util-base64@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-3.0.0.tgz#f7a9a82adf34e27a72d0719395713edf0e493017" @@ -4709,6 +5608,17 @@ bowser "^2.11.0" tslib "^2.6.2" +"@smithy/util-defaults-mode-browser@^3.0.30": + version "3.0.30" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.30.tgz#6c0d95af3f15bef8f1fe3f6217cc4f5ba8df5554" + integrity sha512-nLuGmgfcr0gzm64pqF2UT4SGWVG8UGviAdayDlVzJPNa6Z4lqvpDzdRXmLxtOdEjVlTOEdpZ9dd3ZMMu488mzg== + dependencies: + "@smithy/property-provider" "^3.1.11" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + bowser "^2.11.0" + tslib "^2.6.2" + "@smithy/util-defaults-mode-node@^3.0.26": version "3.0.27" resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.27.tgz#a7248c9d9cb620827ab57ef9d1867bfe8aef42d0" @@ -4722,6 +5632,19 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/util-defaults-mode-node@^3.0.30": + version "3.0.30" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.30.tgz#33cdb02f90944b9ff221e2f8e0904a63ac1e335f" + integrity sha512-OD63eWoH68vp75mYcfYyuVH+p7Li/mY4sYOROnauDrtObo1cS4uWfsy/zhOTW8F8ZPxQC1ZXZKVxoxvMGUv2Ow== + dependencies: + "@smithy/config-resolver" "^3.0.13" + "@smithy/credential-provider-imds" "^3.2.8" + "@smithy/node-config-provider" "^3.1.12" + "@smithy/property-provider" "^3.1.11" + "@smithy/smithy-client" "^3.5.0" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/util-endpoints@^2.1.5": version "2.1.6" resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-2.1.6.tgz#720cbd1a616ad7c099b77780f0cb0f1f9fc5d2df" @@ -4731,6 +5654,15 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/util-endpoints@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz#a088ebfab946a7219dd4763bfced82709894b82d" + integrity sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw== + dependencies: + "@smithy/node-config-provider" "^3.1.12" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/util-hex-encoding@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz#32938b33d5bf2a15796cd3f178a55b4155c535e6" @@ -4746,6 +5678,14 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/util-middleware@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-3.0.11.tgz#2ab5c17266b42c225e62befcffb048afa682b5bf" + integrity sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/util-retry@^3.0.10", "@smithy/util-retry@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-3.0.10.tgz#fc13e1b30e87af0cbecadf29ca83b171e2040440" @@ -4755,6 +5695,15 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/util-retry@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-3.0.11.tgz#d267e5ccb290165cee69732547fea17b695a7425" + integrity sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ== + dependencies: + "@smithy/service-error-classification" "^3.0.11" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@smithy/util-stream@^3.3.0", "@smithy/util-stream@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-3.3.1.tgz#a2636f435637ef90d64df2bb8e71cd63236be112" @@ -4769,6 +5718,20 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@smithy/util-stream@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-3.3.2.tgz#daeea26397e8541cf2499ce65bf0b8d528cba421" + integrity sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg== + dependencies: + "@smithy/fetch-http-handler" "^4.1.2" + "@smithy/node-http-handler" "^3.3.2" + "@smithy/types" "^3.7.2" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-buffer-from" "^3.0.0" + "@smithy/util-hex-encoding" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@smithy/util-uri-escape@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-1.1.0.tgz#a8c5edaf19c0efdb9b51661e840549cf600a1808" @@ -4808,6 +5771,15 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" +"@smithy/util-waiter@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-3.2.0.tgz#1e52f870e77d2e5572025f7606053e6ff00df93d" + integrity sha512-PpjSboaDUE6yl+1qlg3Si57++e84oXdWGbuFUSAciXsVfEZJJJupR2Nb0QuXHiunt2vGR+1PTizOMvnUPaG2Qg== + dependencies: + "@smithy/abort-controller" "^3.1.9" + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + "@socket.io/component-emitter@~3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" @@ -6112,6 +7084,11 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== +"@types/uuid@^9.0.1": + version "9.0.8" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" + integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== + "@types/webidl-conversions@*": version "7.0.0" resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7" @@ -7520,6 +8497,14 @@ buffer@4.9.2: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" + integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + buffer@6.0.3, buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -10228,7 +11213,7 @@ events@1.1.1: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== -events@^3.0.0, events@^3.3.0: +events@3.3.0, events@^3.0.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -11984,7 +12969,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -14808,6 +15793,13 @@ mlly@^1.1.0, mlly@^1.7.1: pkg-types "^1.1.1" ufo "^1.5.3" +mnemonist@0.38.3: + version "0.38.3" + resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.3.tgz#35ec79c1c1f4357cfda2fe264659c2775ccd7d9d" + integrity sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw== + dependencies: + obliterator "^1.6.1" + modify-values@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -15600,6 +16592,11 @@ object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" +obliterator@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3" + integrity sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig== + omggif@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" @@ -18645,6 +19642,14 @@ stoppable@^1.1.0: resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== +stream-browserify@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + stream-events@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" From 544efaed6ea222719dfd9cd5b5282aca6b836d20 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 12 Dec 2024 18:25:49 +0000 Subject: [PATCH 002/173] Finishing off async code changes from pre-signing changes. --- .../objectStore/buckets/tests/plugins.spec.ts | 28 +++++++++---------- packages/server/src/sdk/plugins/plugins.ts | 2 +- .../server/src/utilities/fileSystem/app.ts | 2 +- .../server/src/utilities/fileSystem/plugin.ts | 7 ++++- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts index fc2822314e..0906ea91c2 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts @@ -6,8 +6,8 @@ describe("plugins", () => { describe("enrichPluginURLs", () => { const plugin = structures.plugins.plugin() - function getEnrichedPluginUrls() { - const enriched = plugins.enrichPluginURLs([plugin])[0] + async function getEnrichedPluginUrls() { + const enriched = (await plugins.enrichPluginURLs([plugin]))[0] return { jsUrl: enriched.jsUrl!, iconUrl: enriched.iconUrl!, @@ -19,9 +19,9 @@ describe("plugins", () => { testEnv.singleTenant() }) - it("gets url with embedded minio", () => { + it("gets url with embedded minio", async () => { testEnv.withMinio() - const urls = getEnrichedPluginUrls() + const urls = await getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `/files/signed/plugins/${plugin.name}/plugin.min.js` ) @@ -30,9 +30,9 @@ describe("plugins", () => { ) }) - it("gets url with custom S3", () => { + it("gets url with custom S3", async () => { testEnv.withS3() - const urls = getEnrichedPluginUrls() + const urls = await getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `http://s3.example.com/plugins/${plugin.name}/plugin.min.js` ) @@ -41,9 +41,9 @@ describe("plugins", () => { ) }) - it("gets url with cloudfront + s3", () => { + it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - const urls = getEnrichedPluginUrls() + const urls = await getEnrichedPluginUrls() // omit rest of signed params expect( urls.jsUrl.includes( @@ -65,8 +65,8 @@ describe("plugins", () => { it("gets url with embedded minio", async () => { testEnv.withMinio() - await testEnv.withTenant(tenantId => { - const urls = getEnrichedPluginUrls() + await testEnv.withTenant(async tenantId => { + const urls = await getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `/files/signed/plugins/${tenantId}/${plugin.name}/plugin.min.js` ) @@ -78,8 +78,8 @@ describe("plugins", () => { it("gets url with custom S3", async () => { testEnv.withS3() - await testEnv.withTenant(tenantId => { - const urls = getEnrichedPluginUrls() + await testEnv.withTenant(async tenantId => { + const urls = await getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `http://s3.example.com/plugins/${tenantId}/${plugin.name}/plugin.min.js` ) @@ -91,8 +91,8 @@ describe("plugins", () => { it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - await testEnv.withTenant(tenantId => { - const urls = getEnrichedPluginUrls() + await testEnv.withTenant(async tenantId => { + const urls = await getEnrichedPluginUrls() // omit rest of signed params expect( urls.jsUrl.includes( diff --git a/packages/server/src/sdk/plugins/plugins.ts b/packages/server/src/sdk/plugins/plugins.ts index 63f2f22cd9..bff24dcef7 100644 --- a/packages/server/src/sdk/plugins/plugins.ts +++ b/packages/server/src/sdk/plugins/plugins.ts @@ -18,7 +18,7 @@ export async function fetch(type?: PluginType): Promise { }) ) let plugins = response.rows.map((row: any) => row.doc) as Plugin[] - plugins = objectStore.enrichPluginURLs(plugins) + plugins = await objectStore.enrichPluginURLs(plugins) if (type) { return plugins.filter((plugin: Plugin) => plugin.schema?.type === type) } else { diff --git a/packages/server/src/utilities/fileSystem/app.ts b/packages/server/src/utilities/fileSystem/app.ts index 9bd88ba0b1..642017d2da 100644 --- a/packages/server/src/utilities/fileSystem/app.ts +++ b/packages/server/src/utilities/fileSystem/app.ts @@ -78,7 +78,7 @@ export const getComponentLibraryManifest = async (library: string) => { resp = await objectStore.retrieve(ObjectStoreBuckets.APPS, path) } if (typeof resp !== "string") { - resp = resp.toString("utf8") + resp = resp.toString() } return JSON.parse(resp) } diff --git a/packages/server/src/utilities/fileSystem/plugin.ts b/packages/server/src/utilities/fileSystem/plugin.ts index 3e1e9bef4d..2949daef61 100644 --- a/packages/server/src/utilities/fileSystem/plugin.ts +++ b/packages/server/src/utilities/fileSystem/plugin.ts @@ -3,6 +3,7 @@ import { budibaseTempDir } from "../budibaseDir" import fs from "fs" import { join } from "path" import { objectStore } from "@budibase/backend-core" +import stream from "stream" const DATASOURCE_PATH = join(budibaseTempDir(), "datasource") const AUTOMATION_PATH = join(budibaseTempDir(), "automation") @@ -58,7 +59,11 @@ async function getPluginImpl(path: string, plugin: Plugin) { pluginKey ) - fs.writeFileSync(filename, pluginJs) + if (pluginJs instanceof stream.Readable) { + pluginJs.pipe(fs.createWriteStream(filename)) + } else { + fs.writeFileSync(filename, pluginJs) + } fs.writeFileSync(metadataName, hash) return require(filename) From 49dca3b7c96d248d534700811a16f45d61afd39b Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 19 Dec 2024 13:19:25 +0000 Subject: [PATCH 003/173] Some fixes for failing test cases. --- packages/backend-core/src/environment.ts | 2 +- packages/backend-core/src/objectStore/objectStore.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 954fdd4135..9a46758062 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -154,7 +154,7 @@ const environment = { MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, AWS_SESSION_TOKEN: process.env.AWS_SESSION_TOKEN, - AWS_REGION: process.env.AWS_REGION, + AWS_REGION: process.env.AWS_REGION || "eu-west-1", MINIO_URL: process.env.MINIO_URL, MINIO_ENABLED: process.env.MINIO_ENABLED || 1, INTERNAL_API_KEY: process.env.INTERNAL_API_KEY, diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index 6acf2e21ae..513ad03bb5 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -119,7 +119,7 @@ export function ObjectStore( // Normally a signed url will need to be generated with a specified host in mind. // To support dynamic hosts, e.g. some unknown self-hosted installation url, // use a predefined host. The host 'minio-service' is also forwarded to minio requests via nginx - config.endpoint = "minio-service" + config.endpoint = "http://minio-service" } else { config.endpoint = env.MINIO_URL } From 0f659635c75e55c2571bd80309b06f592c2dc460 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 19 Dec 2024 14:02:24 +0000 Subject: [PATCH 004/173] Fixing mocked test case. --- .../src/api/routes/tests/static.spec.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/routes/tests/static.spec.ts b/packages/server/src/api/routes/tests/static.spec.ts index c2808603e9..872085c382 100644 --- a/packages/server/src/api/routes/tests/static.spec.ts +++ b/packages/server/src/api/routes/tests/static.spec.ts @@ -1,12 +1,10 @@ // Directly mock the AWS SDK -jest.mock("aws-sdk", () => ({ - S3: jest.fn(() => ({ - getSignedUrl: jest.fn( - (operation, params) => `http://example.com/${params.Bucket}/${params.Key}` - ), - upload: jest.fn(() => ({ Contents: {} })), - })), +jest.mock("@aws-sdk/s3-request-presigner", () => ({ + getSignedUrl: jest.fn(() => { + return `http://example.com` + }), })) +jest.mock("@aws-sdk/client-s3") import { Datasource, SourceName } from "@budibase/types" import { setEnv } from "../../../environment" @@ -77,7 +75,10 @@ describe("/static", () => { type: "datasource", name: "Test", source: SourceName.S3, - config: {}, + config: { + accessKeyId: "bb", + secretAccessKey: "bb", + }, }, }) }) @@ -91,7 +92,7 @@ describe("/static", () => { .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) - expect(res.body.signedUrl).toEqual("http://example.com/foo/bar") + expect(res.body.signedUrl).toEqual("http://example.com") expect(res.body.publicUrl).toEqual( `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}` ) From bb5361135cd5d7692a03faa1ea7dd68195bbdaff Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 19 Dec 2024 14:41:31 +0000 Subject: [PATCH 005/173] Fixing more test that rely on mocks. --- .../src/integrations/tests/aws-sdk.mock.ts | 76 ------------------- .../src/integrations/tests/dynamodb.spec.ts | 24 ++++-- .../server/src/integrations/tests/s3.spec.ts | 49 +++++++++++- 3 files changed, 66 insertions(+), 83 deletions(-) delete mode 100644 packages/server/src/integrations/tests/aws-sdk.mock.ts diff --git a/packages/server/src/integrations/tests/aws-sdk.mock.ts b/packages/server/src/integrations/tests/aws-sdk.mock.ts deleted file mode 100644 index 0422adfd3c..0000000000 --- a/packages/server/src/integrations/tests/aws-sdk.mock.ts +++ /dev/null @@ -1,76 +0,0 @@ -const response = (body: any, extra?: any) => () => ({ - promise: () => body, - ...extra, -}) - -class DocumentClient { - put = jest.fn(response({})) - query = jest.fn( - response({ - Items: [], - }) - ) - scan = jest.fn( - response({ - Items: [ - { - Name: "test", - }, - ], - }) - ) - get = jest.fn(response({})) - update = jest.fn(response({})) - delete = jest.fn(response({})) -} - -class S3 { - listObjects = jest.fn( - response({ - Contents: [], - }) - ) - createBucket = jest.fn( - response({ - Contents: {}, - }) - ) - deleteObjects = jest.fn( - response({ - Contents: {}, - }) - ) - getSignedUrl = jest.fn((operation, params) => { - return `http://example.com/${params.Bucket}/${params.Key}` - }) - headBucket = jest.fn( - response({ - Contents: {}, - }) - ) - upload = jest.fn( - response({ - Contents: {}, - }) - ) - getObject = jest.fn( - response( - { - Body: "", - }, - { - createReadStream: jest.fn().mockReturnValue("stream"), - } - ) - ) -} - -module.exports = { - DynamoDB: { - DocumentClient, - }, - S3, - config: { - update: jest.fn(), - }, -} diff --git a/packages/server/src/integrations/tests/dynamodb.spec.ts b/packages/server/src/integrations/tests/dynamodb.spec.ts index c992bc8bfd..75fb84ae60 100644 --- a/packages/server/src/integrations/tests/dynamodb.spec.ts +++ b/packages/server/src/integrations/tests/dynamodb.spec.ts @@ -1,4 +1,20 @@ -jest.mock("aws-sdk", () => require("./aws-sdk.mock")) +jest.mock("@aws-sdk/lib-dynamodb", () => ({ + DynamoDBDocument: { + from: jest.fn(() => ({ + update: jest.fn(), + put: jest.fn(), + query: jest.fn(() => ({ + Items: [], + })), + scan: jest.fn(() => ({ + Items: [], + })), + delete: jest.fn(), + get: jest.fn(), + })), + }, +})) +jest.mock("@aws-sdk/client-dynamodb") import { default as DynamoDBIntegration } from "../dynamodb" class TestConfiguration { @@ -57,11 +73,7 @@ describe("DynamoDB Integration", () => { TableName: tableName, IndexName: indexName, }) - expect(response).toEqual([ - { - Name: "test", - }, - ]) + expect(response).toEqual([]) }) it("calls the get method with the correct params", async () => { diff --git a/packages/server/src/integrations/tests/s3.spec.ts b/packages/server/src/integrations/tests/s3.spec.ts index abe8fb9cf1..678f15bf17 100644 --- a/packages/server/src/integrations/tests/s3.spec.ts +++ b/packages/server/src/integrations/tests/s3.spec.ts @@ -1,5 +1,52 @@ -jest.mock("aws-sdk", () => require("./aws-sdk.mock")) import { default as S3Integration } from "../s3" +jest.mock("@aws-sdk/client-s3", () => { + class S3Mock { + response(body: any, extra?: any) { + return () => ({ + promise: () => body, + ...extra, + }) + } + + listObjects = jest.fn( + this.response({ + Contents: [], + }) + ) + createBucket = jest.fn( + this.response({ + Contents: {}, + }) + ) + deleteObjects = jest.fn( + this.response({ + Contents: {}, + }) + ) + headBucket = jest.fn( + this.response({ + Contents: {}, + }) + ) + upload = jest.fn( + this.response({ + Contents: {}, + }) + ) + getObject = jest.fn( + this.response( + { + Body: "", + }, + { + createReadStream: jest.fn().mockReturnValue("stream"), + } + ) + ) + } + + return { S3: S3Mock } +}) class TestConfiguration { integration: any From cd2286e8cb55c19fe2112e05c6e2b895d1325497 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 19 Dec 2024 14:49:57 +0000 Subject: [PATCH 006/173] removing some extra .promise calls. --- .../src/objectStore/objectStore.ts | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index 513ad03bb5..adc974a131 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -138,30 +138,25 @@ export async function createBucketIfNotExists( ): Promise<{ created: boolean; exists: boolean }> { bucketName = sanitizeBucket(bucketName) try { - await // The `.promise()` call might be on an JS SDK v2 client API. - // If yes, please remove .promise(). If not, remove this comment. - client - .headBucket({ - Bucket: bucketName, - }) - .promise() + await client.headBucket({ + Bucket: bucketName, + }) return { created: false, exists: true } } catch (err: any) { - const promises: any = STATE.bucketCreationPromises - const doesntExist = err.statusCode === 404, - noAccess = err.statusCode === 403 + const statusCode = err.statusCode || err.$response?.statusCode + const promises: Record | undefined> = + STATE.bucketCreationPromises + const doesntExist = statusCode === 404, + noAccess = statusCode === 403 if (promises[bucketName]) { await promises[bucketName] return { created: false, exists: true } } else if (doesntExist || noAccess) { if (doesntExist) { - promises[bucketName] = // The `.promise()` call might be on an JS SDK v2 client API. - // If yes, please remove .promise(). If not, remove this comment. - client - .createBucket({ - Bucket: bucketName, - }) - .promise() + promises[bucketName] = client.createBucket({ + Bucket: bucketName, + }) + await promises[bucketName] delete promises[bucketName] return { created: true, exists: false } @@ -474,10 +469,7 @@ export async function deleteFolder( Prefix: folder, } - const existingObjectsResponse = - await // The `.promise()` call might be on an JS SDK v2 client API. - // If yes, please remove .promise(). If not, remove this comment. - client.listObjects(listParams) + const existingObjectsResponse = await client.listObjects(listParams) if (existingObjectsResponse.Contents?.length === 0) { return } From 5b4f71ca08fa4090bac2952f4edc769eb33d91b7 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 19 Dec 2024 15:13:19 +0000 Subject: [PATCH 007/173] Fixing mocks in backend-core. --- .../__mocks__/@aws-sdk/client-s3.ts | 33 +++++++++++++++++ .../@aws-sdk/s3-request-presigner.ts | 1 + packages/backend-core/__mocks__/aws-sdk.ts | 19 ---------- .../src/objectStore/buckets/tests/app.spec.ts | 36 ------------------- 4 files changed, 34 insertions(+), 55 deletions(-) create mode 100644 packages/backend-core/__mocks__/@aws-sdk/client-s3.ts create mode 100644 packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts delete mode 100644 packages/backend-core/__mocks__/aws-sdk.ts diff --git a/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts b/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts new file mode 100644 index 0000000000..f93b493493 --- /dev/null +++ b/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts @@ -0,0 +1,33 @@ +export class S3 { + headBucket() { + return jest.fn().mockReturnThis() + } + deleteObject() { + return jest.fn().mockReturnThis() + } + deleteObjects() { + return jest.fn().mockReturnThis() + } + createBucket() { + return jest.fn().mockReturnThis() + } + getObject() { + return jest.fn().mockReturnThis() + } + listObject() { + return jest.fn().mockReturnThis() + } + getSignedUrl() { + return jest.fn((operation: string, params: any) => { + return `http://s3.example.com/${params.Bucket}/${params.Key}` + }) + } + promise() { + return jest.fn().mockReturnThis() + } + catch() { + return jest.fn() + } +} + +export const GetObjectCommand = jest.fn() diff --git a/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts b/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts new file mode 100644 index 0000000000..1a39fd96ae --- /dev/null +++ b/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts @@ -0,0 +1 @@ +export const getSignedUrl = jest.fn(() => "http://localhost:10000") diff --git a/packages/backend-core/__mocks__/aws-sdk.ts b/packages/backend-core/__mocks__/aws-sdk.ts deleted file mode 100644 index e3be511d08..0000000000 --- a/packages/backend-core/__mocks__/aws-sdk.ts +++ /dev/null @@ -1,19 +0,0 @@ -const mockS3 = { - headBucket: jest.fn().mockReturnThis(), - deleteObject: jest.fn().mockReturnThis(), - deleteObjects: jest.fn().mockReturnThis(), - createBucket: jest.fn().mockReturnThis(), - getObject: jest.fn().mockReturnThis(), - listObject: jest.fn().mockReturnThis(), - getSignedUrl: jest.fn((operation: string, params: any) => { - return `http://s3.example.com/${params.Bucket}/${params.Key}` - }), - promise: jest.fn().mockReturnThis(), - catch: jest.fn(), -} - -const AWS = { - S3: jest.fn(() => mockS3), -} - -export default AWS diff --git a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts index 1aeba8f2c2..d188d774bb 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts @@ -93,22 +93,6 @@ describe("app", () => { testEnv.multiTenant() }) - it("gets url with embedded minio", () => { - testEnv.withMinio() - const url = getAppFileUrl() - expect(url).toBe( - "/files/signed/prod-budi-app-assets/app_123/attachments/image.jpeg" - ) - }) - - it("gets url with custom S3", () => { - testEnv.withS3() - const url = getAppFileUrl() - expect(url).toBe( - "http://s3.example.com/prod-budi-app-assets/app_123/attachments/image.jpeg" - ) - }) - it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() const url = await getAppFileUrl() @@ -124,26 +108,6 @@ describe("app", () => { testEnv.multiTenant() }) - it("gets url with embedded minio", async () => { - testEnv.withMinio() - await testEnv.withTenant(() => { - const url = getAppFileUrl() - expect(url).toBe( - "/files/signed/prod-budi-app-assets/app_123/attachments/image.jpeg" - ) - }) - }) - - it("gets url with custom S3", async () => { - testEnv.withS3() - await testEnv.withTenant(() => { - const url = getAppFileUrl() - expect(url).toBe( - "http://s3.example.com/prod-budi-app-assets/app_123/attachments/image.jpeg" - ) - }) - }) - it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() await testEnv.withTenant(async () => { From 6e6c3c7bacb10a6b226307ec268e41fbaa7a5989 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 19 Dec 2024 15:32:54 +0000 Subject: [PATCH 008/173] Fixing another test depending on mock behaviour. --- .../objectStore/buckets/tests/global.spec.ts | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts index be459a7a23..9d5ec07c7a 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts @@ -3,7 +3,7 @@ import { testEnv } from "../../../../tests/extra" describe("global", () => { describe("getGlobalFileUrl", () => { - function getGlobalFileUrl() { + async function getGlobalFileUrl() { return global.getGlobalFileUrl("settings", "logoUrl", "etag") } @@ -12,18 +12,6 @@ describe("global", () => { testEnv.singleTenant() }) - it("gets url with embedded minio", () => { - testEnv.withMinio() - const url = getGlobalFileUrl() - expect(url).toBe("/files/signed/global/settings/logoUrl") - }) - - it("gets url with custom S3", () => { - testEnv.withS3() - const url = getGlobalFileUrl() - expect(url).toBe("http://s3.example.com/global/settings/logoUrl") - }) - it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() const url = await getGlobalFileUrl() @@ -39,24 +27,6 @@ describe("global", () => { testEnv.multiTenant() }) - it("gets url with embedded minio", async () => { - testEnv.withMinio() - await testEnv.withTenant(tenantId => { - const url = getGlobalFileUrl() - expect(url).toBe(`/files/signed/global/${tenantId}/settings/logoUrl`) - }) - }) - - it("gets url with custom S3", async () => { - testEnv.withS3() - await testEnv.withTenant(tenantId => { - const url = getGlobalFileUrl() - expect(url).toBe( - `http://s3.example.com/global/${tenantId}/settings/logoUrl` - ) - }) - }) - it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() await testEnv.withTenant(async tenantId => { From f9e144f25cd70dfc61e5bb17e39b55eb2b1be276 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 19 Dec 2024 15:43:04 +0000 Subject: [PATCH 009/173] Updating mocks. --- packages/backend-core/__mocks__/@aws-sdk/client-s3.ts | 7 +------ .../__mocks__/@aws-sdk/s3-request-presigner.ts | 5 ++++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts b/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts index f93b493493..8f002f41a8 100644 --- a/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts +++ b/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts @@ -17,11 +17,6 @@ export class S3 { listObject() { return jest.fn().mockReturnThis() } - getSignedUrl() { - return jest.fn((operation: string, params: any) => { - return `http://s3.example.com/${params.Bucket}/${params.Key}` - }) - } promise() { return jest.fn().mockReturnThis() } @@ -30,4 +25,4 @@ export class S3 { } } -export const GetObjectCommand = jest.fn() +export const GetObjectCommand = jest.fn(inputs => ({ inputs })) diff --git a/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts b/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts index 1a39fd96ae..3ed2c10595 100644 --- a/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts +++ b/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts @@ -1 +1,4 @@ -export const getSignedUrl = jest.fn(() => "http://localhost:10000") +export const getSignedUrl = jest.fn((_, cmd) => { + const { inputs } = cmd + return `http://s3.example.com/${inputs?.Bucket}/${inputs?.Key}` +}) From fbeb15d18656701c9d3f5ab9716579d6ee196758 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 20 Dec 2024 14:00:59 +0000 Subject: [PATCH 010/173] Updating hover and navigation stores. --- .../src/stores/builder/{hover.js => hover.ts} | 13 ++++++--- .../builder/{navigation.js => navigation.ts} | 29 +++++++++---------- packages/types/src/documents/app/app.ts | 8 +++-- packages/types/src/ui/stores/index.ts | 1 + packages/types/src/ui/stores/misc.ts | 2 ++ 5 files changed, 31 insertions(+), 22 deletions(-) rename packages/builder/src/stores/builder/{hover.js => hover.ts} (73%) rename packages/builder/src/stores/builder/{navigation.js => navigation.ts} (73%) create mode 100644 packages/types/src/ui/stores/misc.ts diff --git a/packages/builder/src/stores/builder/hover.js b/packages/builder/src/stores/builder/hover.ts similarity index 73% rename from packages/builder/src/stores/builder/hover.js rename to packages/builder/src/stores/builder/hover.ts index 8da7191cf5..aec8eed1cd 100644 --- a/packages/builder/src/stores/builder/hover.js +++ b/packages/builder/src/stores/builder/hover.ts @@ -2,19 +2,24 @@ import { get } from "svelte/store" import { previewStore } from "stores/builder" import { BudiStore } from "../BudiStore" +interface BuilderHoverStore { + hoverTimeout?: NodeJS.Timeout + componentId: string | null +} + export const INITIAL_HOVER_STATE = { componentId: null, } -export class HoverStore extends BudiStore { - hoverTimeout +export class HoverStore extends BudiStore { + hoverTimeout?: NodeJS.Timeout constructor() { super({ ...INITIAL_HOVER_STATE }) this.hover = this.hover.bind(this) } - hover(componentId, notifyClient = true) { + hover(componentId: string, notifyClient = true) { clearTimeout(this.hoverTimeout) if (componentId) { this.processHover(componentId, notifyClient) @@ -25,7 +30,7 @@ export class HoverStore extends BudiStore { } } - processHover(componentId, notifyClient) { + processHover(componentId: string, notifyClient?: boolean) { if (componentId === get(this.store).componentId) { return } diff --git a/packages/builder/src/stores/builder/navigation.js b/packages/builder/src/stores/builder/navigation.ts similarity index 73% rename from packages/builder/src/stores/builder/navigation.js rename to packages/builder/src/stores/builder/navigation.ts index abdd9638f3..f623224f4d 100644 --- a/packages/builder/src/stores/builder/navigation.js +++ b/packages/builder/src/stores/builder/navigation.ts @@ -2,27 +2,22 @@ import { get } from "svelte/store" import { API } from "api" import { appStore } from "stores/builder" import { BudiStore } from "../BudiStore" +import { AppNavigation, AppNavigationLink, UIObject } from "@budibase/types" + +interface BuilderNavigationStore extends AppNavigation {} export const INITIAL_NAVIGATION_STATE = { navigation: "Top", links: [], - title: null, - sticky: null, - hideLogo: null, - logoUrl: null, - hideTitle: null, textAlign: "Left", - navBackground: null, - navWidth: null, - navTextColor: null, } -export class NavigationStore extends BudiStore { +export class NavigationStore extends BudiStore { constructor() { super(INITIAL_NAVIGATION_STATE) } - syncAppNavigation(nav) { + syncAppNavigation(nav: AppNavigation) { this.update(state => ({ ...state, ...nav, @@ -33,15 +28,17 @@ export class NavigationStore extends BudiStore { this.store.set({ ...INITIAL_NAVIGATION_STATE }) } - async save(navigation) { + async save(navigation: AppNavigation) { const appId = get(appStore).appId const app = await API.saveAppMetadata(appId, { navigation }) - this.syncAppNavigation(app.navigation) + if (app.navigation) { + this.syncAppNavigation(app.navigation) + } } - async saveLink(url, title, roleId) { + async saveLink(url: string, title: string, roleId: string) { const navigation = get(this.store) - let links = [...(navigation?.links ?? [])] + let links: AppNavigationLink[] = [...(navigation?.links ?? [])] // Skip if we have an identical link if (links.find(link => link.url === url && link.text === title)) { @@ -60,7 +57,7 @@ export class NavigationStore extends BudiStore { }) } - async deleteLink(urls) { + async deleteLink(urls: string[] | string) { const navigation = get(this.store) let links = navigation?.links if (!links?.length) { @@ -86,7 +83,7 @@ export class NavigationStore extends BudiStore { }) } - syncMetadata(metadata) { + syncMetadata(metadata: UIObject) { const { navigation } = metadata this.syncAppNavigation(navigation) } diff --git a/packages/types/src/documents/app/app.ts b/packages/types/src/documents/app/app.ts index e31dd1e9ac..a316ce173c 100644 --- a/packages/types/src/documents/app/app.ts +++ b/packages/types/src/documents/app/app.ts @@ -1,5 +1,6 @@ import { User, Document, Plugin, Snippet } from "../" import { SocketSession } from "../../sdk" +import { NavLink } from "../../ui" export type AppMetadataErrors = { [key: string]: string[] } @@ -37,8 +38,8 @@ export interface AppInstance { export interface AppNavigation { navigation: string - title: string - navWidth: string + title?: string + navWidth?: string sticky?: boolean hideLogo?: boolean logoUrl?: string @@ -46,6 +47,7 @@ export interface AppNavigation { navBackground?: string navTextColor?: string links?: AppNavigationLink[] + textAlign?: string } export interface AppNavigationLink { @@ -53,6 +55,8 @@ export interface AppNavigationLink { url: string id?: string roleId?: string + type?: string + subLinks?: AppNavigationLink[] } export interface AppCustomTheme { diff --git a/packages/types/src/ui/stores/index.ts b/packages/types/src/ui/stores/index.ts index 658691cc6d..f3f6a96296 100644 --- a/packages/types/src/ui/stores/index.ts +++ b/packages/types/src/ui/stores/index.ts @@ -1 +1,2 @@ export * from "./integration" +export * from "./misc" diff --git a/packages/types/src/ui/stores/misc.ts b/packages/types/src/ui/stores/misc.ts new file mode 100644 index 0000000000..275b388e9f --- /dev/null +++ b/packages/types/src/ui/stores/misc.ts @@ -0,0 +1,2 @@ +// type purely to capture structures that the type is unknown, but maybe known later +export type UIObject = Record From ace8c68a264413ef83ca25264a18538575f4a545 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 20 Dec 2024 14:10:06 +0000 Subject: [PATCH 011/173] Lint. --- packages/types/src/documents/app/app.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/types/src/documents/app/app.ts b/packages/types/src/documents/app/app.ts index a316ce173c..e253aab225 100644 --- a/packages/types/src/documents/app/app.ts +++ b/packages/types/src/documents/app/app.ts @@ -1,6 +1,5 @@ import { User, Document, Plugin, Snippet } from "../" import { SocketSession } from "../../sdk" -import { NavLink } from "../../ui" export type AppMetadataErrors = { [key: string]: string[] } From fa06f7b6e8f0911f5bb0d3d0a7a96f2795fac3a3 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 2 Jan 2025 10:29:39 +0000 Subject: [PATCH 012/173] Minor bug fix to ensure getPathSteps builds correctly. This will fix the test details --- packages/builder/src/stores/builder/automations.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/stores/builder/automations.ts b/packages/builder/src/stores/builder/automations.ts index c43a856cc4..9b20b4cd03 100644 --- a/packages/builder/src/stores/builder/automations.ts +++ b/packages/builder/src/stores/builder/automations.ts @@ -291,8 +291,8 @@ const automationActions = (store: AutomationStore) => ({ let result: (AutomationStep | AutomationTrigger)[] = [] pathWay.forEach(path => { const { stepIdx, branchIdx } = path - let last = result ? result[result.length - 1] : [] - if (!result) { + let last = result.length ? result[result.length - 1] : [] + if (!result.length) { // Preceeding steps. result = steps.slice(0, stepIdx + 1) return From 8047ff99c6a7685b84d432d82ee80ef5cd9b2468 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 2 Jan 2025 10:59:14 +0000 Subject: [PATCH 013/173] Flags / Layout / Preview stores to TS --- packages/builder/src/stores/builder/flags.js | 27 ------ packages/builder/src/stores/builder/flags.ts | 41 +++++++++ .../stores/builder/{layouts.js => layouts.ts} | 20 +++-- .../builder/src/stores/builder/preview.js | 80 ----------------- .../builder/src/stores/builder/preview.ts | 90 +++++++++++++++++++ 5 files changed, 144 insertions(+), 114 deletions(-) delete mode 100644 packages/builder/src/stores/builder/flags.js create mode 100644 packages/builder/src/stores/builder/flags.ts rename packages/builder/src/stores/builder/{layouts.js => layouts.ts} (77%) delete mode 100644 packages/builder/src/stores/builder/preview.js create mode 100644 packages/builder/src/stores/builder/preview.ts diff --git a/packages/builder/src/stores/builder/flags.js b/packages/builder/src/stores/builder/flags.js deleted file mode 100644 index 21236ffb01..0000000000 --- a/packages/builder/src/stores/builder/flags.js +++ /dev/null @@ -1,27 +0,0 @@ -import { writable } from "svelte/store" -import { API } from "@/api" - -export function createFlagsStore() { - const { subscribe, set } = writable({}) - - const actions = { - fetch: async () => { - const flags = await API.getFlags() - set(flags) - }, - updateFlag: async (flag, value) => { - await API.updateFlag(flag, value) - await actions.fetch() - }, - toggleUiFeature: async feature => { - await API.toggleUiFeature(feature) - }, - } - - return { - subscribe, - ...actions, - } -} - -export const flags = createFlagsStore() diff --git a/packages/builder/src/stores/builder/flags.ts b/packages/builder/src/stores/builder/flags.ts new file mode 100644 index 0000000000..cff3ac4d12 --- /dev/null +++ b/packages/builder/src/stores/builder/flags.ts @@ -0,0 +1,41 @@ +import { get } from "svelte/store" +import { API } from "@/api" +import { GetUserFlagsResponse } from "@budibase/types" +import { BudiStore } from "../BudiStore" + +interface FlagsState { + flags: GetUserFlagsResponse +} + +const INITIAL_FLAGS_STATE: FlagsState = { + flags: {}, +} + +export class FlagsStore extends BudiStore { + constructor() { + super(INITIAL_FLAGS_STATE) + + this.fetch = this.fetch.bind(this) + this.updateFlag = this.updateFlag.bind(this) + this.toggleUiFeature = this.toggleUiFeature.bind(this) + } + + async fetch() { + const flags = await API.getFlags() + this.update(state => ({ + ...state, + flags, + })) + } + + async updateFlag(flag: string, value: any) { + await API.updateFlag(flag, value) + await this.fetch() + } + + async toggleUiFeature(feature: string) { + await API.toggleUiFeature(feature) + } +} + +export const flags = new FlagsStore() diff --git a/packages/builder/src/stores/builder/layouts.js b/packages/builder/src/stores/builder/layouts.ts similarity index 77% rename from packages/builder/src/stores/builder/layouts.js rename to packages/builder/src/stores/builder/layouts.ts index 7617e203f0..0fd8efc8c0 100644 --- a/packages/builder/src/stores/builder/layouts.js +++ b/packages/builder/src/stores/builder/layouts.ts @@ -2,13 +2,19 @@ import { derived, get } from "svelte/store" import { componentStore } from "@/stores/builder" import { API } from "@/api" import { BudiStore } from "../BudiStore" +import { Layout } from "@budibase/types" -export const INITIAL_LAYOUT_STATE = { +interface LayoutState { + layouts: Layout[] + selectedLayoutId: string | null +} + +export const INITIAL_LAYOUT_STATE: LayoutState = { layouts: [], selectedLayoutId: null, } -export class LayoutStore extends BudiStore { +export class LayoutStore extends BudiStore { constructor() { super(INITIAL_LAYOUT_STATE) @@ -22,14 +28,14 @@ export class LayoutStore extends BudiStore { this.store.set({ ...INITIAL_LAYOUT_STATE }) } - syncAppLayouts(pkg) { + syncAppLayouts(pkg: { layouts: Layout[] }) { this.update(state => ({ ...state, layouts: [...pkg.layouts], })) } - select(layoutId) { + select(layoutId: string) { // Check this layout exists const state = get(this.store) const componentState = get(componentStore) @@ -48,18 +54,18 @@ export class LayoutStore extends BudiStore { // Select new layout this.update(state => { - state.selectedLayoutId = layout._id + state.selectedLayoutId = layout._id! return state }) componentStore.select(layout.props?._id) } - async deleteLayout(layout) { + async deleteLayout(layout: Layout) { if (!layout?._id) { return } - await API.deleteLayout(layout._id, layout._rev) + await API.deleteLayout(layout._id, layout._rev!) this.update(state => { state.layouts = state.layouts.filter(x => x._id !== layout._id) return state diff --git a/packages/builder/src/stores/builder/preview.js b/packages/builder/src/stores/builder/preview.js deleted file mode 100644 index 4923185ee7..0000000000 --- a/packages/builder/src/stores/builder/preview.js +++ /dev/null @@ -1,80 +0,0 @@ -import { writable, get } from "svelte/store" - -const INITIAL_PREVIEW_STATE = { - previewDevice: "desktop", - previewEventHandler: null, - showPreview: false, - selectedComponentContext: null, -} - -export const createPreviewStore = () => { - const store = writable({ - ...INITIAL_PREVIEW_STATE, - }) - - const setDevice = device => { - store.update(state => { - state.previewDevice = device - return state - }) - } - - // Potential evt names "eject-block", "dragging-new-component" - const sendEvent = (name, payload) => { - const { previewEventHandler } = get(store) - previewEventHandler?.(name, payload) - } - - const registerEventHandler = handler => { - store.update(state => { - state.previewEventHandler = handler - return state - }) - } - - const startDrag = component => { - sendEvent("dragging-new-component", { - dragging: true, - component, - }) - } - - const stopDrag = () => { - sendEvent("dragging-new-component", { - dragging: false, - }) - } - - //load preview? - const showPreview = isVisible => { - store.update(state => { - state.showPreview = isVisible - return state - }) - } - - const setSelectedComponentContext = context => { - store.update(state => { - state.selectedComponentContext = context - return state - }) - } - - const requestComponentContext = () => { - sendEvent("request-context") - } - - return { - subscribe: store.subscribe, - setDevice, - sendEvent, //may not be required - registerEventHandler, - startDrag, - stopDrag, - showPreview, - setSelectedComponentContext, - requestComponentContext, - } -} - -export const previewStore = createPreviewStore() diff --git a/packages/builder/src/stores/builder/preview.ts b/packages/builder/src/stores/builder/preview.ts new file mode 100644 index 0000000000..fe14c02535 --- /dev/null +++ b/packages/builder/src/stores/builder/preview.ts @@ -0,0 +1,90 @@ +import { get } from "svelte/store" +import { BudiStore } from "../BudiStore" + +type PreviewDevice = "desktop" | "tablet" | "mobile" +type PreviewEventHandler = (name: string, payload?: any) => void +type ComponentContext = Record + +interface PreviewState { + previewDevice: PreviewDevice + previewEventHandler: PreviewEventHandler | null + showPreview: boolean + selectedComponentContext: ComponentContext | null +} + +const INITIAL_PREVIEW_STATE: PreviewState = { + previewDevice: "desktop", + previewEventHandler: null, + showPreview: false, + selectedComponentContext: null, +} + +export class PreviewStore extends BudiStore { + constructor() { + super(INITIAL_PREVIEW_STATE) + + this.setDevice = this.setDevice.bind(this) + this.sendEvent = this.sendEvent.bind(this) + this.registerEventHandler = this.registerEventHandler.bind(this) + this.startDrag = this.startDrag.bind(this) + this.stopDrag = this.stopDrag.bind(this) + this.showPreview = this.showPreview.bind(this) + this.setSelectedComponentContext = + this.setSelectedComponentContext.bind(this) + this.requestComponentContext = this.requestComponentContext.bind(this) + } + + setDevice(device: PreviewDevice) { + this.update(state => ({ + ...state, + previewDevice: device, + })) + } + + // Potential evt names "eject-block", "dragging-new-component" + sendEvent(name: string, payload?: any) { + const { previewEventHandler } = get(this.store) + previewEventHandler?.(name, payload) + } + + registerEventHandler(handler: PreviewEventHandler) { + this.update(state => ({ + ...state, + previewEventHandler: handler, + })) + } + + startDrag(component: any) { + this.sendEvent("dragging-new-component", { + dragging: true, + component, + }) + } + + stopDrag() { + this.sendEvent("dragging-new-component", { + dragging: false, + }) + } + + //load preview? + showPreview(isVisible: boolean) { + this.update(state => ({ + ...state, + showPreview: isVisible, + })) + } + + setSelectedComponentContext(context: ComponentContext) { + this.update(state => ({ + ...state, + selectedComponentContext: context, + })) + } + + requestComponentContext() { + this.sendEvent("request-context") + } +} + +export const previewStore = new PreviewStore() From 7c36d8dac56a64f7b612f99af016f862d346daac Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 2 Jan 2025 11:04:30 +0000 Subject: [PATCH 014/173] convert selectedLayout derived store --- .../builder/src/stores/builder/layouts.ts | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/stores/builder/layouts.ts b/packages/builder/src/stores/builder/layouts.ts index 0fd8efc8c0..41e61e3611 100644 --- a/packages/builder/src/stores/builder/layouts.ts +++ b/packages/builder/src/stores/builder/layouts.ts @@ -1,7 +1,7 @@ import { derived, get } from "svelte/store" import { componentStore } from "@/stores/builder" import { API } from "@/api" -import { BudiStore } from "../BudiStore" +import { BudiStore, DerivedBudiStore } from "../BudiStore" import { Layout } from "@budibase/types" interface LayoutState { @@ -9,6 +9,10 @@ interface LayoutState { selectedLayoutId: string | null } +interface DerivedLayoutState extends LayoutState { + selectedLayout: Layout | null +} + export const INITIAL_LAYOUT_STATE: LayoutState = { layouts: [], selectedLayoutId: null, @@ -62,10 +66,10 @@ export class LayoutStore extends BudiStore { } async deleteLayout(layout: Layout) { - if (!layout?._id) { + if (!layout?._id || !layout?._rev) { return } - await API.deleteLayout(layout._id, layout._rev!) + await API.deleteLayout(layout._id, layout._rev) this.update(state => { state.layouts = state.layouts.filter(x => x._id !== layout._id) return state @@ -75,6 +79,24 @@ export class LayoutStore extends BudiStore { export const layoutStore = new LayoutStore() -export const selectedLayout = derived(layoutStore, $store => { - return $store.layouts?.find(layout => layout._id === $store.selectedLayoutId) -}) +export class SelectedLayoutStore extends DerivedBudiStore< + LayoutState, + DerivedLayoutState +> { + constructor(layoutStore: LayoutStore) { + const makeDerivedStore = () => { + return derived(layoutStore, $store => { + return { + ...$store, + selectedLayout: + $store.layouts?.find( + layout => layout._id === $store.selectedLayoutId + ) || null, + } + }) + } + super(INITIAL_LAYOUT_STATE, makeDerivedStore) + } +} + +export const selectedLayout = new SelectedLayoutStore(layoutStore) From 11e55bfbd72d653adea51e3ba3ed4026b0922c5f Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 2 Jan 2025 11:19:20 +0000 Subject: [PATCH 015/173] move types --- packages/builder/src/stores/builder/preview.ts | 2 +- packages/types/src/ui/stores/index.ts | 1 + packages/types/src/ui/stores/preview.ts | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 packages/types/src/ui/stores/preview.ts diff --git a/packages/builder/src/stores/builder/preview.ts b/packages/builder/src/stores/builder/preview.ts index fe14c02535..0ec2811e15 100644 --- a/packages/builder/src/stores/builder/preview.ts +++ b/packages/builder/src/stores/builder/preview.ts @@ -1,7 +1,7 @@ import { get } from "svelte/store" import { BudiStore } from "../BudiStore" +import { PreviewDevice } from "@budibase/types" -type PreviewDevice = "desktop" | "tablet" | "mobile" type PreviewEventHandler = (name: string, payload?: any) => void type ComponentContext = Record diff --git a/packages/types/src/ui/stores/index.ts b/packages/types/src/ui/stores/index.ts index 8dae68862e..1b82a06388 100644 --- a/packages/types/src/ui/stores/index.ts +++ b/packages/types/src/ui/stores/index.ts @@ -1,3 +1,4 @@ export * from "./integration" export * from "./automations" export * from "./grid" +export * from "./preview" diff --git a/packages/types/src/ui/stores/preview.ts b/packages/types/src/ui/stores/preview.ts new file mode 100644 index 0000000000..4d09366ff5 --- /dev/null +++ b/packages/types/src/ui/stores/preview.ts @@ -0,0 +1 @@ +export type PreviewDevice = "desktop" | "tablet" | "mobile" From 2f1b7811c3eebb265f3717be94350106fff37277 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 2 Jan 2025 11:25:22 +0000 Subject: [PATCH 016/173] unused import --- packages/builder/src/stores/builder/flags.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/builder/src/stores/builder/flags.ts b/packages/builder/src/stores/builder/flags.ts index cff3ac4d12..6d2150f49b 100644 --- a/packages/builder/src/stores/builder/flags.ts +++ b/packages/builder/src/stores/builder/flags.ts @@ -1,4 +1,3 @@ -import { get } from "svelte/store" import { API } from "@/api" import { GetUserFlagsResponse } from "@budibase/types" import { BudiStore } from "../BudiStore" From 4ee99f807c47ff442cccfddac2d784a8bccd85cb Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 2 Jan 2025 12:22:46 +0000 Subject: [PATCH 017/173] revert derivedstore implementation --- packages/builder/src/stores/builder/flags.ts | 1 + .../builder/src/stores/builder/layouts.ts | 30 +++---------------- .../builder/src/stores/builder/preview.ts | 2 +- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/packages/builder/src/stores/builder/flags.ts b/packages/builder/src/stores/builder/flags.ts index 6d2150f49b..cff3ac4d12 100644 --- a/packages/builder/src/stores/builder/flags.ts +++ b/packages/builder/src/stores/builder/flags.ts @@ -1,3 +1,4 @@ +import { get } from "svelte/store" import { API } from "@/api" import { GetUserFlagsResponse } from "@budibase/types" import { BudiStore } from "../BudiStore" diff --git a/packages/builder/src/stores/builder/layouts.ts b/packages/builder/src/stores/builder/layouts.ts index 41e61e3611..af7b17fcc7 100644 --- a/packages/builder/src/stores/builder/layouts.ts +++ b/packages/builder/src/stores/builder/layouts.ts @@ -1,7 +1,7 @@ import { derived, get } from "svelte/store" import { componentStore } from "@/stores/builder" import { API } from "@/api" -import { BudiStore, DerivedBudiStore } from "../BudiStore" +import { BudiStore } from "../BudiStore" import { Layout } from "@budibase/types" interface LayoutState { @@ -9,10 +9,6 @@ interface LayoutState { selectedLayoutId: string | null } -interface DerivedLayoutState extends LayoutState { - selectedLayout: Layout | null -} - export const INITIAL_LAYOUT_STATE: LayoutState = { layouts: [], selectedLayoutId: null, @@ -79,24 +75,6 @@ export class LayoutStore extends BudiStore { export const layoutStore = new LayoutStore() -export class SelectedLayoutStore extends DerivedBudiStore< - LayoutState, - DerivedLayoutState -> { - constructor(layoutStore: LayoutStore) { - const makeDerivedStore = () => { - return derived(layoutStore, $store => { - return { - ...$store, - selectedLayout: - $store.layouts?.find( - layout => layout._id === $store.selectedLayoutId - ) || null, - } - }) - } - super(INITIAL_LAYOUT_STATE, makeDerivedStore) - } -} - -export const selectedLayout = new SelectedLayoutStore(layoutStore) +export const selectedLayout = derived(layoutStore, $store => { + return $store.layouts?.find(layout => layout._id === $store.selectedLayoutId) +}) diff --git a/packages/builder/src/stores/builder/preview.ts b/packages/builder/src/stores/builder/preview.ts index 0ec2811e15..fe14c02535 100644 --- a/packages/builder/src/stores/builder/preview.ts +++ b/packages/builder/src/stores/builder/preview.ts @@ -1,7 +1,7 @@ import { get } from "svelte/store" import { BudiStore } from "../BudiStore" -import { PreviewDevice } from "@budibase/types" +type PreviewDevice = "desktop" | "tablet" | "mobile" type PreviewEventHandler = (name: string, payload?: any) => void type ComponentContext = Record From 6d95076d28373dbfe5a79a36a7ba5940771647fd Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 2 Jan 2025 12:59:25 +0000 Subject: [PATCH 018/173] lint --- packages/builder/src/stores/builder/flags.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/builder/src/stores/builder/flags.ts b/packages/builder/src/stores/builder/flags.ts index cff3ac4d12..6d2150f49b 100644 --- a/packages/builder/src/stores/builder/flags.ts +++ b/packages/builder/src/stores/builder/flags.ts @@ -1,4 +1,3 @@ -import { get } from "svelte/store" import { API } from "@/api" import { GetUserFlagsResponse } from "@budibase/types" import { BudiStore } from "../BudiStore" From 4353e56200aaafc9bd8c1396faef4256145d1f1a Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 2 Jan 2025 14:00:24 +0000 Subject: [PATCH 019/173] Bump version to 3.2.30 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 5e0bc09825..000f9eda16 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.29", + "version": "3.2.30", "npmClient": "yarn", "concurrency": 20, "command": { From 46a132a220fe585214a1ca1ecdf8dfdc82ea337e Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 2 Jan 2025 14:31:42 +0000 Subject: [PATCH 020/173] Bump version to 3.2.31 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 000f9eda16..155f4f5ba3 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.30", + "version": "3.2.31", "npmClient": "yarn", "concurrency": 20, "command": { From aba5fbfd89b9b6b6ebc3c5274add460470a9a5cd Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 16:04:17 +0100 Subject: [PATCH 021/173] Fix user cell search --- .../src/components/grid/cells/BBReferenceCell.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/cells/BBReferenceCell.svelte b/packages/frontend-core/src/components/grid/cells/BBReferenceCell.svelte index 5d98ba903b..fe6d8945ba 100644 --- a/packages/frontend-core/src/components/grid/cells/BBReferenceCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/BBReferenceCell.svelte @@ -26,7 +26,7 @@ : RelationshipType.MANY_TO_MANY, } - async function searchFunction(searchParams) { + async function searchFunction(_tableId, searchParams) { if ( subtype !== BBReferenceFieldSubType.USER && subtype !== BBReferenceFieldSubType.USERS From 94adbb15adc43dc2fa8b71ad5ca18f326a598e96 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 2 Jan 2025 15:17:22 +0000 Subject: [PATCH 022/173] Bump version to 3.2.32 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 155f4f5ba3..dde9cf03a0 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.31", + "version": "3.2.32", "npmClient": "yarn", "concurrency": 20, "command": { From b4b805ac1c94cfc5594f1e50a695a5441acb55f3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 3 Jan 2025 11:02:09 +0100 Subject: [PATCH 023/173] Fix queries when returning nulls --- packages/server/src/threads/query.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/src/threads/query.ts b/packages/server/src/threads/query.ts index facdd20642..3ba4995b2c 100644 --- a/packages/server/src/threads/query.ts +++ b/packages/server/src/threads/query.ts @@ -174,7 +174,9 @@ class QueryRunner { } // needs to an array for next step - if (!Array.isArray(rows)) { + if (rows === null) { + rows = [] + } else if (!Array.isArray(rows)) { rows = [rows] } From 9c7beeeeaf846dfdb71f942ed686d1bbe0e199ea Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 3 Jan 2025 10:42:59 +0000 Subject: [PATCH 024/173] user and websocket stores converted to typescript --- packages/builder/src/stores/builder/users.js | 62 --------- packages/builder/src/stores/builder/users.ts | 72 ++++++++++ .../builder/src/stores/builder/websocket.js | 95 -------------- .../builder/src/stores/builder/websocket.ts | 124 ++++++++++++++++++ .../src/utils/{websocket.js => websocket.ts} | 16 ++- packages/types/src/ui/stores/grid/user.ts | 1 + 6 files changed, 208 insertions(+), 162 deletions(-) delete mode 100644 packages/builder/src/stores/builder/users.js create mode 100644 packages/builder/src/stores/builder/users.ts delete mode 100644 packages/builder/src/stores/builder/websocket.js create mode 100644 packages/builder/src/stores/builder/websocket.ts rename packages/frontend-core/src/utils/{websocket.js => websocket.ts} (78%) diff --git a/packages/builder/src/stores/builder/users.js b/packages/builder/src/stores/builder/users.js deleted file mode 100644 index 0794c63289..0000000000 --- a/packages/builder/src/stores/builder/users.js +++ /dev/null @@ -1,62 +0,0 @@ -import { writable, get, derived } from "svelte/store" - -export const createUserStore = () => { - const store = writable([]) - - const init = users => { - store.set(users) - } - - const updateUser = user => { - const $users = get(store) - if (!$users.some(x => x.sessionId === user.sessionId)) { - store.set([...$users, user]) - } else { - store.update(state => { - const index = state.findIndex(x => x.sessionId === user.sessionId) - state[index] = user - return state.slice() - }) - } - } - - const removeUser = sessionId => { - store.update(state => { - return state.filter(x => x.sessionId !== sessionId) - }) - } - - const reset = () => { - store.set([]) - } - - return { - ...store, - actions: { - init, - updateUser, - removeUser, - reset, - }, - } -} - -export const userStore = createUserStore() - -export const userSelectedResourceMap = derived(userStore, $userStore => { - let map = {} - $userStore.forEach(user => { - const resource = user.builderMetadata?.selectedResourceId - if (resource) { - if (!map[resource]) { - map[resource] = [] - } - map[resource].push(user) - } - }) - return map -}) - -export const isOnlyUser = derived(userStore, $userStore => { - return $userStore.length < 2 -}) diff --git a/packages/builder/src/stores/builder/users.ts b/packages/builder/src/stores/builder/users.ts new file mode 100644 index 0000000000..5f0c4a3701 --- /dev/null +++ b/packages/builder/src/stores/builder/users.ts @@ -0,0 +1,72 @@ +import { get, derived } from "svelte/store" +import { BudiStore } from "../BudiStore" +import { UIUser } from "@budibase/types" + +export class UserStore extends BudiStore { + actions: { + init: (users: UIUser[]) => void + updateUser: (user: UIUser) => void + removeUser: (sessionId: string) => void + reset: () => void + } + + constructor() { + super([]) + this.actions = { + init: this.init.bind(this), + updateUser: this.updateUser.bind(this), + removeUser: this.removeUser.bind(this), + reset: this.reset.bind(this), + } + } + + init(users: UIUser[]) { + this.store.set(users) + } + + updateUser(user: UIUser) { + const $users = get(this.store) + if (!$users.some(x => x.sessionId === user.sessionId)) { + this.store.set([...$users, user]) + } else { + this.update(state => { + const index = state.findIndex(x => x.sessionId === user.sessionId) + state[index] = user + return state.slice() + }) + } + } + + removeUser(sessionId: string) { + this.update(state => { + return state.filter(x => x.sessionId !== sessionId) + }) + } + + reset() { + this.store.set([]) + } +} + +export const userStore = new UserStore() + +export const userSelectedResourceMap = derived( + userStore, + ($userStore): Record => { + let map: Record = {} + $userStore.forEach(user => { + const resource = user.builderMetadata?.selectedResourceId + if (resource) { + if (!map[resource]) { + map[resource] = [] + } + map[resource].push(user) + } + }) + return map + } +) + +export const isOnlyUser = derived(userStore, $userStore => { + return $userStore.length < 2 +}) diff --git a/packages/builder/src/stores/builder/websocket.js b/packages/builder/src/stores/builder/websocket.js deleted file mode 100644 index 3944c8cba5..0000000000 --- a/packages/builder/src/stores/builder/websocket.js +++ /dev/null @@ -1,95 +0,0 @@ -import { createWebsocket } from "@budibase/frontend-core" -import { - automationStore, - userStore, - appStore, - themeStore, - navigationStore, - deploymentStore, - snippets, - datasources, - tables, - roles, -} from "@/stores/builder" -import { get } from "svelte/store" -import { auth, appsStore } from "@/stores/portal" -import { screenStore } from "./screens" -import { SocketEvent, BuilderSocketEvent, helpers } from "@budibase/shared-core" -import { notifications } from "@budibase/bbui" - -export const createBuilderWebsocket = appId => { - const socket = createWebsocket("/socket/builder") - - // Built-in events - socket.on("connect", () => { - socket.emit(BuilderSocketEvent.SelectApp, { appId }, ({ users }) => { - userStore.actions.init(users) - }) - }) - socket.on("connect_error", err => { - console.error("Failed to connect to builder websocket:", err.message) - }) - socket.on("disconnect", () => { - userStore.actions.reset() - }) - - // User events - socket.onOther(SocketEvent.UserUpdate, ({ user }) => { - userStore.actions.updateUser(user) - }) - socket.onOther(SocketEvent.UserDisconnect, ({ sessionId }) => { - userStore.actions.removeUser(sessionId) - }) - socket.onOther(BuilderSocketEvent.LockTransfer, ({ userId }) => { - if (userId === get(auth)?.user?._id) { - appStore.update(state => ({ - ...state, - hasLock: true, - })) - } - }) - - // Data section events - socket.onOther(BuilderSocketEvent.TableChange, ({ id, table }) => { - tables.replaceTable(id, table) - }) - socket.onOther(BuilderSocketEvent.DatasourceChange, ({ id, datasource }) => { - datasources.replaceDatasource(id, datasource) - }) - - // Role events - socket.onOther(BuilderSocketEvent.RoleChange, ({ id, role }) => { - roles.replace(id, role) - }) - - // Design section events - socket.onOther(BuilderSocketEvent.ScreenChange, ({ id, screen }) => { - screenStore.replace(id, screen) - }) - - // App events - socket.onOther(BuilderSocketEvent.AppMetadataChange, ({ metadata }) => { - appStore.syncMetadata(metadata) - themeStore.syncMetadata(metadata) - navigationStore.syncMetadata(metadata) - snippets.syncMetadata(metadata) - }) - socket.onOther( - BuilderSocketEvent.AppPublishChange, - async ({ user, published }) => { - await appsStore.load() - if (published) { - await deploymentStore.load() - } - const verb = published ? "published" : "unpublished" - notifications.success(`${helpers.getUserLabel(user)} ${verb} this app`) - } - ) - - // Automation events - socket.onOther(BuilderSocketEvent.AutomationChange, ({ id, automation }) => { - automationStore.actions.replace(id, automation) - }) - - return socket -} diff --git a/packages/builder/src/stores/builder/websocket.ts b/packages/builder/src/stores/builder/websocket.ts new file mode 100644 index 0000000000..49b8067dd8 --- /dev/null +++ b/packages/builder/src/stores/builder/websocket.ts @@ -0,0 +1,124 @@ +import { createWebsocket } from "@budibase/frontend-core" +import { + automationStore, + userStore, + appStore, + themeStore, + navigationStore, + deploymentStore, + snippets, + datasources, + tables, + roles, +} from "@/stores/builder" +import { get } from "svelte/store" +import { auth, appsStore } from "@/stores/portal" +import { screenStore } from "./screens" +import { SocketEvent, BuilderSocketEvent, helpers } from "@budibase/shared-core" +import { notifications } from "@budibase/bbui" +import { Automation, Datasource, Role, Table, UIUser } from "@budibase/types" + +export const createBuilderWebsocket = (appId: string) => { + const socket = createWebsocket("/socket/builder") + + // Built-in events + socket.on("connect", () => { + socket.emit( + BuilderSocketEvent.SelectApp, + { appId }, + ({ users }: { users: UIUser[] }) => { + userStore.actions.init(users) + } + ) + }) + socket.on("connect_error", err => { + console.error("Failed to connect to builder websocket:", err.message) + }) + socket.on("disconnect", () => { + userStore.actions.reset() + }) + + // User events + socket.onOther(SocketEvent.UserUpdate, ({ user }: { user: UIUser }) => { + userStore.actions.updateUser(user) + }) + socket.onOther( + SocketEvent.UserDisconnect, + ({ sessionId }: { sessionId: string }) => { + userStore.actions.removeUser(sessionId) + } + ) + socket.onOther( + BuilderSocketEvent.LockTransfer, + ({ userId }: { userId: string }) => { + if (userId === get(auth)?.user?._id) { + appStore.update(state => ({ + ...state, + hasLock: true, + })) + } + } + ) + + // Data section events + socket.onOther( + BuilderSocketEvent.TableChange, + ({ id, table }: { id: string; table: Table }) => { + tables.replaceTable(id, table) + } + ) + socket.onOther( + BuilderSocketEvent.DatasourceChange, + ({ id, datasource }: { id: string; datasource: Datasource }) => { + datasources.replaceDatasource(id, datasource) + } + ) + + // Role events + socket.onOther( + BuilderSocketEvent.RoleChange, + ({ id, role }: { id: string; role: Role }) => { + roles.replace(id, role) + } + ) + + // Design section events + socket.onOther( + BuilderSocketEvent.ScreenChange, + ({ id, screen }: { id: string; screen: Screen }) => { + screenStore.replace(id, screen) + } + ) + + // App events + socket.onOther( + BuilderSocketEvent.AppMetadataChange, + ({ metadata }: { metadata: any }) => { + appStore.syncMetadata(metadata) + themeStore.syncMetadata(metadata) + navigationStore.syncMetadata(metadata) + snippets.syncMetadata(metadata) + } + ) + socket.onOther( + BuilderSocketEvent.AppPublishChange, + async ({ user, published }: { user: UIUser; published: boolean }) => { + await appsStore.load() + if (published) { + await deploymentStore.load() + } + const verb = published ? "published" : "unpublished" + notifications.success(`${helpers.getUserLabel(user)} ${verb} this app`) + } + ) + + // Automation events + socket.onOther( + BuilderSocketEvent.AutomationChange, + ({ id, automation }: { id: string; automation: Automation }) => { + automationStore.actions.replace(id, automation) + } + ) + + return socket +} diff --git a/packages/frontend-core/src/utils/websocket.js b/packages/frontend-core/src/utils/websocket.ts similarity index 78% rename from packages/frontend-core/src/utils/websocket.js rename to packages/frontend-core/src/utils/websocket.ts index dee679eaef..475b14176f 100644 --- a/packages/frontend-core/src/utils/websocket.js +++ b/packages/frontend-core/src/utils/websocket.ts @@ -1,12 +1,18 @@ -import { io } from "socket.io-client" +import { io, Socket } from "socket.io-client" import { SocketEvent, SocketSessionTTL } from "@budibase/shared-core" import { APISessionID } from "../api" const DefaultOptions = { heartbeat: true, } +export interface ExtendedSocket extends Socket { + onOther: (event: string, callback: (data: any) => void) => void +} -export const createWebsocket = (path, options = DefaultOptions) => { +export const createWebsocket = ( + path: string, + options = DefaultOptions +): ExtendedSocket => { if (!path) { throw "A websocket path must be provided" } @@ -32,10 +38,10 @@ export const createWebsocket = (path, options = DefaultOptions) => { // Disable polling and rely on websocket only, as HTTP transport // will only work with sticky sessions which we don't have transports: ["websocket"], - }) + }) as ExtendedSocket // Set up a heartbeat that's half of the session TTL - let interval + let interval: NodeJS.Timeout | undefined if (heartbeat) { interval = setInterval(() => { socket.emit(SocketEvent.Heartbeat) @@ -48,7 +54,7 @@ export const createWebsocket = (path, options = DefaultOptions) => { // Helper utility to ignore events that were triggered due to API // changes made by us - socket.onOther = (event, callback) => { + socket.onOther = (event: string, callback: (data: any) => void) => { socket.on(event, data => { if (data?.apiSessionId !== APISessionID) { callback(data) diff --git a/packages/types/src/ui/stores/grid/user.ts b/packages/types/src/ui/stores/grid/user.ts index b6eb529805..9625b0bb80 100644 --- a/packages/types/src/ui/stores/grid/user.ts +++ b/packages/types/src/ui/stores/grid/user.ts @@ -3,4 +3,5 @@ import { User } from "@budibase/types" export interface UIUser extends User { sessionId: string gridMetadata?: { focusedCellId?: string } + builderMetadata?: { selectedResourceId?: string } } From 8a4f42003c8702841ebc15a28884ec39b77abd04 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 3 Jan 2025 11:31:48 +0000 Subject: [PATCH 025/173] flatten actions --- packages/builder/src/stores/builder/users.ts | 21 ++++--------------- .../builder/src/stores/builder/websocket.ts | 8 +++---- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/packages/builder/src/stores/builder/users.ts b/packages/builder/src/stores/builder/users.ts index 5f0c4a3701..5350b2af90 100644 --- a/packages/builder/src/stores/builder/users.ts +++ b/packages/builder/src/stores/builder/users.ts @@ -3,31 +3,18 @@ import { BudiStore } from "../BudiStore" import { UIUser } from "@budibase/types" export class UserStore extends BudiStore { - actions: { - init: (users: UIUser[]) => void - updateUser: (user: UIUser) => void - removeUser: (sessionId: string) => void - reset: () => void - } - constructor() { super([]) - this.actions = { - init: this.init.bind(this), - updateUser: this.updateUser.bind(this), - removeUser: this.removeUser.bind(this), - reset: this.reset.bind(this), - } } init(users: UIUser[]) { - this.store.set(users) + this.set(users) } updateUser(user: UIUser) { - const $users = get(this.store) + const $users = get(this) if (!$users.some(x => x.sessionId === user.sessionId)) { - this.store.set([...$users, user]) + this.set([...$users, user]) } else { this.update(state => { const index = state.findIndex(x => x.sessionId === user.sessionId) @@ -44,7 +31,7 @@ export class UserStore extends BudiStore { } reset() { - this.store.set([]) + this.set([]) } } diff --git a/packages/builder/src/stores/builder/websocket.ts b/packages/builder/src/stores/builder/websocket.ts index 49b8067dd8..bd9e2c8d4d 100644 --- a/packages/builder/src/stores/builder/websocket.ts +++ b/packages/builder/src/stores/builder/websocket.ts @@ -27,7 +27,7 @@ export const createBuilderWebsocket = (appId: string) => { BuilderSocketEvent.SelectApp, { appId }, ({ users }: { users: UIUser[] }) => { - userStore.actions.init(users) + userStore.init(users) } ) }) @@ -35,17 +35,17 @@ export const createBuilderWebsocket = (appId: string) => { console.error("Failed to connect to builder websocket:", err.message) }) socket.on("disconnect", () => { - userStore.actions.reset() + userStore.reset() }) // User events socket.onOther(SocketEvent.UserUpdate, ({ user }: { user: UIUser }) => { - userStore.actions.updateUser(user) + userStore.updateUser(user) }) socket.onOther( SocketEvent.UserDisconnect, ({ sessionId }: { sessionId: string }) => { - userStore.actions.removeUser(sessionId) + userStore.removeUser(sessionId) } ) socket.onOther( From 428df339c4b0a6c4933fcd4221879031529a50f3 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 3 Jan 2025 16:33:51 +0000 Subject: [PATCH 026/173] Theme / Row actions / Snippers stores --- .../builder/{rowActions.js => rowActions.ts} | 57 +++++++++------- .../builder/src/stores/builder/snippets.js | 35 ---------- .../builder/src/stores/builder/snippets.ts | 32 +++++++++ packages/builder/src/stores/builder/theme.js | 58 ---------------- packages/builder/src/stores/builder/theme.ts | 67 +++++++++++++++++++ 5 files changed, 132 insertions(+), 117 deletions(-) rename packages/builder/src/stores/builder/{rowActions.js => rowActions.ts} (71%) delete mode 100644 packages/builder/src/stores/builder/snippets.js create mode 100644 packages/builder/src/stores/builder/snippets.ts delete mode 100644 packages/builder/src/stores/builder/theme.js create mode 100644 packages/builder/src/stores/builder/theme.ts diff --git a/packages/builder/src/stores/builder/rowActions.js b/packages/builder/src/stores/builder/rowActions.ts similarity index 71% rename from packages/builder/src/stores/builder/rowActions.js rename to packages/builder/src/stores/builder/rowActions.ts index 9cc4063b91..378579e41b 100644 --- a/packages/builder/src/stores/builder/rowActions.js +++ b/packages/builder/src/stores/builder/rowActions.ts @@ -6,18 +6,29 @@ import { automationStore } from "./automations" import { API } from "@/api" import { getSequentialName } from "@/helpers/duplicate" -const initialState = {} +interface RowAction { + id: string + name: string + tableId: string + allowedSources?: string[] +} -export class RowActionStore extends BudiStore { +interface RowActionState { + [tableId: string]: RowAction[] +} + +const initialState: RowActionState = {} + +export class RowActionStore extends BudiStore { constructor() { super(initialState) } reset = () => { - this.store.set(initialState) + this.set(initialState) } - refreshRowActions = async sourceId => { + refreshRowActions = async (sourceId: string) => { if (!sourceId) { return } @@ -34,26 +45,30 @@ export class RowActionStore extends BudiStore { // Fetch row actions for this table const res = await API.rowActions.fetch(tableId) - const actions = Object.values(res || {}) + const actions = Object.values(res || {}) as RowAction[] this.update(state => ({ ...state, [tableId]: actions, })) } - createRowAction = async (tableId, viewId, name) => { + createRowAction = async (tableId: string, viewId?: string, name?: string) => { if (!tableId) { return } // Get a unique name for this action if (!name) { - const existingRowActions = get(this.store)[tableId] || [] + const existingRowActions = get(this)[tableId] || [] name = getSequentialName(existingRowActions, "New row action ", { getName: x => x.name, }) } + if (!name) { + return + } + // Create the action const res = await API.rowActions.create(tableId, name) @@ -73,41 +88,35 @@ export class RowActionStore extends BudiStore { return res } - enableView = async (tableId, rowActionId, viewId) => { + enableView = async (tableId: string, rowActionId: string, viewId: string) => { await API.rowActions.enableView(tableId, rowActionId, viewId) await this.refreshRowActions(tableId) } - disableView = async (tableId, rowActionId, viewId) => { + disableView = async ( + tableId: string, + rowActionId: string, + viewId: string + ) => { await API.rowActions.disableView(tableId, rowActionId, viewId) await this.refreshRowActions(tableId) } - rename = async (tableId, rowActionId, name) => { - await API.rowActions.update({ - tableId, - rowActionId, - name, - }) - await this.refreshRowActions(tableId) - automationStore.actions.fetch() - } - - delete = async (tableId, rowActionId) => { + delete = async (tableId: string, rowActionId: string) => { await API.rowActions.delete(tableId, rowActionId) await this.refreshRowActions(tableId) // We don't need to refresh automations as we can only delete row actions // from the automations store, so we already handle the state update there } - trigger = async (sourceId, rowActionId, rowId) => { + trigger = async (sourceId: string, rowActionId: string, rowId: string) => { await API.rowActions.trigger(sourceId, rowActionId, rowId) } } const store = new RowActionStore() -const derivedStore = derived(store, $store => { - let map = {} +const derivedStore = derived(store, $store => { + const map: RowActionState = {} // Generate an entry for every view as well Object.keys($store || {}).forEach(tableId => { @@ -115,7 +124,7 @@ const derivedStore = derived(store, $store => { map[tableId] = $store[tableId] for (let action of $store[tableId]) { const otherSources = (action.allowedSources || []).filter( - sourceId => sourceId !== tableId + (sourceId: string) => sourceId !== tableId ) for (let source of otherSources) { map[source] ??= [] diff --git a/packages/builder/src/stores/builder/snippets.js b/packages/builder/src/stores/builder/snippets.js deleted file mode 100644 index 4e98ef1bdc..0000000000 --- a/packages/builder/src/stores/builder/snippets.js +++ /dev/null @@ -1,35 +0,0 @@ -import { writable, get } from "svelte/store" -import { API } from "@/api" -import { appStore } from "./app" - -const createsnippets = () => { - const store = writable([]) - - const syncMetadata = metadata => { - store.set(metadata?.snippets || []) - } - - const saveSnippet = async updatedSnippet => { - const snippets = [ - ...get(store).filter(snippet => snippet.name !== updatedSnippet.name), - updatedSnippet, - ] - const app = await API.saveAppMetadata(get(appStore).appId, { snippets }) - syncMetadata(app) - } - - const deleteSnippet = async snippetName => { - const snippets = get(store).filter(snippet => snippet.name !== snippetName) - const app = await API.saveAppMetadata(get(appStore).appId, { snippets }) - syncMetadata(app) - } - - return { - ...store, - syncMetadata, - saveSnippet, - deleteSnippet, - } -} - -export const snippets = createsnippets() diff --git a/packages/builder/src/stores/builder/snippets.ts b/packages/builder/src/stores/builder/snippets.ts new file mode 100644 index 0000000000..a6a63f7c89 --- /dev/null +++ b/packages/builder/src/stores/builder/snippets.ts @@ -0,0 +1,32 @@ +import { get } from "svelte/store" +import { API } from "@/api" +import { appStore } from "./app" +import { BudiStore } from "../BudiStore" +import { Snippet, UpdateAppResponse } from "@budibase/types" + +export class SnippetStore extends BudiStore { + constructor() { + super([]) + } + + syncMetadata = (metadata: UpdateAppResponse) => { + this.set(metadata?.snippets || []) + } + + saveSnippet = async (updatedSnippet: Snippet) => { + const snippets = [ + ...get(this).filter(snippet => snippet.name !== updatedSnippet.name), + updatedSnippet, + ] + const app = await API.saveAppMetadata(get(appStore).appId, { snippets }) + this.syncMetadata(app) + } + + deleteSnippet = async (snippetName: string) => { + const snippets = get(this).filter(snippet => snippet.name !== snippetName) + const app = await API.saveAppMetadata(get(appStore).appId, { snippets }) + this.syncMetadata(app) + } +} + +export const snippets = new SnippetStore() diff --git a/packages/builder/src/stores/builder/theme.js b/packages/builder/src/stores/builder/theme.js deleted file mode 100644 index ed46e9095a..0000000000 --- a/packages/builder/src/stores/builder/theme.js +++ /dev/null @@ -1,58 +0,0 @@ -import { writable, get } from "svelte/store" -import { API } from "@/api" -import { ensureValidTheme, DefaultAppTheme } from "@budibase/shared-core" - -export const createThemeStore = () => { - const store = writable({ - theme: DefaultAppTheme, - customTheme: {}, - }) - - const syncAppTheme = app => { - store.update(state => { - const theme = ensureValidTheme(app.theme, DefaultAppTheme) - return { - ...state, - theme, - customTheme: app.customTheme, - } - }) - } - - const save = async (theme, appId) => { - const app = await API.saveAppMetadata(appId, { theme }) - store.update(state => { - state.theme = app.theme - return state - }) - } - - const saveCustom = async (theme, appId) => { - const updated = { ...get(store).customTheme, ...theme } - const app = await API.saveAppMetadata(appId, { customTheme: updated }) - store.update(state => { - state.customTheme = app.customTheme - return state - }) - } - - const syncMetadata = metadata => { - const { theme, customTheme } = metadata - store.update(state => ({ - ...state, - theme: ensureValidTheme(theme, DefaultAppTheme), - customTheme, - })) - } - - return { - subscribe: store.subscribe, - update: store.update, - syncMetadata, - syncAppTheme, - save, - saveCustom, - } -} - -export const themeStore = createThemeStore() diff --git a/packages/builder/src/stores/builder/theme.ts b/packages/builder/src/stores/builder/theme.ts new file mode 100644 index 0000000000..b3ac202a5d --- /dev/null +++ b/packages/builder/src/stores/builder/theme.ts @@ -0,0 +1,67 @@ +import { get } from "svelte/store" +import { API } from "@/api" +import { BudiStore } from "../BudiStore" +import { ensureValidTheme, DefaultAppTheme } from "@budibase/shared-core" +import { App, UpdateAppResponse, Theme, AppCustomTheme } from "@budibase/types" + +interface ThemeState { + theme: Theme + customTheme: AppCustomTheme +} + +export class ThemeStore extends BudiStore { + constructor() { + super({ + theme: DefaultAppTheme as Theme, + customTheme: {}, + }) + } + + syncAppTheme = (app: App) => { + this.update(state => { + const theme = ensureValidTheme( + app.theme as Theme | undefined, + DefaultAppTheme + ) as Theme + return { + ...state, + theme, + customTheme: app.customTheme || {}, + } + }) + } + + save = async (theme: Theme, appId: string) => { + const app = await API.saveAppMetadata(appId, { theme }) + this.update(state => ({ + ...state, + theme: ensureValidTheme( + app.theme as Theme | undefined, + DefaultAppTheme + ) as Theme, + })) + } + + saveCustom = async (theme: Partial, appId: string) => { + const updated = { ...get(this).customTheme, ...theme } + const app = await API.saveAppMetadata(appId, { customTheme: updated }) + this.update(state => ({ + ...state, + customTheme: app.customTheme || {}, + })) + } + + syncMetadata = (metadata: UpdateAppResponse) => { + const { theme, customTheme } = metadata + this.update(state => ({ + ...state, + theme: ensureValidTheme( + theme as Theme | undefined, + DefaultAppTheme + ) as Theme, + customTheme: customTheme || {}, + })) + } +} + +export const themeStore = new ThemeStore() From 47c87a6650ef5b25b07d3be9b0d5d91ccfcfdcd5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Jan 2025 02:27:34 +0000 Subject: [PATCH 027/173] Bump next from 14.2.15 to 14.2.21 in /examples/nextjs-api-sales Bumps [next](https://github.com/vercel/next.js) from 14.2.15 to 14.2.21. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v14.2.15...v14.2.21) --- updated-dependencies: - dependency-name: next dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- examples/nextjs-api-sales/package.json | 2 +- examples/nextjs-api-sales/yarn.lock | 108 ++++++++++++------------- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/examples/nextjs-api-sales/package.json b/examples/nextjs-api-sales/package.json index 1050c6b75e..d50e7d4eb5 100644 --- a/examples/nextjs-api-sales/package.json +++ b/examples/nextjs-api-sales/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "bulma": "^0.9.3", - "next": "14.2.15", + "next": "14.2.21", "node-fetch": "^3.2.10", "sass": "^1.52.3", "react": "17.0.2", diff --git a/examples/nextjs-api-sales/yarn.lock b/examples/nextjs-api-sales/yarn.lock index b595a148bf..a10fccb2e9 100644 --- a/examples/nextjs-api-sales/yarn.lock +++ b/examples/nextjs-api-sales/yarn.lock @@ -46,10 +46,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@next/env@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.15.tgz#06d984e37e670d93ddd6790af1844aeb935f332f" - integrity sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ== +"@next/env@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.21.tgz#09ff0813d29c596397e141205d4f5fd5c236bdd0" + integrity sha512-lXcwcJd5oR01tggjWJ6SrNNYFGuOOMB9c251wUNkjCpkoXOPkDeF/15c3mnVlBqrW4JJXb2kVxDFhC4GduJt2A== "@next/eslint-plugin-next@12.1.0": version "12.1.0" @@ -58,50 +58,50 @@ dependencies: glob "7.1.7" -"@next/swc-darwin-arm64@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.15.tgz#6386d585f39a1c490c60b72b1f76612ba4434347" - integrity sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA== +"@next/swc-darwin-arm64@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.21.tgz#32a31992aace1440981df9cf7cb3af7845d94fec" + integrity sha512-HwEjcKsXtvszXz5q5Z7wCtrHeTTDSTgAbocz45PHMUjU3fBYInfvhR+ZhavDRUYLonm53aHZbB09QtJVJj8T7g== -"@next/swc-darwin-x64@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.15.tgz#b7baeedc6a28f7545ad2bc55adbab25f7b45cb89" - integrity sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg== +"@next/swc-darwin-x64@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.21.tgz#5ab4b3f6685b6b52f810d0f5cf6e471480ddffdb" + integrity sha512-TSAA2ROgNzm4FhKbTbyJOBrsREOMVdDIltZ6aZiKvCi/v0UwFmwigBGeqXDA97TFMpR3LNNpw52CbVelkoQBxA== -"@next/swc-linux-arm64-gnu@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.15.tgz#fa13c59d3222f70fb4cb3544ac750db2c6e34d02" - integrity sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw== +"@next/swc-linux-arm64-gnu@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.21.tgz#8a0e1fa887aef19ca218af2af515d0a5ee67ba3f" + integrity sha512-0Dqjn0pEUz3JG+AImpnMMW/m8hRtl1GQCNbO66V1yp6RswSTiKmnHf3pTX6xMdJYSemf3O4Q9ykiL0jymu0TuA== -"@next/swc-linux-arm64-musl@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.15.tgz#30e45b71831d9a6d6d18d7ac7d611a8d646a17f9" - integrity sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ== +"@next/swc-linux-arm64-musl@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.21.tgz#ddad844406b42fa8965fe11250abc85c1fe0fd05" + integrity sha512-Ggfw5qnMXldscVntwnjfaQs5GbBbjioV4B4loP+bjqNEb42fzZlAaK+ldL0jm2CTJga9LynBMhekNfV8W4+HBw== -"@next/swc-linux-x64-gnu@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.15.tgz#5065db17fc86f935ad117483f21f812dc1b39254" - integrity sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA== +"@next/swc-linux-x64-gnu@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.21.tgz#db55fd666f9ba27718f65caa54b622a912cdd16b" + integrity sha512-uokj0lubN1WoSa5KKdThVPRffGyiWlm/vCc/cMkWOQHw69Qt0X1o3b2PyLLx8ANqlefILZh1EdfLRz9gVpG6tg== -"@next/swc-linux-x64-musl@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.15.tgz#3c4a4568d8be7373a820f7576cf33388b5dab47e" - integrity sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ== +"@next/swc-linux-x64-musl@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.21.tgz#dddb850353624efcd58c4c4e30ad8a1aab379642" + integrity sha512-iAEBPzWNbciah4+0yI4s7Pce6BIoxTQ0AGCkxn/UBuzJFkYyJt71MadYQkjPqCQCJAFQ26sYh7MOKdU+VQFgPg== -"@next/swc-win32-arm64-msvc@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.15.tgz#fb812cc4ca0042868e32a6a021da91943bb08b98" - integrity sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g== +"@next/swc-win32-arm64-msvc@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.21.tgz#290012ee57b196d3d2d04853e6bf0179cae9fbaf" + integrity sha512-plykgB3vL2hB4Z32W3ktsfqyuyGAPxqwiyrAi2Mr8LlEUhNn9VgkiAl5hODSBpzIfWweX3er1f5uNpGDygfQVQ== -"@next/swc-win32-ia32-msvc@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.15.tgz#ec26e6169354f8ced240c1427be7fd485c5df898" - integrity sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ== +"@next/swc-win32-ia32-msvc@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.21.tgz#c959135a78cab18cca588d11d1e33bcf199590d4" + integrity sha512-w5bacz4Vxqrh06BjWgua3Yf7EMDb8iMcVhNrNx8KnJXt8t+Uu0Zg4JHLDL/T7DkTCEEfKXO/Er1fcfWxn2xfPA== -"@next/swc-win32-x64-msvc@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.15.tgz#18d68697002b282006771f8d92d79ade9efd35c4" - integrity sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g== +"@next/swc-win32-x64-msvc@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.21.tgz#21ff892286555b90538a7d1b505ea21a005d6ead" + integrity sha512-sT6+llIkzpsexGYZq8cjjthRyRGe5cJVhqh12FmlbxHqna6zsDDK8UNaV7g41T6atFHCJUPeLb3uyAwrBwy0NA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1253,12 +1253,12 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -next@14.2.15: - version "14.2.15" - resolved "https://registry.yarnpkg.com/next/-/next-14.2.15.tgz#348e5603e22649775d19c785c09a89c9acb5189a" - integrity sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw== +next@14.2.21: + version "14.2.21" + resolved "https://registry.yarnpkg.com/next/-/next-14.2.21.tgz#f6da9e2abba1a0e4ca7a5273825daf06632554ba" + integrity sha512-rZmLwucLHr3/zfDMYbJXbw0ZeoBpirxkXuvsJbk7UPorvPYZhP7vq7aHbKnU7dQNCYIimRrbB2pp3xmf+wsYUg== dependencies: - "@next/env" "14.2.15" + "@next/env" "14.2.21" "@swc/helpers" "0.5.5" busboy "1.6.0" caniuse-lite "^1.0.30001579" @@ -1266,15 +1266,15 @@ next@14.2.15: postcss "8.4.31" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-darwin-arm64" "14.2.15" - "@next/swc-darwin-x64" "14.2.15" - "@next/swc-linux-arm64-gnu" "14.2.15" - "@next/swc-linux-arm64-musl" "14.2.15" - "@next/swc-linux-x64-gnu" "14.2.15" - "@next/swc-linux-x64-musl" "14.2.15" - "@next/swc-win32-arm64-msvc" "14.2.15" - "@next/swc-win32-ia32-msvc" "14.2.15" - "@next/swc-win32-x64-msvc" "14.2.15" + "@next/swc-darwin-arm64" "14.2.21" + "@next/swc-darwin-x64" "14.2.21" + "@next/swc-linux-arm64-gnu" "14.2.21" + "@next/swc-linux-arm64-musl" "14.2.21" + "@next/swc-linux-x64-gnu" "14.2.21" + "@next/swc-linux-x64-musl" "14.2.21" + "@next/swc-win32-arm64-msvc" "14.2.21" + "@next/swc-win32-ia32-msvc" "14.2.21" + "@next/swc-win32-x64-msvc" "14.2.21" node-domexception@^1.0.0: version "1.0.0" From 4469e38ab87725b1ed09122b5dc5f890c91b06e3 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 6 Jan 2025 10:27:37 +0000 Subject: [PATCH 028/173] Fix triggering automations --- packages/client/src/utils/buttonActions.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 9d0bddcc92..16dc3c97e7 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -216,11 +216,11 @@ const deleteRowHandler = async action => { const triggerAutomationHandler = async action => { const { fields, notificationOverride, timeout } = action.parameters try { - const result = await API.triggerAutomation({ - automationId: action.parameters.automationId, + const result = await API.triggerAutomation( + action.parameters.automationId, fields, - timeout, - }) + timeout + ) // Value will exist if automation is synchronous, so return it. if (result.value) { From f2440f3727a76e81f0ad534d852309b4a559aa0d Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 6 Jan 2025 10:34:57 +0000 Subject: [PATCH 029/173] convert roles stores to typescript --- packages/builder/src/stores/builder/roles.js | 88 ---------------- packages/builder/src/stores/builder/roles.ts | 104 +++++++++++++++++++ 2 files changed, 104 insertions(+), 88 deletions(-) delete mode 100644 packages/builder/src/stores/builder/roles.js create mode 100644 packages/builder/src/stores/builder/roles.ts diff --git a/packages/builder/src/stores/builder/roles.js b/packages/builder/src/stores/builder/roles.js deleted file mode 100644 index e718545f14..0000000000 --- a/packages/builder/src/stores/builder/roles.js +++ /dev/null @@ -1,88 +0,0 @@ -import { derived, writable, get } from "svelte/store" -import { API } from "@/api" -import { RoleUtils } from "@budibase/frontend-core" - -export function createRolesStore() { - const store = writable([]) - const enriched = derived(store, $store => { - return $store.map(role => ({ - ...role, - - // Ensure we have new metadata for all roles - uiMetadata: { - displayName: role.uiMetadata?.displayName || role.name, - color: - role.uiMetadata?.color || "var(--spectrum-global-color-magenta-400)", - description: role.uiMetadata?.description || "Custom role", - }, - })) - }) - - function setRoles(roles) { - store.set( - roles.sort((a, b) => { - const priorityA = RoleUtils.getRolePriority(a._id) - const priorityB = RoleUtils.getRolePriority(b._id) - if (priorityA !== priorityB) { - return priorityA > priorityB ? -1 : 1 - } - const nameA = a.uiMetadata?.displayName || a.name - const nameB = b.uiMetadata?.displayName || b.name - return nameA < nameB ? -1 : 1 - }) - ) - } - - const actions = { - fetch: async () => { - const roles = await API.getRoles() - setRoles(roles) - }, - fetchByAppId: async appId => { - const { roles } = await API.getRolesForApp(appId) - setRoles(roles) - }, - delete: async role => { - await API.deleteRole(role._id, role._rev) - await actions.fetch() - }, - save: async role => { - const savedRole = await API.saveRole(role) - await actions.fetch() - return savedRole - }, - replace: (roleId, role) => { - // Handles external updates of roles - if (!roleId) { - return - } - - // Handle deletion - if (!role) { - store.update(state => state.filter(x => x._id !== roleId)) - return - } - - // Add new role - const index = get(store).findIndex(x => x._id === role._id) - if (index === -1) { - store.update(state => [...state, role]) - } - - // Update existing role - else if (role) { - store.update(state => { - state[index] = role - return [...state] - }) - } - }, - } - - return { - subscribe: enriched.subscribe, - ...actions, - } -} - -export const roles = createRolesStore() diff --git a/packages/builder/src/stores/builder/roles.ts b/packages/builder/src/stores/builder/roles.ts new file mode 100644 index 0000000000..ea34fdef53 --- /dev/null +++ b/packages/builder/src/stores/builder/roles.ts @@ -0,0 +1,104 @@ +import { derived, get } from "svelte/store" +import { API } from "@/api" +import { RoleUtils } from "@budibase/frontend-core" +import { BudiStore } from "../BudiStore" +import { Role } from "@budibase/types" + +interface RoleWithMetadata extends Role { + uiMetadata?: { + displayName?: string + color?: string + description?: string + } +} + +export class RoleStore extends BudiStore { + constructor() { + super([]) + } + + enriched = derived(this, $store => { + return $store.map(role => ({ + ...role, + // Ensure we have new metadata for all roles + uiMetadata: { + displayName: role.uiMetadata?.displayName || role.name, + color: + role.uiMetadata?.color || "var(--spectrum-global-color-magenta-400)", + description: role.uiMetadata?.description || "Custom role", + }, + })) + }) + + private setRoles = (roles: RoleWithMetadata[]) => { + this.set( + roles.sort((a, b) => { + // Ensure we have valid IDs for priority comparison + const priorityA = RoleUtils.getRolePriority(a._id) + const priorityB = RoleUtils.getRolePriority(b._id) + if (priorityA !== priorityB) { + return priorityA > priorityB ? -1 : 1 + } + const nameA = a.uiMetadata?.displayName || a.name + const nameB = b.uiMetadata?.displayName || b.name + return nameA < nameB ? -1 : 1 + }) + ) + } + + fetch = async () => { + const roles = await API.getRoles() + this.setRoles(roles) + } + + fetchByAppId = async (appId: string) => { + const { roles } = await API.getRolesForApp(appId) + this.setRoles(roles) + } + + delete = async (role: RoleWithMetadata) => { + if (!role._id || !role._rev) { + return + } + await API.deleteRole(role._id, role._rev) + await this.fetch() + } + + save = async (role: RoleWithMetadata) => { + const savedRole = await API.saveRole(role) + await this.fetch() + return savedRole + } + + replace = (roleId: string, role?: RoleWithMetadata) => { + // Handles external updates of roles + if (!roleId) { + return + } + + // Handle deletion + if (!role) { + this.update(state => state.filter(x => x._id !== roleId)) + return + } + + // Add new role + const index = get(this).findIndex(x => x._id === role._id) + if (index === -1) { + this.update(state => [...state, role]) + } + // Update existing role + else if (role) { + this.update(state => { + state[index] = role + return [...state] + }) + } + } +} + +const store = new RoleStore() +export const roles = { + ...store, + subscribe: store.enriched.subscribe, +} From 1248e55bc2e2969a9075b3e94f3341da7382e3ee Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 6 Jan 2025 11:35:46 +0000 Subject: [PATCH 030/173] use correct type --- packages/builder/src/stores/builder/roles.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/packages/builder/src/stores/builder/roles.ts b/packages/builder/src/stores/builder/roles.ts index ea34fdef53..95ea63a997 100644 --- a/packages/builder/src/stores/builder/roles.ts +++ b/packages/builder/src/stores/builder/roles.ts @@ -4,15 +4,7 @@ import { RoleUtils } from "@budibase/frontend-core" import { BudiStore } from "../BudiStore" import { Role } from "@budibase/types" -interface RoleWithMetadata extends Role { - uiMetadata?: { - displayName?: string - color?: string - description?: string - } -} - -export class RoleStore extends BudiStore { +export class RoleStore extends BudiStore { constructor() { super([]) } @@ -30,7 +22,7 @@ export class RoleStore extends BudiStore { })) }) - private setRoles = (roles: RoleWithMetadata[]) => { + private setRoles = (roles: Role[]) => { this.set( roles.sort((a, b) => { // Ensure we have valid IDs for priority comparison @@ -56,7 +48,7 @@ export class RoleStore extends BudiStore { this.setRoles(roles) } - delete = async (role: RoleWithMetadata) => { + delete = async (role: Role) => { if (!role._id || !role._rev) { return } @@ -64,13 +56,13 @@ export class RoleStore extends BudiStore { await this.fetch() } - save = async (role: RoleWithMetadata) => { + save = async (role: Role) => { const savedRole = await API.saveRole(role) await this.fetch() return savedRole } - replace = (roleId: string, role?: RoleWithMetadata) => { + replace = (roleId: string, role?: Role) => { // Handles external updates of roles if (!roleId) { return From a58c75e328f0b4aa0f2ebfb47a1df3275d2b541d Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 6 Jan 2025 12:11:14 +0000 Subject: [PATCH 031/173] Expose feature flags type in packages/type so it can be exposed to the frontend. --- .../backend-core/src/context/mainContext.ts | 8 +- packages/backend-core/src/context/types.ts | 2 +- .../backend-core/src/features/features.ts | 135 ++++-------------- .../src/features/tests/features.spec.ts | 28 +--- packages/pro | 2 +- .../src/api/controllers/row/staticFormula.ts | 4 +- packages/server/src/automations/actions.ts | 6 +- .../server/src/automations/steps/openai.ts | 4 +- .../server/src/middleware/zod-validator.ts | 2 +- packages/types/src/api/web/global/self.ts | 3 +- packages/types/src/sdk/featureFlag.ts | 10 +- .../worker/src/api/controllers/global/self.ts | 3 +- 12 files changed, 57 insertions(+), 150 deletions(-) diff --git a/packages/backend-core/src/context/mainContext.ts b/packages/backend-core/src/context/mainContext.ts index 64ba240fa5..e5f20882d3 100644 --- a/packages/backend-core/src/context/mainContext.ts +++ b/packages/backend-core/src/context/mainContext.ts @@ -385,17 +385,17 @@ export function getCurrentContext(): ContextMap | undefined { } } -export function getFeatureFlags>( +export function getFeatureFlags( key: string -): T | undefined { +): Record | undefined { const context = getCurrentContext() if (!context) { return undefined } - return context.featureFlagCache?.[key] as T + return context.featureFlagCache?.[key] } -export function setFeatureFlags(key: string, value: Record) { +export function setFeatureFlags(key: string, value: Record) { const context = getCurrentContext() if (!context) { return diff --git a/packages/backend-core/src/context/types.ts b/packages/backend-core/src/context/types.ts index 5549a47ff7..23598b951e 100644 --- a/packages/backend-core/src/context/types.ts +++ b/packages/backend-core/src/context/types.ts @@ -20,7 +20,7 @@ export type ContextMap = { clients: Record } featureFlagCache?: { - [key: string]: Record + [key: string]: Record } viewToTableCache?: Record } diff --git a/packages/backend-core/src/features/features.ts b/packages/backend-core/src/features/features.ts index 650254fcb2..772bcf5860 100644 --- a/packages/backend-core/src/features/features.ts +++ b/packages/backend-core/src/features/features.ts @@ -2,9 +2,10 @@ import env from "../environment" import * as crypto from "crypto" import * as context from "../context" import { PostHog, PostHogOptions } from "posthog-node" -import { FeatureFlag } from "@budibase/types" import tracer from "dd-trace" import { Duration } from "../utils" +import { cloneDeep } from "lodash" +import { FeatureFlagDefaults } from "@budibase/types" let posthog: PostHog | undefined export function init(opts?: PostHogOptions) { @@ -30,74 +31,6 @@ export function shutdown() { posthog?.shutdown() } -export abstract class Flag { - static boolean(defaultValue: boolean): Flag { - return new BooleanFlag(defaultValue) - } - - static string(defaultValue: string): Flag { - return new StringFlag(defaultValue) - } - - static number(defaultValue: number): Flag { - return new NumberFlag(defaultValue) - } - - protected constructor(public defaultValue: T) {} - - abstract parse(value: any): T -} - -type UnwrapFlag = F extends Flag ? U : never - -export type FlagValues = { - [K in keyof T]: UnwrapFlag -} - -type KeysOfType = { - [K in keyof T]: T[K] extends Flag ? K : never -}[keyof T] - -class BooleanFlag extends Flag { - parse(value: any) { - if (typeof value === "string") { - return ["true", "t", "1"].includes(value.toLowerCase()) - } - - if (typeof value === "boolean") { - return value - } - - throw new Error(`could not parse value "${value}" as boolean`) - } -} - -class StringFlag extends Flag { - parse(value: any) { - if (typeof value === "string") { - return value - } - throw new Error(`could not parse value "${value}" as string`) - } -} - -class NumberFlag extends Flag { - parse(value: any) { - if (typeof value === "number") { - return value - } - - if (typeof value === "string") { - const parsed = parseFloat(value) - if (!isNaN(parsed)) { - return parsed - } - } - - throw new Error(`could not parse value "${value}" as number`) - } -} - export interface EnvFlagEntry { tenantId: string key: string @@ -120,7 +53,7 @@ export function parseEnvFlags(flags: string): EnvFlagEntry[] { return result } -export class FlagSet, T extends { [key: string]: V }> { +export class FlagSet { // This is used to safely cache flags sets in the current request context. // Because multiple sets could theoretically exist, we don't want the cache of // one to leak into another. @@ -130,34 +63,25 @@ export class FlagSet, T extends { [key: string]: V }> { this.setId = crypto.randomUUID() } - defaults(): FlagValues { - return Object.keys(this.flagSchema).reduce((acc, key) => { - const typedKey = key as keyof T - acc[typedKey] = this.flagSchema[key].defaultValue - return acc - }, {} as FlagValues) + defaults(): T { + return cloneDeep(this.flagSchema) } isFlagName(name: string | number | symbol): name is keyof T { return this.flagSchema[name as keyof T] !== undefined } - async get(key: K): Promise[K]> { + async isEnabled(key: K): Promise { const flags = await this.fetch() return flags[key] } - async isEnabled>(key: K): Promise { - const flags = await this.fetch() - return flags[key] - } - - async fetch(): Promise> { + async fetch(): Promise { return await tracer.trace("features.fetch", async span => { - const cachedFlags = context.getFeatureFlags>(this.setId) + const cachedFlags = context.getFeatureFlags(this.setId) if (cachedFlags) { span?.addTags({ fromCache: true }) - return cachedFlags + return cachedFlags as T } const tags: Record = {} @@ -189,7 +113,7 @@ export class FlagSet, T extends { [key: string]: V }> { // @ts-expect-error - TS does not like you writing into a generic type, // but we know that it's okay in this case because it's just an object. - flagValues[key as keyof FlagValues] = value + flagValues[key as keyof T] = value tags[`flags.${key}.source`] = "environment" } @@ -217,11 +141,11 @@ export class FlagSet, T extends { [key: string]: V }> { tags[`readFromPostHog`] = true const personProperties: Record = { tenantId } - const posthogFlags = await posthog.getAllFlagsAndPayloads(userId, { + const posthogFlags = await posthog.getAllFlags(userId, { personProperties, }) - for (const [name, value] of Object.entries(posthogFlags.featureFlags)) { + for (const [name, value] of Object.entries(posthogFlags)) { if (!this.isFlagName(name)) { // We don't want an unexpected PostHog flag to break the app, so we // just log it and continue. @@ -229,19 +153,20 @@ export class FlagSet, T extends { [key: string]: V }> { continue } + if (typeof value !== "boolean") { + console.warn(`Invalid value for posthog flag "${name}": ${value}`) + continue + } + if (flagValues[name] === true || specificallySetFalse.has(name)) { // If the flag is already set to through environment variables, we // don't want to override it back to false here. continue } - const payload = posthogFlags.featureFlagPayloads?.[name] - const flag = this.flagSchema[name] try { - // @ts-expect-error - TS does not like you writing into a generic - // type, but we know that it's okay in this case because it's just - // an object. - flagValues[name] = flag.parse(payload || value) + // @ts-expect-error - TS does not like you writing into a generic type. + flagValues[name] = value tags[`flags.${name}.source`] = "posthog" } catch (err) { // We don't want an invalid PostHog flag to break the app, so we just @@ -262,18 +187,12 @@ export class FlagSet, T extends { [key: string]: V }> { } } -// This is the primary source of truth for feature flags. If you want to add a -// new flag, add it here and use the `fetch` and `get` functions to access it. -// All of the machinery in this file is to make sure that flags have their -// default values set correctly and their types flow through the system. -const flagsConfig: Record> = { - [FeatureFlag.DEFAULT_VALUES]: Flag.boolean(true), - [FeatureFlag.AUTOMATION_BRANCHING]: Flag.boolean(true), - [FeatureFlag.AI_CUSTOM_CONFIGS]: Flag.boolean(true), - [FeatureFlag.BUDIBASE_AI]: Flag.boolean(true), - [FeatureFlag.USE_ZOD_VALIDATOR]: Flag.boolean(env.isDev()), -} -export const flags = new FlagSet(flagsConfig) +export const flags = new FlagSet(FeatureFlagDefaults) -type UnwrapPromise = T extends Promise ? U : T -export type FeatureFlags = UnwrapPromise> +export async function isEnabled(flag: keyof typeof FeatureFlagDefaults) { + return await flags.isEnabled(flag) +} + +export async function all() { + return await flags.fetch() +} diff --git a/packages/backend-core/src/features/tests/features.spec.ts b/packages/backend-core/src/features/tests/features.spec.ts index ced874f4af..f918347eea 100644 --- a/packages/backend-core/src/features/tests/features.spec.ts +++ b/packages/backend-core/src/features/tests/features.spec.ts @@ -1,5 +1,5 @@ import { IdentityContext, IdentityType } from "@budibase/types" -import { Flag, FlagSet, FlagValues, init, shutdown } from "../" +import { FlagSet, init, shutdown } from "../" import * as context from "../../context" import environment, { withEnv } from "../../environment" import nodeFetch from "node-fetch" @@ -7,10 +7,8 @@ import nock from "nock" import * as crypto from "crypto" const schema = { - TEST_BOOLEAN: Flag.boolean(false), - TEST_STRING: Flag.string("default value"), - TEST_NUMBER: Flag.number(0), - TEST_BOOLEAN_DEFAULT_TRUE: Flag.boolean(true), + TEST_BOOLEAN: false, + TEST_BOOLEAN_DEFAULT_TRUE: true, } const flags = new FlagSet(schema) @@ -19,7 +17,7 @@ interface TestCase { identity?: Partial environmentFlags?: string posthogFlags?: PostHogFlags - expected?: Partial> + expected?: Partial errorMessage?: string | RegExp } @@ -83,22 +81,6 @@ describe("feature flags", () => { }, expected: { TEST_BOOLEAN: true }, }, - { - it: "should be able to read string flags from PostHog", - posthogFlags: { - featureFlags: { TEST_STRING: true }, - featureFlagPayloads: { TEST_STRING: "test" }, - }, - expected: { TEST_STRING: "test" }, - }, - { - it: "should be able to read numeric flags from PostHog", - posthogFlags: { - featureFlags: { TEST_NUMBER: true }, - featureFlagPayloads: { TEST_NUMBER: "123" }, - }, - expected: { TEST_NUMBER: 123 }, - }, { it: "should not be able to override a negative environment flag from PostHog", environmentFlags: "default:!TEST_BOOLEAN", @@ -177,7 +159,7 @@ describe("feature flags", () => { expect(values).toMatchObject(expected) for (const [key, expectedValue] of Object.entries(expected)) { - const value = await flags.get(key as keyof typeof schema) + const value = await flags.isEnabled(key as keyof typeof schema) expect(value).toBe(expectedValue) } } else { diff --git a/packages/pro b/packages/pro index ae786121d9..9091868986 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit ae786121d923449b0ad5fcbd123d0a9fec28f65e +Subproject commit 9091868986fbc6aae580280f48853482e0b06c6a diff --git a/packages/server/src/api/controllers/row/staticFormula.ts b/packages/server/src/api/controllers/row/staticFormula.ts index 4464b7f44a..b81a164807 100644 --- a/packages/server/src/api/controllers/row/staticFormula.ts +++ b/packages/server/src/api/controllers/row/staticFormula.ts @@ -163,9 +163,9 @@ export async function finaliseRow( contextRows: [enrichedRow], }) const aiEnabled = - ((await features.flags.isEnabled(FeatureFlag.BUDIBASE_AI)) && + ((await features.isEnabled(FeatureFlag.BUDIBASE_AI)) && (await pro.features.isBudibaseAIEnabled())) || - ((await features.flags.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) && + ((await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) && (await pro.features.isAICustomConfigsEnabled())) if (aiEnabled) { row = await processAIColumns(table, row, { diff --git a/packages/server/src/automations/actions.ts b/packages/server/src/automations/actions.ts index e5a1c63b7d..1c201d1f64 100644 --- a/packages/server/src/automations/actions.ts +++ b/packages/server/src/automations/actions.ts @@ -105,13 +105,13 @@ if (env.SELF_HOSTED) { export async function getActionDefinitions(): Promise< Record > { - if (await features.flags.isEnabled(FeatureFlag.AUTOMATION_BRANCHING)) { + if (await features.isEnabled(FeatureFlag.AUTOMATION_BRANCHING)) { BUILTIN_ACTION_DEFINITIONS["BRANCH"] = branch.definition } if ( env.SELF_HOSTED || - (await features.flags.isEnabled(FeatureFlag.BUDIBASE_AI)) || - (await features.flags.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) + (await features.isEnabled(FeatureFlag.BUDIBASE_AI)) || + (await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) ) { BUILTIN_ACTION_DEFINITIONS["OPENAI"] = openai.definition } diff --git a/packages/server/src/automations/steps/openai.ts b/packages/server/src/automations/steps/openai.ts index 48eaa93057..19595cc0d0 100644 --- a/packages/server/src/automations/steps/openai.ts +++ b/packages/server/src/automations/steps/openai.ts @@ -100,10 +100,10 @@ export async function run({ try { let response const customConfigsEnabled = - (await features.flags.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) && + (await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) && (await pro.features.isAICustomConfigsEnabled()) const budibaseAIEnabled = - (await features.flags.isEnabled(FeatureFlag.BUDIBASE_AI)) && + (await features.isEnabled(FeatureFlag.BUDIBASE_AI)) && (await pro.features.isBudibaseAIEnabled()) let llmWrapper diff --git a/packages/server/src/middleware/zod-validator.ts b/packages/server/src/middleware/zod-validator.ts index e8cc2c470a..d57e1c48ff 100644 --- a/packages/server/src/middleware/zod-validator.ts +++ b/packages/server/src/middleware/zod-validator.ts @@ -7,7 +7,7 @@ import { fromZodError } from "zod-validation-error" function validate(schema: AnyZodObject, property: "body" | "params") { // Return a Koa middleware function return async (ctx: Ctx, next: any) => { - if (!(await features.flags.isEnabled(FeatureFlag.USE_ZOD_VALIDATOR))) { + if (!(await features.isEnabled(FeatureFlag.USE_ZOD_VALIDATOR))) { return next() } diff --git a/packages/types/src/api/web/global/self.ts b/packages/types/src/api/web/global/self.ts index 5f21a8ddc5..d2c79bdba3 100644 --- a/packages/types/src/api/web/global/self.ts +++ b/packages/types/src/api/web/global/self.ts @@ -1,3 +1,4 @@ +import { FeatureFlags } from "packages/types/src/sdk" import { DevInfo, User } from "../../../documents" export interface GenerateAPIKeyRequest { @@ -8,5 +9,5 @@ export interface GenerateAPIKeyResponse extends DevInfo {} export interface FetchAPIKeyResponse extends DevInfo {} export interface GetGlobalSelfResponse extends User { - flags?: Record + flags?: FeatureFlags } diff --git a/packages/types/src/sdk/featureFlag.ts b/packages/types/src/sdk/featureFlag.ts index 98e744324c..725ae0feb1 100644 --- a/packages/types/src/sdk/featureFlag.ts +++ b/packages/types/src/sdk/featureFlag.ts @@ -6,6 +6,12 @@ export enum FeatureFlag { USE_ZOD_VALIDATOR = "USE_ZOD_VALIDATOR", } -export interface TenantFeatureFlags { - [key: string]: FeatureFlag[] +export const FeatureFlagDefaults = { + [FeatureFlag.DEFAULT_VALUES]: true, + [FeatureFlag.AUTOMATION_BRANCHING]: true, + [FeatureFlag.AI_CUSTOM_CONFIGS]: true, + [FeatureFlag.BUDIBASE_AI]: true, + [FeatureFlag.USE_ZOD_VALIDATOR]: false, } + +export type FeatureFlags = typeof FeatureFlagDefaults diff --git a/packages/worker/src/api/controllers/global/self.ts b/packages/worker/src/api/controllers/global/self.ts index f8488f526b..eb704ccf02 100644 --- a/packages/worker/src/api/controllers/global/self.ts +++ b/packages/worker/src/api/controllers/global/self.ts @@ -111,8 +111,7 @@ export async function getSelf(ctx: UserCtx) { ctx.body = await groups.enrichUserRolesFromGroups(user) // add the feature flags for this tenant - const flags = await features.flags.fetch() - ctx.body.flags = flags + ctx.body.flags = await features.flags.fetch() addSessionAttributesToUser(ctx) } From c3564528b7c989e8069449251d474651ee9cb2c7 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 6 Jan 2025 12:15:41 +0000 Subject: [PATCH 032/173] Fix types. --- packages/backend-core/src/features/tests/utils.ts | 3 ++- packages/types/src/api/web/global/self.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/backend-core/src/features/tests/utils.ts b/packages/backend-core/src/features/tests/utils.ts index cc633c083d..b9281b7f19 100644 --- a/packages/backend-core/src/features/tests/utils.ts +++ b/packages/backend-core/src/features/tests/utils.ts @@ -1,5 +1,6 @@ -import { FeatureFlags, parseEnvFlags } from ".." +import { FeatureFlags } from "@budibase/types" import { setEnv } from "../../environment" +import { parseEnvFlags } from "../features" function getCurrentFlags(): Record> { const result: Record> = {} diff --git a/packages/types/src/api/web/global/self.ts b/packages/types/src/api/web/global/self.ts index d2c79bdba3..9e879e6c3c 100644 --- a/packages/types/src/api/web/global/self.ts +++ b/packages/types/src/api/web/global/self.ts @@ -1,4 +1,4 @@ -import { FeatureFlags } from "packages/types/src/sdk" +import { FeatureFlags } from "@budibase/types" import { DevInfo, User } from "../../../documents" export interface GenerateAPIKeyRequest { From 867d162751d9fa75745cde7f317572d3857f376e Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 6 Jan 2025 12:34:38 +0000 Subject: [PATCH 033/173] convert published store to ts --- .../src/stores/builder/{published.js => published.ts} | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) rename packages/builder/src/stores/builder/{published.js => published.ts} (53%) diff --git a/packages/builder/src/stores/builder/published.js b/packages/builder/src/stores/builder/published.ts similarity index 53% rename from packages/builder/src/stores/builder/published.js rename to packages/builder/src/stores/builder/published.ts index a59352fb22..c38f3bb718 100644 --- a/packages/builder/src/stores/builder/published.js +++ b/packages/builder/src/stores/builder/published.ts @@ -1,13 +1,16 @@ import { appStore } from "./app" import { appsStore } from "@/stores/portal/apps" import { deploymentStore } from "./deployments" -import { derived } from "svelte/store" +import { derived, type Readable } from "svelte/store" +import { DeploymentProgressResponse, DeploymentStatus } from "@budibase/types" -export const appPublished = derived( +export const appPublished: Readable = derived( [appStore, appsStore, deploymentStore], ([$appStore, $appsStore, $deploymentStore]) => { const app = $appsStore.apps.find(app => app.devId === $appStore.appId) - const deployments = $deploymentStore.filter(x => x.status === "SUCCESS") + const deployments = $deploymentStore.filter( + (x: DeploymentProgressResponse) => x.status === DeploymentStatus.SUCCESS + ) return app?.status === "published" && deployments.length > 0 } ) From 511328002ee5ff4a33c73df764b3528468eed37d Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 6 Jan 2025 12:35:55 +0000 Subject: [PATCH 034/173] Update pro reference. --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 9091868986..32d84f109d 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 9091868986fbc6aae580280f48853482e0b06c6a +Subproject commit 32d84f109d4edc526145472a7446327312151442 From 17bb67f6252de70c8679a2852005f6d6647adc54 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 6 Jan 2025 12:41:40 +0000 Subject: [PATCH 035/173] type theme correctly in app document --- packages/builder/src/stores/builder/theme.ts | 15 +++------------ packages/types/src/documents/app/app.ts | 4 ++-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/packages/builder/src/stores/builder/theme.ts b/packages/builder/src/stores/builder/theme.ts index b3ac202a5d..f2675fe06b 100644 --- a/packages/builder/src/stores/builder/theme.ts +++ b/packages/builder/src/stores/builder/theme.ts @@ -19,10 +19,7 @@ export class ThemeStore extends BudiStore { syncAppTheme = (app: App) => { this.update(state => { - const theme = ensureValidTheme( - app.theme as Theme | undefined, - DefaultAppTheme - ) as Theme + const theme = ensureValidTheme(app.theme, DefaultAppTheme) return { ...state, theme, @@ -35,10 +32,7 @@ export class ThemeStore extends BudiStore { const app = await API.saveAppMetadata(appId, { theme }) this.update(state => ({ ...state, - theme: ensureValidTheme( - app.theme as Theme | undefined, - DefaultAppTheme - ) as Theme, + theme: ensureValidTheme(app.theme, DefaultAppTheme), })) } @@ -55,10 +49,7 @@ export class ThemeStore extends BudiStore { const { theme, customTheme } = metadata this.update(state => ({ ...state, - theme: ensureValidTheme( - theme as Theme | undefined, - DefaultAppTheme - ) as Theme, + theme: ensureValidTheme(theme, DefaultAppTheme), customTheme: customTheme || {}, })) } diff --git a/packages/types/src/documents/app/app.ts b/packages/types/src/documents/app/app.ts index e31dd1e9ac..7486a3fa7e 100644 --- a/packages/types/src/documents/app/app.ts +++ b/packages/types/src/documents/app/app.ts @@ -1,4 +1,4 @@ -import { User, Document, Plugin, Snippet } from "../" +import { User, Document, Plugin, Snippet, Theme } from "../" import { SocketSession } from "../../sdk" export type AppMetadataErrors = { [key: string]: string[] } @@ -14,7 +14,7 @@ export interface App extends Document { instance: AppInstance tenantId: string status: string - theme?: string + theme?: Theme customTheme?: AppCustomTheme revertableVersion?: string lockedBy?: User From a09caf52d8c3fe4bd19f853f10cc30f5f3969ce5 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 6 Jan 2025 12:43:15 +0000 Subject: [PATCH 036/173] remove unnecessary casts --- packages/builder/src/stores/builder/theme.ts | 15 +++------------ packages/types/src/documents/app/app.ts | 4 ++-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/packages/builder/src/stores/builder/theme.ts b/packages/builder/src/stores/builder/theme.ts index b3ac202a5d..f2675fe06b 100644 --- a/packages/builder/src/stores/builder/theme.ts +++ b/packages/builder/src/stores/builder/theme.ts @@ -19,10 +19,7 @@ export class ThemeStore extends BudiStore { syncAppTheme = (app: App) => { this.update(state => { - const theme = ensureValidTheme( - app.theme as Theme | undefined, - DefaultAppTheme - ) as Theme + const theme = ensureValidTheme(app.theme, DefaultAppTheme) return { ...state, theme, @@ -35,10 +32,7 @@ export class ThemeStore extends BudiStore { const app = await API.saveAppMetadata(appId, { theme }) this.update(state => ({ ...state, - theme: ensureValidTheme( - app.theme as Theme | undefined, - DefaultAppTheme - ) as Theme, + theme: ensureValidTheme(app.theme, DefaultAppTheme), })) } @@ -55,10 +49,7 @@ export class ThemeStore extends BudiStore { const { theme, customTheme } = metadata this.update(state => ({ ...state, - theme: ensureValidTheme( - theme as Theme | undefined, - DefaultAppTheme - ) as Theme, + theme: ensureValidTheme(theme, DefaultAppTheme), customTheme: customTheme || {}, })) } diff --git a/packages/types/src/documents/app/app.ts b/packages/types/src/documents/app/app.ts index e31dd1e9ac..7486a3fa7e 100644 --- a/packages/types/src/documents/app/app.ts +++ b/packages/types/src/documents/app/app.ts @@ -1,4 +1,4 @@ -import { User, Document, Plugin, Snippet } from "../" +import { User, Document, Plugin, Snippet, Theme } from "../" import { SocketSession } from "../../sdk" export type AppMetadataErrors = { [key: string]: string[] } @@ -14,7 +14,7 @@ export interface App extends Document { instance: AppInstance tenantId: string status: string - theme?: string + theme?: Theme customTheme?: AppCustomTheme revertableVersion?: string lockedBy?: User From 48948712b9438042704dcb4facbdb3228f197007 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 6 Jan 2025 12:53:10 +0000 Subject: [PATCH 037/173] remove further cast --- packages/builder/src/stores/builder/theme.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/theme.ts b/packages/builder/src/stores/builder/theme.ts index f2675fe06b..604add9410 100644 --- a/packages/builder/src/stores/builder/theme.ts +++ b/packages/builder/src/stores/builder/theme.ts @@ -12,7 +12,7 @@ interface ThemeState { export class ThemeStore extends BudiStore { constructor() { super({ - theme: DefaultAppTheme as Theme, + theme: DefaultAppTheme, customTheme: {}, }) } From 30b543b6b727f25d46ec5d19a26091c76eb9b901 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 6 Jan 2025 13:35:00 +0000 Subject: [PATCH 038/173] error message for no row action name --- packages/builder/src/stores/builder/rowActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/rowActions.ts b/packages/builder/src/stores/builder/rowActions.ts index 378579e41b..9576eccd1b 100644 --- a/packages/builder/src/stores/builder/rowActions.ts +++ b/packages/builder/src/stores/builder/rowActions.ts @@ -66,7 +66,7 @@ export class RowActionStore extends BudiStore { } if (!name) { - return + throw new Error("Failed to generate a unique name for the row action") } // Create the action From 9f712eda71eba4c2bf6092e1cabfd38bf27e97c0 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 6 Jan 2025 13:36:56 +0000 Subject: [PATCH 039/173] Revert pro change --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index ae786121d9..32d84f109d 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit ae786121d923449b0ad5fcbd123d0a9fec28f65e +Subproject commit 32d84f109d4edc526145472a7446327312151442 From ab3bf05dfefe22520e8bedd601134ba6275f9710 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 6 Jan 2025 13:37:55 +0000 Subject: [PATCH 040/173] Make store terser --- packages/builder/src/stores/portal/featureFlags.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/builder/src/stores/portal/featureFlags.ts b/packages/builder/src/stores/portal/featureFlags.ts index ab0b178ab4..0e40d0c7b4 100644 --- a/packages/builder/src/stores/portal/featureFlags.ts +++ b/packages/builder/src/stores/portal/featureFlags.ts @@ -2,12 +2,7 @@ import { derived, Readable } from "svelte/store" import { auth } from "@/stores/portal" import { FeatureFlags, FeatureFlagDefaults } from "@budibase/types" -export const featureFlags: Readable = derived( - [auth], - ([$auth]) => { - return { - ...FeatureFlagDefaults, - ...($auth?.user?.flags || {}), - } - } -) +export const featureFlags: Readable = derived(auth, $auth => ({ + ...FeatureFlagDefaults, + ...($auth?.user?.flags || {}), +})) From 34b9cf38cf733b89256e31c6a0bd78dc3cc5ec16 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 6 Jan 2025 14:50:57 +0000 Subject: [PATCH 041/173] Add the openAPI package globally to avoid issues with it not being found. --- .github/workflows/readme-openapi.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/readme-openapi.yml b/.github/workflows/readme-openapi.yml index b52787934f..9f42f6141b 100644 --- a/.github/workflows/readme-openapi.yml +++ b/.github/workflows/readme-openapi.yml @@ -19,5 +19,8 @@ jobs: cache: yarn - run: yarn --frozen-lockfile + - name: Install OpenAPI pkg + run: yarn global add openapi + - name: update specs run: cd packages/server && yarn specs && openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 From 294f696d63cc66250742c7d3dd7f4b619698f566 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:31:39 +0000 Subject: [PATCH 042/173] Offer option to open Budibase via CLI (#15312) --- packages/cli/package.json | 3 ++- packages/cli/src/hosting/start.ts | 5 +++++ yarn.lock | 24 ++++++++++++------------ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 927824a522..662434957e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@budibase/backend-core": "*", + "@budibase/pouchdb-replication-stream": "1.2.11", "@budibase/string-templates": "*", "@budibase/types": "*", "chalk": "4.1.0", @@ -28,9 +29,9 @@ "inquirer": "8.0.0", "lookpath": "1.1.0", "node-fetch": "2.6.7", + "open": "8.4.2", "posthog-node": "4.0.1", "pouchdb": "7.3.0", - "@budibase/pouchdb-replication-stream": "1.2.11", "randomstring": "1.1.5", "tar": "6.2.1", "yaml": "^2.1.1" diff --git a/packages/cli/src/hosting/start.ts b/packages/cli/src/hosting/start.ts index 75e3df451f..5b08268c94 100644 --- a/packages/cli/src/hosting/start.ts +++ b/packages/cli/src/hosting/start.ts @@ -3,6 +3,8 @@ import { info, success } from "../utils" import * as makeFiles from "./makeFiles" import compose from "docker-compose" import fs from "fs" +import { confirmation } from "../questions" +const open = require("open") export async function start() { await checkDockerConfigured() @@ -22,6 +24,9 @@ export async function start() { // need to log as it makes it more clear await compose.upAll({ cwd: "./", log: true }) }) + if (await confirmation(`Do you wish to open http://localhost:${port} ?`)) { + await open(`http://localhost:${port}`) + } console.log( success( `Services started, please go to http://localhost:${port} for next steps.` diff --git a/yarn.lock b/yarn.lock index c6181f7866..c54385478e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2131,9 +2131,9 @@ through2 "^2.0.0" "@budibase/pro@npm:@budibase/pro@latest": - version "3.2.28" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.28.tgz#59b5b37225715bb8fbf5b1c5c989140b10b58710" - integrity sha512-eDPeZpYFRZYQhCulcQAUwFoPk68c8+K9mIsB6QD3oMHmHTDA1P2ZcXvLNqDTIqHB94DqnWinqDf4hTuGYApgPA== + version "3.2.32" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.32.tgz#f6abcd5a5524e7f33d958acb6e610e29995427bb" + integrity sha512-bF0pd17IjYugjll2yKYmb0RM+tfKZcCmRBc4XG2NZ4f/I47QaOovm9RqSw6tfqCFuzRewxR3SWmtmSseUc/e0w== dependencies: "@anthropic-ai/sdk" "^0.27.3" "@budibase/backend-core" "*" @@ -15600,15 +15600,7 @@ only@~0.0.2: resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" integrity sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ== -open@^7.3.1: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - -open@^8.0.0, open@^8.4.0, open@~8.4.0: +open@8.4.2, open@^8.0.0, open@^8.4.0, open@~8.4.0: version "8.4.2" resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== @@ -15617,6 +15609,14 @@ open@^8.0.0, open@^8.4.0, open@~8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" +open@^7.3.1: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + openai@4.59.0: version "4.59.0" resolved "https://registry.yarnpkg.com/openai/-/openai-4.59.0.tgz#3961d11a9afb5920e1bd475948a87969e244fc08" From 80a77d28a292bf56b7eeb55f13b07abfbe69d0d0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 6 Jan 2025 17:37:58 +0000 Subject: [PATCH 043/173] PR comment fixes. --- .../src/objectStore/buckets/tests/app.spec.ts | 36 +++++++++++++++++++ .../objectStore/buckets/tests/global.spec.ts | 30 ++++++++++++++++ .../src/objectStore/objectStore.ts | 19 +++++----- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts index d188d774bb..e36b36d39d 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts @@ -93,6 +93,22 @@ describe("app", () => { testEnv.multiTenant() }) + it("gets url with embedded minio", async () => { + testEnv.withMinio() + const url = await getAppFileUrl() + expect(url).toBe( + "/files/signed/prod-budi-app-assets/app_123/attachments/image.jpeg" + ) + }) + + it("gets url with custom S3", async () => { + testEnv.withS3() + const url = await getAppFileUrl() + expect(url).toBe( + "http://s3.example.com/prod-budi-app-assets/app_123/attachments/image.jpeg" + ) + }) + it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() const url = await getAppFileUrl() @@ -108,6 +124,26 @@ describe("app", () => { testEnv.multiTenant() }) + it("gets url with embedded minio", async () => { + testEnv.withMinio() + await testEnv.withTenant(async () => { + const url = await getAppFileUrl() + expect(url).toBe( + "/files/signed/prod-budi-app-assets/app_123/attachments/image.jpeg" + ) + }) + }) + + it("gets url with custom S3", async () => { + testEnv.withS3() + await testEnv.withTenant(async () => { + const url = await getAppFileUrl() + expect(url).toBe( + "http://s3.example.com/prod-budi-app-assets/app_123/attachments/image.jpeg" + ) + }) + }) + it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() await testEnv.withTenant(async () => { diff --git a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts index 9d5ec07c7a..c98d98e016 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts @@ -12,6 +12,18 @@ describe("global", () => { testEnv.singleTenant() }) + it("gets url with embedded minio", async () => { + testEnv.withMinio() + const url = await getGlobalFileUrl() + expect(url).toBe("/files/signed/global/settings/logoUrl") + }) + + it("gets url with custom S3", async () => { + testEnv.withS3() + const url = await getGlobalFileUrl() + expect(url).toBe("http://s3.example.com/global/settings/logoUrl") + }) + it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() const url = await getGlobalFileUrl() @@ -27,6 +39,24 @@ describe("global", () => { testEnv.multiTenant() }) + it("gets url with embedded minio", async () => { + testEnv.withMinio() + await testEnv.withTenant(async tenantId => { + const url = await getGlobalFileUrl() + expect(url).toBe(`/files/signed/global/${tenantId}/settings/logoUrl`) + }) + }) + + it("gets url with custom S3", async () => { + testEnv.withS3() + await testEnv.withTenant(async tenantId => { + const url = await getGlobalFileUrl() + expect(url).toBe( + `http://s3.example.com/global/${tenantId}/settings/logoUrl` + ) + }) + }) + it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() await testEnv.withTenant(async tenantId => { diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index adc974a131..4f07abe7e2 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -23,6 +23,7 @@ import { v4 } from "uuid" import { APP_PREFIX, APP_DEV_PREFIX } from "../db" import fsp from "fs/promises" import { ReadableStream } from "stream/web" +import { NodeJsRuntimeStreamingBlobPayloadOutputTypes } from "@smithy/types" const streamPipeline = promisify(stream.pipeline) // use this as a temporary store of buckets that are being created @@ -194,17 +195,17 @@ export async function upload({ } let contentType = type - if (!contentType) { - contentType = extension - ? CONTENT_TYPE_MAP[extension.toLowerCase()] - : CONTENT_TYPE_MAP.txt - } + const finalContentType = contentType + ? contentType + : extension + ? CONTENT_TYPE_MAP[extension.toLowerCase()] + : CONTENT_TYPE_MAP.txt const config: PutObjectCommandInput = { // windows file paths need to be converted to forward slashes for s3 Bucket: sanitizeBucket(bucketName), Key: sanitizeKey(filename), Body: fileBytes as stream.Readable | Buffer, - ContentType: contentType!, + ContentType: finalContentType, } if (metadata && typeof metadata === "object") { // remove any nullish keys from the metadata object, as these may be considered invalid @@ -310,11 +311,13 @@ export async function retrieve( if (!response.Body) { throw new Error("Unable to retrieve object") } + const nodeResponse = + response.Body as NodeJsRuntimeStreamingBlobPayloadOutputTypes // currently these are all strings if (STRING_CONTENT_TYPES.includes(response.ContentType)) { - return response.Body.toString() + return nodeResponse.toString() } else { - return response.Body as stream.Readable + return nodeResponse } } From 766d095c9c3b38d34bd09bd0b6fce635e990a690 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 6 Jan 2025 17:53:14 +0000 Subject: [PATCH 044/173] Adding dependency. --- packages/backend-core/package.json | 1 + yarn.lock | 44 ++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 4339ee0a94..b380fca017 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -74,6 +74,7 @@ "devDependencies": { "@jest/types": "^29.6.3", "@shopify/jest-koa-mocks": "5.1.1", + "@smithy/types": "4.0.0", "@swc/core": "1.3.71", "@swc/jest": "0.2.27", "@types/chance": "1.1.3", diff --git a/yarn.lock b/yarn.lock index 599f5cdf2f..fbae35bf36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2778,9 +2778,9 @@ through2 "^2.0.0" "@budibase/pro@npm:@budibase/pro@latest": - version "3.2.28" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.28.tgz#59b5b37225715bb8fbf5b1c5c989140b10b58710" - integrity sha512-eDPeZpYFRZYQhCulcQAUwFoPk68c8+K9mIsB6QD3oMHmHTDA1P2ZcXvLNqDTIqHB94DqnWinqDf4hTuGYApgPA== + version "3.2.32" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-3.2.32.tgz#f6abcd5a5524e7f33d958acb6e610e29995427bb" + integrity sha512-bF0pd17IjYugjll2yKYmb0RM+tfKZcCmRBc4XG2NZ4f/I47QaOovm9RqSw6tfqCFuzRewxR3SWmtmSseUc/e0w== dependencies: "@anthropic-ai/sdk" "^0.27.3" "@budibase/backend-core" "*" @@ -5512,6 +5512,13 @@ "@smithy/util-stream" "^3.3.2" tslib "^2.6.2" +"@smithy/types@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.0.0.tgz#7458c1c4dde3c6cf23221370acf5acd03215de6e" + integrity sha512-aNwIGSOgDOhtTRY/rrn2aeuQeKw/IFrQ998yK5l6Ah853WeWIEmFPs/EO4OpfADEdcK+igWnZytm/oUgkLgUYg== + dependencies: + tslib "^2.6.2" + "@smithy/types@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@smithy/types/-/types-1.2.0.tgz#9dc65767b0ee3d6681704fcc67665d6fc9b6a34e" @@ -19709,7 +19716,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -19801,7 +19817,7 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -19815,6 +19831,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" @@ -21562,7 +21585,7 @@ worker-farm@1.7.0: dependencies: errno "~0.1.7" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -21580,6 +21603,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 62873dedf480be50e3d70aa5daef7ad1b2ed160e Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 7 Jan 2025 10:35:07 +0000 Subject: [PATCH 045/173] make roles derived store --- packages/builder/src/stores/builder/roles.ts | 44 ++++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/builder/src/stores/builder/roles.ts b/packages/builder/src/stores/builder/roles.ts index 95ea63a997..732f50d6be 100644 --- a/packages/builder/src/stores/builder/roles.ts +++ b/packages/builder/src/stores/builder/roles.ts @@ -1,28 +1,30 @@ -import { derived, get } from "svelte/store" +import { derived, get, type Writable } from "svelte/store" import { API } from "@/api" import { RoleUtils } from "@budibase/frontend-core" -import { BudiStore } from "../BudiStore" +import { DerivedBudiStore } from "../BudiStore" import { Role } from "@budibase/types" -export class RoleStore extends BudiStore { +export class RoleStore extends DerivedBudiStore { constructor() { - super([]) + const makeDerivedStore = (store: Writable) => + derived(store, $store => { + return $store.map((role: Role) => ({ + ...role, + // Ensure we have new metadata for all roles + uiMetadata: { + displayName: role.uiMetadata?.displayName || role.name, + color: + role.uiMetadata?.color || + "var(--spectrum-global-color-magenta-400)", + description: role.uiMetadata?.description || "Custom role", + }, + })) + }) + + super([], makeDerivedStore) } - enriched = derived(this, $store => { - return $store.map(role => ({ - ...role, - // Ensure we have new metadata for all roles - uiMetadata: { - displayName: role.uiMetadata?.displayName || role.name, - color: - role.uiMetadata?.color || "var(--spectrum-global-color-magenta-400)", - description: role.uiMetadata?.description || "Custom role", - }, - })) - }) - - private setRoles = (roles: Role[]) => { + setRoles = (roles: Role[]) => { this.set( roles.sort((a, b) => { // Ensure we have valid IDs for priority comparison @@ -89,8 +91,4 @@ export class RoleStore extends BudiStore { } } -const store = new RoleStore() -export const roles = { - ...store, - subscribe: store.enriched.subscribe, -} +export const roles = new RoleStore() From 47e0913c54c3329f840bfee5f9ae43212541aa0a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 7 Jan 2025 12:27:29 +0000 Subject: [PATCH 046/173] Use find/splice instead of filter --- packages/builder/src/stores/portal/groups.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/stores/portal/groups.ts b/packages/builder/src/stores/portal/groups.ts index edb7ae7318..028f300d2c 100644 --- a/packages/builder/src/stores/portal/groups.ts +++ b/packages/builder/src/stores/portal/groups.ts @@ -47,9 +47,12 @@ class GroupStore extends BudiStore { async delete(group: UserGroup) { await API.deleteGroup(group._id!, group._rev!) - this.update(state => { - state = state.filter(state => state._id !== group._id) - return state + this.update(groups => { + const index = groups.findIndex(g => g._id === group._id) + if (index !== -1) { + groups.splice(index, 1) + } + return groups }) } From 19f39af9ec4cc0cee2667f7a3c0eb4b29f83f0fd Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 7 Jan 2025 14:04:51 +0000 Subject: [PATCH 047/173] Fix conflict --- packages/worker/src/api/controllers/global/self.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/worker/src/api/controllers/global/self.ts b/packages/worker/src/api/controllers/global/self.ts index c8d99f332c..3464bff88f 100644 --- a/packages/worker/src/api/controllers/global/self.ts +++ b/packages/worker/src/api/controllers/global/self.ts @@ -114,11 +114,7 @@ export async function getSelf(ctx: UserCtx) { const sessionAttributes = getUserSessionAttributes(ctx) // add the feature flags for this tenant -<<<<<<< HEAD const flags = await features.flags.fetch() -======= - ctx.body.flags = await features.flags.fetch() ->>>>>>> 55685be0814403644bc25d82b3218e27f6590490 ctx.body = { ...enrichedUser, From be5c619911a8c7464f0198d3b0c309f372304ddd Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:08:43 +0000 Subject: [PATCH 048/173] Add save button to user screen (#15309) * Add save button to user screen * Performance improvement * lint * Simplify code --- .../portal/users/users/[userId].svelte | 52 ++++++++++--------- .../src/api/controllers/global/users.ts | 16 +++--- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 57ecc9d39f..6c480d9ef8 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -87,6 +87,7 @@ let popover let user, tenantOwner let loaded = false + let userFieldsToUpdate = {} $: internalGroups = $groups?.filter(g => !g?.scimInfo?.isSync) @@ -164,40 +165,45 @@ return label } - async function updateUserFirstName(evt) { + async function saveUser() { try { - await users.save({ ...user, firstName: evt.target.value }) + await users.save({ ...user, ...userFieldsToUpdate }) + userFieldsToUpdate = {} await fetchUser() } catch (error) { notifications.error("Error updating user") } } + async function updateUserFirstName(evt) { + userFieldsToUpdate.firstName = evt.target.value + } + async function updateUserLastName(evt) { - try { - await users.save({ ...user, lastName: evt.target.value }) - await fetchUser() - } catch (error) { - notifications.error("Error updating user") - } + userFieldsToUpdate.lastName = evt.target.value } async function updateUserRole({ detail }) { + let flags = {} if (detail === Constants.BudibaseRoles.Developer) { - toggleFlags({ admin: { global: false }, builder: { global: true } }) + flags = { admin: { global: false }, builder: { global: true } } } else if (detail === Constants.BudibaseRoles.Admin) { - toggleFlags({ admin: { global: true }, builder: { global: true } }) + flags = { admin: { global: true }, builder: { global: true } } } else if (detail === Constants.BudibaseRoles.AppUser) { - toggleFlags({ admin: { global: false }, builder: { global: false } }) + flags = { admin: { global: false }, builder: { global: false } } } else if (detail === Constants.BudibaseRoles.Creator) { - toggleFlags({ + flags = { admin: { global: false }, builder: { global: false, creator: true, apps: user?.builder?.apps || [], }, - }) + } + } + userFieldsToUpdate = { + ...userFieldsToUpdate, + ...flags, } } @@ -209,15 +215,6 @@ tenantOwner = await users.getAccountHolder() } - async function toggleFlags(detail) { - try { - await users.save({ ...user, ...detail }) - await fetchUser() - } catch (error) { - notifications.error("Error updating user") - } - } - const addGroup = async groupId => { await groups.addUser(groupId, userId) await fetchUser() @@ -296,7 +293,7 @@
@@ -304,7 +301,7 @@
@@ -325,6 +322,13 @@ {/if} +
+ +
{#if $licensing.groupsEnabled} diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index a028f4fd33..83f2f41b0e 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -72,12 +72,14 @@ export const save = async (ctx: UserCtx) => { const requestUser = ctx.request.body // Do not allow the account holder role to be changed - const accountMetadata = await users.getExistingAccounts([requestUser.email]) - if (accountMetadata?.length > 0) { - if ( - requestUser.admin?.global !== true || - requestUser.builder?.global !== true - ) { + if ( + requestUser.admin?.global !== true || + requestUser.builder?.global !== true + ) { + const accountMetadata = await users.getExistingAccounts([ + requestUser.email, + ]) + if (accountMetadata?.length > 0) { throw Error("Cannot set role of account holder") } } @@ -441,7 +443,6 @@ export const checkInvite = async (ctx: UserCtx) => { } catch (e) { console.warn("Error getting invite from code", e) ctx.throw(400, "There was a problem with the invite") - return } ctx.body = { email: invite.email, @@ -472,7 +473,6 @@ export const updateInvite = async ( invite = await cache.invite.getCode(code) } catch (e) { ctx.throw(400, "There was a problem with the invite") - return } let updated = { From d7b1b1a3671f7bab4f80cd825c4a8e98bc6cde03 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 16:52:01 +0100 Subject: [PATCH 049/173] Fix issues when fetching view v1 data --- packages/client/src/api/patches.js | 4 ++-- packages/frontend-core/src/fetch/ViewFetch.js | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/client/src/api/patches.js b/packages/client/src/api/patches.js index 5413379b72..9203ac3c70 100644 --- a/packages/client/src/api/patches.js +++ b/packages/client/src/api/patches.js @@ -85,9 +85,9 @@ export const patchAPI = API => { } } const fetchViewData = API.fetchViewData - API.fetchViewData = async params => { + API.fetchViewData = async (viewName, params) => { const tableId = params?.tableId - const rows = await fetchViewData(params) + const rows = await fetchViewData(viewName, params) return await enrichRows(rows, tableId) } diff --git a/packages/frontend-core/src/fetch/ViewFetch.js b/packages/frontend-core/src/fetch/ViewFetch.js index 272c222dd4..eb89f9b67a 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.js +++ b/packages/frontend-core/src/fetch/ViewFetch.js @@ -8,9 +8,15 @@ export default class ViewFetch extends DataFetch { async getData() { const { datasource } = this.options try { - const res = await this.API.fetchViewData(datasource.name) + const res = await this.API.fetchViewData(datasource.name, { + calculation: datasource.calculation, + field: datasource.field, + groupBy: datasource.groupBy, + tableId: datasource.tableId, + }) return { rows: res || [] } } catch (error) { + console.error(error) return { rows: [] } } } From 4d0f69556c9a8bb9bb0781fa54edb8345b32d3eb Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 7 Jan 2025 16:59:34 +0000 Subject: [PATCH 050/173] Bump version to 3.2.33 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index dde9cf03a0..3afc2c60e9 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.32", + "version": "3.2.33", "npmClient": "yarn", "concurrency": 20, "command": { From 64471bd7337ede6fbc598cd7806728858474b569 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 7 Jan 2025 17:12:56 +0000 Subject: [PATCH 051/173] Fix enrich endpoint in client --- packages/client/src/api/patches.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/client/src/api/patches.js b/packages/client/src/api/patches.js index 5413379b72..6ea3b7c183 100644 --- a/packages/client/src/api/patches.js +++ b/packages/client/src/api/patches.js @@ -66,10 +66,9 @@ export const patchAPI = API => { } } const fetchRelationshipData = API.fetchRelationshipData - API.fetchRelationshipData = async params => { - const tableId = params?.tableId - const rows = await fetchRelationshipData(params) - return await enrichRows(rows, tableId) + API.fetchRelationshipData = async (sourceId, rowId, fieldName) => { + const rows = await fetchRelationshipData(sourceId, rowId, fieldName) + return await enrichRows(rows, sourceId) } const fetchTableData = API.fetchTableData API.fetchTableData = async tableId => { From af83f1b2e15a0268efb7bcac7abcd784575c9208 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 7 Jan 2025 17:18:36 +0000 Subject: [PATCH 052/173] Delete old feature flags. --- packages/builder/src/stores/portal/menu.js | 10 +++------- packages/pro | 2 +- .../src/api/controllers/row/staticFormula.ts | 17 ++++------------- packages/server/src/automations/actions.ts | 12 ++---------- packages/server/src/automations/steps/openai.ts | 11 +++-------- packages/types/src/sdk/featureFlag.ts | 8 -------- 6 files changed, 13 insertions(+), 47 deletions(-) diff --git a/packages/builder/src/stores/portal/menu.js b/packages/builder/src/stores/portal/menu.js index 75a9b363be..4f87a5bfde 100644 --- a/packages/builder/src/stores/portal/menu.js +++ b/packages/builder/src/stores/portal/menu.js @@ -1,9 +1,7 @@ import { derived } from "svelte/store" import { admin } from "./admin" import { auth } from "./auth" -import { isEnabled } from "@/helpers/featureFlags" import { sdk } from "@budibase/shared-core" -import { FeatureFlag } from "@budibase/types" export const menu = derived([admin, auth], ([$admin, $auth]) => { const user = $auth?.user @@ -63,13 +61,11 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => { title: "Environment", href: "/builder/portal/settings/environment", }, - ] - if (isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) { - settingsSubPages.push({ + { title: "AI", href: "/builder/portal/settings/ai", - }) - } + }, + ] if (!cloud) { settingsSubPages.push({ diff --git a/packages/pro b/packages/pro index 32d84f109d..23fdd50b7e 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 32d84f109d4edc526145472a7446327312151442 +Subproject commit 23fdd50b7ef28cf320716ed2c46e15d63185daa7 diff --git a/packages/server/src/api/controllers/row/staticFormula.ts b/packages/server/src/api/controllers/row/staticFormula.ts index b81a164807..678e824b94 100644 --- a/packages/server/src/api/controllers/row/staticFormula.ts +++ b/packages/server/src/api/controllers/row/staticFormula.ts @@ -4,15 +4,8 @@ import { processAIColumns, processFormulas, } from "../../../utilities/rowProcessor" -import { context, features } from "@budibase/backend-core" -import { - Table, - Row, - FeatureFlag, - FormulaType, - FieldType, - ViewV2, -} from "@budibase/types" +import { context } from "@budibase/backend-core" +import { Table, Row, FormulaType, FieldType, ViewV2 } from "@budibase/types" import * as linkRows from "../../../db/linkedRows" import isEqual from "lodash/isEqual" import { cloneDeep, merge } from "lodash/fp" @@ -163,10 +156,8 @@ export async function finaliseRow( contextRows: [enrichedRow], }) const aiEnabled = - ((await features.isEnabled(FeatureFlag.BUDIBASE_AI)) && - (await pro.features.isBudibaseAIEnabled())) || - ((await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) && - (await pro.features.isAICustomConfigsEnabled())) + (await pro.features.isBudibaseAIEnabled()) || + (await pro.features.isAICustomConfigsEnabled()) if (aiEnabled) { row = await processAIColumns(table, row, { contextRows: [enrichedRow], diff --git a/packages/server/src/automations/actions.ts b/packages/server/src/automations/actions.ts index 1c201d1f64..537b6befc3 100644 --- a/packages/server/src/automations/actions.ts +++ b/packages/server/src/automations/actions.ts @@ -27,11 +27,9 @@ import { Hosting, ActionImplementation, AutomationStepDefinition, - FeatureFlag, } from "@budibase/types" import sdk from "../sdk" import { getAutomationPlugin } from "../utilities/fileSystem" -import { features } from "@budibase/backend-core" type ActionImplType = ActionImplementations< typeof env.SELF_HOSTED extends "true" ? Hosting.SELF : Hosting.CLOUD @@ -78,6 +76,7 @@ export const BUILTIN_ACTION_DEFINITIONS: Record< LOOP: loop.definition, COLLECT: collect.definition, TRIGGER_AUTOMATION_RUN: triggerAutomationRun.definition, + BRANCH: branch.definition, // these used to be lowercase step IDs, maintain for backwards compat discord: discord.definition, slack: slack.definition, @@ -105,14 +104,7 @@ if (env.SELF_HOSTED) { export async function getActionDefinitions(): Promise< Record > { - if (await features.isEnabled(FeatureFlag.AUTOMATION_BRANCHING)) { - BUILTIN_ACTION_DEFINITIONS["BRANCH"] = branch.definition - } - if ( - env.SELF_HOSTED || - (await features.isEnabled(FeatureFlag.BUDIBASE_AI)) || - (await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) - ) { + if (env.SELF_HOSTED) { BUILTIN_ACTION_DEFINITIONS["OPENAI"] = openai.definition } diff --git a/packages/server/src/automations/steps/openai.ts b/packages/server/src/automations/steps/openai.ts index 19595cc0d0..53e41ceb09 100644 --- a/packages/server/src/automations/steps/openai.ts +++ b/packages/server/src/automations/steps/openai.ts @@ -7,9 +7,8 @@ import { AutomationIOType, OpenAIStepInputs, OpenAIStepOutputs, - FeatureFlag, } from "@budibase/types" -import { env, features } from "@budibase/backend-core" +import { env } from "@budibase/backend-core" import * as automationUtils from "../automationUtils" import * as pro from "@budibase/pro" @@ -99,12 +98,8 @@ export async function run({ try { let response - const customConfigsEnabled = - (await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS)) && - (await pro.features.isAICustomConfigsEnabled()) - const budibaseAIEnabled = - (await features.isEnabled(FeatureFlag.BUDIBASE_AI)) && - (await pro.features.isBudibaseAIEnabled()) + const customConfigsEnabled = await pro.features.isAICustomConfigsEnabled() + const budibaseAIEnabled = await pro.features.isBudibaseAIEnabled() let llmWrapper if (budibaseAIEnabled || customConfigsEnabled) { diff --git a/packages/types/src/sdk/featureFlag.ts b/packages/types/src/sdk/featureFlag.ts index 725ae0feb1..7b61b70772 100644 --- a/packages/types/src/sdk/featureFlag.ts +++ b/packages/types/src/sdk/featureFlag.ts @@ -1,16 +1,8 @@ export enum FeatureFlag { - AUTOMATION_BRANCHING = "AUTOMATION_BRANCHING", - AI_CUSTOM_CONFIGS = "AI_CUSTOM_CONFIGS", - DEFAULT_VALUES = "DEFAULT_VALUES", - BUDIBASE_AI = "BUDIBASE_AI", USE_ZOD_VALIDATOR = "USE_ZOD_VALIDATOR", } export const FeatureFlagDefaults = { - [FeatureFlag.DEFAULT_VALUES]: true, - [FeatureFlag.AUTOMATION_BRANCHING]: true, - [FeatureFlag.AI_CUSTOM_CONFIGS]: true, - [FeatureFlag.BUDIBASE_AI]: true, [FeatureFlag.USE_ZOD_VALIDATOR]: false, } From 21bfb7a45da8b1b615c100d8d52d0e991e24eae5 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 7 Jan 2025 17:47:14 +0000 Subject: [PATCH 053/173] Bump version to 3.2.34 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 3afc2c60e9..bc3f341979 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.33", + "version": "3.2.34", "npmClient": "yarn", "concurrency": 20, "command": { From 0d1c86777ca471f6e8f2131e28f127ea74aa3c03 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 8 Jan 2025 09:26:44 +0000 Subject: [PATCH 054/173] Fix usage calculations --- packages/builder/src/stores/portal/licensing.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/stores/portal/licensing.ts b/packages/builder/src/stores/portal/licensing.ts index 0b56e14005..99970313e2 100644 --- a/packages/builder/src/stores/portal/licensing.ts +++ b/packages/builder/src/stores/portal/licensing.ts @@ -227,7 +227,7 @@ class LicensingStore extends BudiStore { MonthlyQuotaName.AUTOMATIONS, ].reduce((acc: MonthlyMetrics, key) => { const limit = license.quotas.usage.monthly[key].value - const used = (usage.monthly.current?.[key] || 0 / limit) * 100 + const used = ((usage.monthly.current?.[key] || 0) / limit) * 100 acc[key] = limit > -1 ? Math.floor(used) : -1 return acc }, {}) @@ -236,7 +236,7 @@ class LicensingStore extends BudiStore { const staticMetrics = [StaticQuotaName.APPS, StaticQuotaName.ROWS].reduce( (acc: StaticMetrics, key) => { const limit = license.quotas.usage.static[key].value - const used = (usage.usageQuota[key] || 0 / limit) * 100 + const used = ((usage.usageQuota[key] || 0) / limit) * 100 acc[key] = limit > -1 ? Math.floor(used) : -1 return acc }, From aec4cc5bfbe93c494e0b9cd74b9d4779b277c476 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 8 Jan 2025 09:35:31 +0000 Subject: [PATCH 055/173] Bump version to 3.2.35 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index bc3f341979..5f61c9bb35 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.34", + "version": "3.2.35", "npmClient": "yarn", "concurrency": 20, "command": { From 377e764d5bcbe204e5cc37675242f54690dc82f4 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 8 Jan 2025 10:25:44 +0000 Subject: [PATCH 056/173] Bump version to 3.2.36 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 5f61c9bb35..9b2cacda12 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.35", + "version": "3.2.36", "npmClient": "yarn", "concurrency": 20, "command": { From 8eed6de0800524232c28d22b5bac0d57282ff6a7 Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Wed, 8 Jan 2025 10:28:08 +0000 Subject: [PATCH 057/173] Revert "Update AWS SDK to V3" --- .../__mocks__/@aws-sdk/client-s3.ts | 28 - .../@aws-sdk/s3-request-presigner.ts | 4 - packages/backend-core/__mocks__/aws-sdk.ts | 19 + packages/backend-core/package.json | 6 +- packages/backend-core/src/environment.ts | 2 +- .../src/objectStore/buckets/app.ts | 8 +- .../src/objectStore/buckets/global.ts | 8 +- .../src/objectStore/buckets/plugins.ts | 22 +- .../src/objectStore/buckets/tests/app.spec.ts | 24 +- .../objectStore/buckets/tests/global.spec.ts | 26 +- .../objectStore/buckets/tests/plugins.spec.ts | 28 +- .../src/objectStore/objectStore.ts | 198 ++- .../backend-core/src/objectStore/utils.ts | 9 +- packages/cli/src/backups/objectStore.ts | 25 +- packages/server/package.json | 5 +- .../server/src/api/controllers/application.ts | 2 +- .../src/api/controllers/static/index.ts | 26 +- .../src/api/routes/tests/static.spec.ts | 19 +- .../src/automations/tests/createRow.spec.ts | 18 +- packages/server/src/integrations/dynamodb.ts | 38 +- packages/server/src/integrations/s3.ts | 57 +- .../src/integrations/tests/aws-sdk.mock.ts | 76 ++ .../src/integrations/tests/dynamodb.spec.ts | 24 +- .../server/src/integrations/tests/s3.spec.ts | 49 +- .../server/src/integrations/utils/utils.ts | 2 +- packages/server/src/sdk/plugins/plugins.ts | 2 +- .../server/src/utilities/fileSystem/app.ts | 2 +- .../server/src/utilities/fileSystem/plugin.ts | 7 +- .../src/utilities/rowProcessor/index.ts | 14 +- .../src/api/controllers/global/configs.ts | 46 +- yarn.lock | 1107 +---------------- 31 files changed, 364 insertions(+), 1537 deletions(-) delete mode 100644 packages/backend-core/__mocks__/@aws-sdk/client-s3.ts delete mode 100644 packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts create mode 100644 packages/backend-core/__mocks__/aws-sdk.ts create mode 100644 packages/server/src/integrations/tests/aws-sdk.mock.ts diff --git a/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts b/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts deleted file mode 100644 index 8f002f41a8..0000000000 --- a/packages/backend-core/__mocks__/@aws-sdk/client-s3.ts +++ /dev/null @@ -1,28 +0,0 @@ -export class S3 { - headBucket() { - return jest.fn().mockReturnThis() - } - deleteObject() { - return jest.fn().mockReturnThis() - } - deleteObjects() { - return jest.fn().mockReturnThis() - } - createBucket() { - return jest.fn().mockReturnThis() - } - getObject() { - return jest.fn().mockReturnThis() - } - listObject() { - return jest.fn().mockReturnThis() - } - promise() { - return jest.fn().mockReturnThis() - } - catch() { - return jest.fn() - } -} - -export const GetObjectCommand = jest.fn(inputs => ({ inputs })) diff --git a/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts b/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts deleted file mode 100644 index 3ed2c10595..0000000000 --- a/packages/backend-core/__mocks__/@aws-sdk/s3-request-presigner.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const getSignedUrl = jest.fn((_, cmd) => { - const { inputs } = cmd - return `http://s3.example.com/${inputs?.Bucket}/${inputs?.Key}` -}) diff --git a/packages/backend-core/__mocks__/aws-sdk.ts b/packages/backend-core/__mocks__/aws-sdk.ts new file mode 100644 index 0000000000..e3be511d08 --- /dev/null +++ b/packages/backend-core/__mocks__/aws-sdk.ts @@ -0,0 +1,19 @@ +const mockS3 = { + headBucket: jest.fn().mockReturnThis(), + deleteObject: jest.fn().mockReturnThis(), + deleteObjects: jest.fn().mockReturnThis(), + createBucket: jest.fn().mockReturnThis(), + getObject: jest.fn().mockReturnThis(), + listObject: jest.fn().mockReturnThis(), + getSignedUrl: jest.fn((operation: string, params: any) => { + return `http://s3.example.com/${params.Bucket}/${params.Key}` + }), + promise: jest.fn().mockReturnThis(), + catch: jest.fn(), +} + +const AWS = { + S3: jest.fn(() => mockS3), +} + +export default AWS diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index b380fca017..3e1b5f324b 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -30,9 +30,6 @@ "test:watch": "jest --watchAll" }, "dependencies": { - "@aws-sdk/client-s3": "3.709.0", - "@aws-sdk/lib-storage": "3.709.0", - "@aws-sdk/s3-request-presigner": "3.709.0", "@budibase/nano": "10.1.5", "@budibase/pouchdb-replication-stream": "1.2.11", "@budibase/shared-core": "*", @@ -74,13 +71,11 @@ "devDependencies": { "@jest/types": "^29.6.3", "@shopify/jest-koa-mocks": "5.1.1", - "@smithy/types": "4.0.0", "@swc/core": "1.3.71", "@swc/jest": "0.2.27", "@types/chance": "1.1.3", "@types/cookies": "0.7.8", "@types/jest": "29.5.5", - "@types/koa": "2.13.4", "@types/lodash": "4.14.200", "@types/node-fetch": "2.6.4", "@types/pouchdb": "6.4.2", @@ -88,6 +83,7 @@ "@types/semver": "7.3.7", "@types/tar-fs": "2.0.1", "@types/uuid": "8.3.4", + "@types/koa": "2.13.4", "chance": "1.1.8", "ioredis-mock": "8.9.0", "jest": "29.7.0", diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 9a46758062..954fdd4135 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -154,7 +154,7 @@ const environment = { MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, AWS_SESSION_TOKEN: process.env.AWS_SESSION_TOKEN, - AWS_REGION: process.env.AWS_REGION || "eu-west-1", + AWS_REGION: process.env.AWS_REGION, MINIO_URL: process.env.MINIO_URL, MINIO_ENABLED: process.env.MINIO_ENABLED || 1, INTERNAL_API_KEY: process.env.INTERNAL_API_KEY, diff --git a/packages/backend-core/src/objectStore/buckets/app.ts b/packages/backend-core/src/objectStore/buckets/app.ts index dbf49ca994..43bc965c65 100644 --- a/packages/backend-core/src/objectStore/buckets/app.ts +++ b/packages/backend-core/src/objectStore/buckets/app.ts @@ -13,7 +13,7 @@ export function clientLibraryPath(appId: string) { * due to issues with the domain we were unable to continue doing this - keeping * incase we are able to switch back to CDN path again in future. */ -export async function clientLibraryCDNUrl(appId: string, version: string) { +export function clientLibraryCDNUrl(appId: string, version: string) { let file = clientLibraryPath(appId) if (env.CLOUDFRONT_CDN) { // append app version to bust the cache @@ -24,7 +24,7 @@ export async function clientLibraryCDNUrl(appId: string, version: string) { // file is public return cloudfront.getUrl(file) } else { - return await objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, file) + return objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, file) } } @@ -44,10 +44,10 @@ export function clientLibraryUrl(appId: string, version: string) { return `/api/assets/client?${qs.encode(qsParams)}` } -export async function getAppFileUrl(s3Key: string) { +export function getAppFileUrl(s3Key: string) { if (env.CLOUDFRONT_CDN) { return cloudfront.getPresignedUrl(s3Key) } else { - return await objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, s3Key) + return objectStore.getPresignedUrl(env.APPS_BUCKET_NAME, s3Key) } } diff --git a/packages/backend-core/src/objectStore/buckets/global.ts b/packages/backend-core/src/objectStore/buckets/global.ts index 29c3347b05..69e201bb98 100644 --- a/packages/backend-core/src/objectStore/buckets/global.ts +++ b/packages/backend-core/src/objectStore/buckets/global.ts @@ -5,11 +5,7 @@ import * as cloudfront from "../cloudfront" // URLs -export const getGlobalFileUrl = async ( - type: string, - name: string, - etag?: string -) => { +export const getGlobalFileUrl = (type: string, name: string, etag?: string) => { let file = getGlobalFileS3Key(type, name) if (env.CLOUDFRONT_CDN) { if (etag) { @@ -17,7 +13,7 @@ export const getGlobalFileUrl = async ( } return cloudfront.getPresignedUrl(file) } else { - return await objectStore.getPresignedUrl(env.GLOBAL_BUCKET_NAME, file) + return objectStore.getPresignedUrl(env.GLOBAL_BUCKET_NAME, file) } } diff --git a/packages/backend-core/src/objectStore/buckets/plugins.ts b/packages/backend-core/src/objectStore/buckets/plugins.ts index 131f180f48..02be9345ab 100644 --- a/packages/backend-core/src/objectStore/buckets/plugins.ts +++ b/packages/backend-core/src/objectStore/buckets/plugins.ts @@ -6,25 +6,23 @@ import { Plugin } from "@budibase/types" // URLS -export async function enrichPluginURLs(plugins?: Plugin[]): Promise { +export function enrichPluginURLs(plugins?: Plugin[]): Plugin[] { if (!plugins || !plugins.length) { return [] } - return await Promise.all( - plugins.map(async plugin => { - const jsUrl = await getPluginJSUrl(plugin) - const iconUrl = await getPluginIconUrl(plugin) - return { ...plugin, jsUrl, iconUrl } - }) - ) + return plugins.map(plugin => { + const jsUrl = getPluginJSUrl(plugin) + const iconUrl = getPluginIconUrl(plugin) + return { ...plugin, jsUrl, iconUrl } + }) } -async function getPluginJSUrl(plugin: Plugin) { +function getPluginJSUrl(plugin: Plugin) { const s3Key = getPluginJSKey(plugin) return getPluginUrl(s3Key) } -async function getPluginIconUrl(plugin: Plugin) { +function getPluginIconUrl(plugin: Plugin): string | undefined { const s3Key = getPluginIconKey(plugin) if (!s3Key) { return @@ -32,11 +30,11 @@ async function getPluginIconUrl(plugin: Plugin) { return getPluginUrl(s3Key) } -async function getPluginUrl(s3Key: string) { +function getPluginUrl(s3Key: string) { if (env.CLOUDFRONT_CDN) { return cloudfront.getPresignedUrl(s3Key) } else { - return await objectStore.getPresignedUrl(env.PLUGIN_BUCKET_NAME, s3Key) + return objectStore.getPresignedUrl(env.PLUGIN_BUCKET_NAME, s3Key) } } diff --git a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts index e36b36d39d..4a132ce54d 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/app.spec.ts @@ -93,25 +93,25 @@ describe("app", () => { testEnv.multiTenant() }) - it("gets url with embedded minio", async () => { + it("gets url with embedded minio", () => { testEnv.withMinio() - const url = await getAppFileUrl() + const url = getAppFileUrl() expect(url).toBe( "/files/signed/prod-budi-app-assets/app_123/attachments/image.jpeg" ) }) - it("gets url with custom S3", async () => { + it("gets url with custom S3", () => { testEnv.withS3() - const url = await getAppFileUrl() + const url = getAppFileUrl() expect(url).toBe( "http://s3.example.com/prod-budi-app-assets/app_123/attachments/image.jpeg" ) }) - it("gets url with cloudfront + s3", async () => { + it("gets url with cloudfront + s3", () => { testEnv.withCloudfront() - const url = await getAppFileUrl() + const url = getAppFileUrl() // omit rest of signed params expect( url.includes("http://cf.example.com/app_123/attachments/image.jpeg?") @@ -126,8 +126,8 @@ describe("app", () => { it("gets url with embedded minio", async () => { testEnv.withMinio() - await testEnv.withTenant(async () => { - const url = await getAppFileUrl() + await testEnv.withTenant(() => { + const url = getAppFileUrl() expect(url).toBe( "/files/signed/prod-budi-app-assets/app_123/attachments/image.jpeg" ) @@ -136,8 +136,8 @@ describe("app", () => { it("gets url with custom S3", async () => { testEnv.withS3() - await testEnv.withTenant(async () => { - const url = await getAppFileUrl() + await testEnv.withTenant(() => { + const url = getAppFileUrl() expect(url).toBe( "http://s3.example.com/prod-budi-app-assets/app_123/attachments/image.jpeg" ) @@ -146,8 +146,8 @@ describe("app", () => { it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - await testEnv.withTenant(async () => { - const url = await getAppFileUrl() + await testEnv.withTenant(() => { + const url = getAppFileUrl() // omit rest of signed params expect( url.includes( diff --git a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts index c98d98e016..148a4c80bf 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/global.spec.ts @@ -3,7 +3,7 @@ import { testEnv } from "../../../../tests/extra" describe("global", () => { describe("getGlobalFileUrl", () => { - async function getGlobalFileUrl() { + function getGlobalFileUrl() { return global.getGlobalFileUrl("settings", "logoUrl", "etag") } @@ -12,21 +12,21 @@ describe("global", () => { testEnv.singleTenant() }) - it("gets url with embedded minio", async () => { + it("gets url with embedded minio", () => { testEnv.withMinio() - const url = await getGlobalFileUrl() + const url = getGlobalFileUrl() expect(url).toBe("/files/signed/global/settings/logoUrl") }) - it("gets url with custom S3", async () => { + it("gets url with custom S3", () => { testEnv.withS3() - const url = await getGlobalFileUrl() + const url = getGlobalFileUrl() expect(url).toBe("http://s3.example.com/global/settings/logoUrl") }) - it("gets url with cloudfront + s3", async () => { + it("gets url with cloudfront + s3", () => { testEnv.withCloudfront() - const url = await getGlobalFileUrl() + const url = getGlobalFileUrl() // omit rest of signed params expect( url.includes("http://cf.example.com/settings/logoUrl?etag=etag&") @@ -41,16 +41,16 @@ describe("global", () => { it("gets url with embedded minio", async () => { testEnv.withMinio() - await testEnv.withTenant(async tenantId => { - const url = await getGlobalFileUrl() + await testEnv.withTenant(tenantId => { + const url = getGlobalFileUrl() expect(url).toBe(`/files/signed/global/${tenantId}/settings/logoUrl`) }) }) it("gets url with custom S3", async () => { testEnv.withS3() - await testEnv.withTenant(async tenantId => { - const url = await getGlobalFileUrl() + await testEnv.withTenant(tenantId => { + const url = getGlobalFileUrl() expect(url).toBe( `http://s3.example.com/global/${tenantId}/settings/logoUrl` ) @@ -59,8 +59,8 @@ describe("global", () => { it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - await testEnv.withTenant(async tenantId => { - const url = await getGlobalFileUrl() + await testEnv.withTenant(tenantId => { + const url = getGlobalFileUrl() // omit rest of signed params expect( url.includes( diff --git a/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts b/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts index 0906ea91c2..fc2822314e 100644 --- a/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts +++ b/packages/backend-core/src/objectStore/buckets/tests/plugins.spec.ts @@ -6,8 +6,8 @@ describe("plugins", () => { describe("enrichPluginURLs", () => { const plugin = structures.plugins.plugin() - async function getEnrichedPluginUrls() { - const enriched = (await plugins.enrichPluginURLs([plugin]))[0] + function getEnrichedPluginUrls() { + const enriched = plugins.enrichPluginURLs([plugin])[0] return { jsUrl: enriched.jsUrl!, iconUrl: enriched.iconUrl!, @@ -19,9 +19,9 @@ describe("plugins", () => { testEnv.singleTenant() }) - it("gets url with embedded minio", async () => { + it("gets url with embedded minio", () => { testEnv.withMinio() - const urls = await getEnrichedPluginUrls() + const urls = getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `/files/signed/plugins/${plugin.name}/plugin.min.js` ) @@ -30,9 +30,9 @@ describe("plugins", () => { ) }) - it("gets url with custom S3", async () => { + it("gets url with custom S3", () => { testEnv.withS3() - const urls = await getEnrichedPluginUrls() + const urls = getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `http://s3.example.com/plugins/${plugin.name}/plugin.min.js` ) @@ -41,9 +41,9 @@ describe("plugins", () => { ) }) - it("gets url with cloudfront + s3", async () => { + it("gets url with cloudfront + s3", () => { testEnv.withCloudfront() - const urls = await getEnrichedPluginUrls() + const urls = getEnrichedPluginUrls() // omit rest of signed params expect( urls.jsUrl.includes( @@ -65,8 +65,8 @@ describe("plugins", () => { it("gets url with embedded minio", async () => { testEnv.withMinio() - await testEnv.withTenant(async tenantId => { - const urls = await getEnrichedPluginUrls() + await testEnv.withTenant(tenantId => { + const urls = getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `/files/signed/plugins/${tenantId}/${plugin.name}/plugin.min.js` ) @@ -78,8 +78,8 @@ describe("plugins", () => { it("gets url with custom S3", async () => { testEnv.withS3() - await testEnv.withTenant(async tenantId => { - const urls = await getEnrichedPluginUrls() + await testEnv.withTenant(tenantId => { + const urls = getEnrichedPluginUrls() expect(urls.jsUrl).toBe( `http://s3.example.com/plugins/${tenantId}/${plugin.name}/plugin.min.js` ) @@ -91,8 +91,8 @@ describe("plugins", () => { it("gets url with cloudfront + s3", async () => { testEnv.withCloudfront() - await testEnv.withTenant(async tenantId => { - const urls = await getEnrichedPluginUrls() + await testEnv.withTenant(tenantId => { + const urls = getEnrichedPluginUrls() // omit rest of signed params expect( urls.jsUrl.includes( diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index 4f07abe7e2..79875b5e99 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -1,15 +1,6 @@ const sanitize = require("sanitize-s3-objectkey") -import { - HeadObjectCommandOutput, - PutObjectCommandInput, - S3, - S3ClientConfig, - GetObjectCommand, - _Object as S3Object, -} from "@aws-sdk/client-s3" -import { Upload } from "@aws-sdk/lib-storage" -import { getSignedUrl } from "@aws-sdk/s3-request-presigner" +import AWS from "aws-sdk" import stream, { Readable } from "stream" import fetch from "node-fetch" import tar from "tar-fs" @@ -22,8 +13,8 @@ import { bucketTTLConfig, budibaseTempDir } from "./utils" import { v4 } from "uuid" import { APP_PREFIX, APP_DEV_PREFIX } from "../db" import fsp from "fs/promises" +import { HeadObjectOutput } from "aws-sdk/clients/s3" import { ReadableStream } from "stream/web" -import { NodeJsRuntimeStreamingBlobPayloadOutputTypes } from "@smithy/types" const streamPipeline = promisify(stream.pipeline) // use this as a temporary store of buckets that are being created @@ -93,24 +84,26 @@ export function sanitizeBucket(input: string) { * @constructor */ export function ObjectStore( + bucket: string, opts: { presigning: boolean } = { presigning: false } ) { - const config: S3ClientConfig = { - forcePathStyle: true, - credentials: { - accessKeyId: env.MINIO_ACCESS_KEY!, - secretAccessKey: env.MINIO_SECRET_KEY!, - }, + const config: AWS.S3.ClientConfiguration = { + s3ForcePathStyle: true, + signatureVersion: "v4", + apiVersion: "2006-03-01", + accessKeyId: env.MINIO_ACCESS_KEY, + secretAccessKey: env.MINIO_SECRET_KEY, region: env.AWS_REGION, } + if (bucket) { + config.params = { + Bucket: sanitizeBucket(bucket), + } + } // for AWS Credentials using temporary session token if (!env.MINIO_ENABLED && env.AWS_SESSION_TOKEN) { - config.credentials = { - accessKeyId: env.MINIO_ACCESS_KEY!, - secretAccessKey: env.MINIO_SECRET_KEY!, - sessionToken: env.AWS_SESSION_TOKEN, - } + config.sessionToken = env.AWS_SESSION_TOKEN } // custom S3 is in use i.e. minio @@ -120,13 +113,13 @@ export function ObjectStore( // Normally a signed url will need to be generated with a specified host in mind. // To support dynamic hosts, e.g. some unknown self-hosted installation url, // use a predefined host. The host 'minio-service' is also forwarded to minio requests via nginx - config.endpoint = "http://minio-service" + config.endpoint = "minio-service" } else { config.endpoint = env.MINIO_URL } } - return new S3(config) + return new AWS.S3(config) } /** @@ -139,25 +132,26 @@ export async function createBucketIfNotExists( ): Promise<{ created: boolean; exists: boolean }> { bucketName = sanitizeBucket(bucketName) try { - await client.headBucket({ - Bucket: bucketName, - }) + await client + .headBucket({ + Bucket: bucketName, + }) + .promise() return { created: false, exists: true } } catch (err: any) { - const statusCode = err.statusCode || err.$response?.statusCode - const promises: Record | undefined> = - STATE.bucketCreationPromises - const doesntExist = statusCode === 404, - noAccess = statusCode === 403 + const promises: any = STATE.bucketCreationPromises + const doesntExist = err.statusCode === 404, + noAccess = err.statusCode === 403 if (promises[bucketName]) { await promises[bucketName] return { created: false, exists: true } } else if (doesntExist || noAccess) { if (doesntExist) { - promises[bucketName] = client.createBucket({ - Bucket: bucketName, - }) - + promises[bucketName] = client + .createBucket({ + Bucket: bucketName, + }) + .promise() await promises[bucketName] delete promises[bucketName] return { created: true, exists: false } @@ -186,26 +180,25 @@ export async function upload({ const fileBytes = path ? (await fsp.open(path)).createReadStream() : body - const objectStore = ObjectStore() + const objectStore = ObjectStore(bucketName) const bucketCreated = await createBucketIfNotExists(objectStore, bucketName) if (ttl && bucketCreated.created) { let ttlConfig = bucketTTLConfig(bucketName, ttl) - await objectStore.putBucketLifecycleConfiguration(ttlConfig) + await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise() } let contentType = type - const finalContentType = contentType - ? contentType - : extension - ? CONTENT_TYPE_MAP[extension.toLowerCase()] - : CONTENT_TYPE_MAP.txt - const config: PutObjectCommandInput = { + if (!contentType) { + contentType = extension + ? CONTENT_TYPE_MAP[extension.toLowerCase()] + : CONTENT_TYPE_MAP.txt + } + const config: any = { // windows file paths need to be converted to forward slashes for s3 - Bucket: sanitizeBucket(bucketName), Key: sanitizeKey(filename), - Body: fileBytes as stream.Readable | Buffer, - ContentType: finalContentType, + Body: fileBytes, + ContentType: contentType, } if (metadata && typeof metadata === "object") { // remove any nullish keys from the metadata object, as these may be considered invalid @@ -214,15 +207,10 @@ export async function upload({ delete metadata[key] } } - config.Metadata = metadata as Record + config.Metadata = metadata } - const upload = new Upload({ - client: objectStore, - params: config, - }) - - return upload.done() + return objectStore.upload(config).promise() } /** @@ -241,12 +229,12 @@ export async function streamUpload({ throw new Error("Stream to upload is invalid/undefined") } const extension = filename.split(".").pop() - const objectStore = ObjectStore() + const objectStore = ObjectStore(bucketName) const bucketCreated = await createBucketIfNotExists(objectStore, bucketName) if (ttl && bucketCreated.created) { let ttlConfig = bucketTTLConfig(bucketName, ttl) - await objectStore.putBucketLifecycleConfiguration(ttlConfig) + await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise() } // Set content type for certain known extensions @@ -279,15 +267,13 @@ export async function streamUpload({ ...extra, } - const upload = new Upload({ - client: objectStore, - params, - }) - const details = await upload.done() - const headDetails = await objectStore.headObject({ - Bucket: bucket, - Key: objKey, - }) + const details = await objectStore.upload(params).promise() + const headDetails = await objectStore + .headObject({ + Bucket: bucket, + Key: objKey, + }) + .promise() return { ...details, ContentLength: headDetails.ContentLength, @@ -298,44 +284,35 @@ export async function streamUpload({ * retrieves the contents of a file from the object store, if it is a known content type it * will be converted, otherwise it will be returned as a buffer stream. */ -export async function retrieve( - bucketName: string, - filepath: string -): Promise { - const objectStore = ObjectStore() +export async function retrieve(bucketName: string, filepath: string) { + const objectStore = ObjectStore(bucketName) const params = { Bucket: sanitizeBucket(bucketName), Key: sanitizeKey(filepath), } - const response = await objectStore.getObject(params) - if (!response.Body) { - throw new Error("Unable to retrieve object") - } - const nodeResponse = - response.Body as NodeJsRuntimeStreamingBlobPayloadOutputTypes + const response: any = await objectStore.getObject(params).promise() // currently these are all strings if (STRING_CONTENT_TYPES.includes(response.ContentType)) { - return nodeResponse.toString() + return response.Body.toString("utf8") } else { - return nodeResponse + return response.Body } } -export async function listAllObjects( - bucketName: string, - path: string -): Promise { - const objectStore = ObjectStore() +export async function listAllObjects(bucketName: string, path: string) { + const objectStore = ObjectStore(bucketName) const list = (params: ListParams = {}) => { - return objectStore.listObjectsV2({ - ...params, - Bucket: sanitizeBucket(bucketName), - Prefix: sanitizeKey(path), - }) + return objectStore + .listObjectsV2({ + ...params, + Bucket: sanitizeBucket(bucketName), + Prefix: sanitizeKey(path), + }) + .promise() } let isTruncated = false, token, - objects: Object[] = [] + objects: AWS.S3.Types.Object[] = [] do { let params: ListParams = {} if (token) { @@ -354,19 +331,18 @@ export async function listAllObjects( /** * Generate a presigned url with a default TTL of 1 hour */ -export async function getPresignedUrl( +export function getPresignedUrl( bucketName: string, key: string, durationSeconds = 3600 ) { - const objectStore = ObjectStore({ presigning: true }) + const objectStore = ObjectStore(bucketName, { presigning: true }) const params = { Bucket: sanitizeBucket(bucketName), Key: sanitizeKey(key), + Expires: durationSeconds, } - const url = await getSignedUrl(objectStore, new GetObjectCommand(params), { - expiresIn: durationSeconds, - }) + const url = objectStore.getSignedUrl("getObject", params) if (!env.MINIO_ENABLED) { // return the full URL to the client @@ -390,11 +366,7 @@ export async function retrieveToTmp(bucketName: string, filepath: string) { filepath = sanitizeKey(filepath) const data = await retrieve(bucketName, filepath) const outputPath = join(budibaseTempDir(), v4()) - if (data instanceof stream.Readable) { - data.pipe(fs.createWriteStream(outputPath)) - } else { - fs.writeFileSync(outputPath, data) - } + fs.writeFileSync(outputPath, data) return outputPath } @@ -436,17 +408,17 @@ export async function retrieveDirectory(bucketName: string, path: string) { * Delete a single file. */ export async function deleteFile(bucketName: string, filepath: string) { - const objectStore = ObjectStore() + const objectStore = ObjectStore(bucketName) await createBucketIfNotExists(objectStore, bucketName) const params = { Bucket: bucketName, Key: sanitizeKey(filepath), } - return objectStore.deleteObject(params) + return objectStore.deleteObject(params).promise() } export async function deleteFiles(bucketName: string, filepaths: string[]) { - const objectStore = ObjectStore() + const objectStore = ObjectStore(bucketName) await createBucketIfNotExists(objectStore, bucketName) const params = { Bucket: bucketName, @@ -454,7 +426,7 @@ export async function deleteFiles(bucketName: string, filepaths: string[]) { Objects: filepaths.map((path: any) => ({ Key: sanitizeKey(path) })), }, } - return objectStore.deleteObjects(params) + return objectStore.deleteObjects(params).promise() } /** @@ -466,13 +438,13 @@ export async function deleteFolder( ): Promise { bucketName = sanitizeBucket(bucketName) folder = sanitizeKey(folder) - const client = ObjectStore() + const client = ObjectStore(bucketName) const listParams = { Bucket: bucketName, Prefix: folder, } - const existingObjectsResponse = await client.listObjects(listParams) + const existingObjectsResponse = await client.listObjects(listParams).promise() if (existingObjectsResponse.Contents?.length === 0) { return } @@ -487,7 +459,7 @@ export async function deleteFolder( deleteParams.Delete.Objects.push({ Key: content.Key }) }) - const deleteResponse = await client.deleteObjects(deleteParams) + const deleteResponse = await client.deleteObjects(deleteParams).promise() // can only empty 1000 items at once if (deleteResponse.Deleted?.length === 1000) { return deleteFolder(bucketName, folder) @@ -562,33 +534,29 @@ export async function getReadStream( ): Promise { bucketName = sanitizeBucket(bucketName) path = sanitizeKey(path) - const client = ObjectStore() + const client = ObjectStore(bucketName) const params = { Bucket: bucketName, Key: path, } - const response = await client.getObject(params) - if (!response.Body || !(response.Body instanceof stream.Readable)) { - throw new Error("Unable to retrieve stream - invalid response") - } - return response.Body + return client.getObject(params).createReadStream() } export async function getObjectMetadata( bucket: string, path: string -): Promise { +): Promise { bucket = sanitizeBucket(bucket) path = sanitizeKey(path) - const client = ObjectStore() + const client = ObjectStore(bucket) const params = { Bucket: bucket, Key: path, } try { - return await client.headObject(params) + return await client.headObject(params).promise() } catch (err: any) { throw new Error("Unable to retrieve metadata from object") } diff --git a/packages/backend-core/src/objectStore/utils.ts b/packages/backend-core/src/objectStore/utils.ts index 2a9dd26e02..30c2fefbf1 100644 --- a/packages/backend-core/src/objectStore/utils.ts +++ b/packages/backend-core/src/objectStore/utils.ts @@ -2,10 +2,7 @@ import path, { join } from "path" import { tmpdir } from "os" import fs from "fs" import env from "../environment" -import { - LifecycleRule, - PutBucketLifecycleConfigurationCommandInput, -} from "@aws-sdk/client-s3" +import { PutBucketLifecycleConfigurationRequest } from "aws-sdk/clients/s3" import * as objectStore from "./objectStore" import { AutomationAttachment, @@ -46,8 +43,8 @@ export function budibaseTempDir() { export const bucketTTLConfig = ( bucketName: string, days: number -): PutBucketLifecycleConfigurationCommandInput => { - const lifecycleRule: LifecycleRule = { +): PutBucketLifecycleConfigurationRequest => { + const lifecycleRule = { ID: `${bucketName}-ExpireAfter${days}days`, Prefix: "", Status: "Enabled", diff --git a/packages/cli/src/backups/objectStore.ts b/packages/cli/src/backups/objectStore.ts index 34e231b87b..2a24199603 100644 --- a/packages/cli/src/backups/objectStore.ts +++ b/packages/cli/src/backups/objectStore.ts @@ -3,7 +3,6 @@ import fs from "fs" import { join } from "path" import { TEMP_DIR, MINIO_DIR } from "./utils" import { progressBar } from "../utils" -import * as stream from "node:stream" const { ObjectStoreBuckets, @@ -21,21 +20,15 @@ export async function exportObjects() { let fullList: any[] = [] let errorCount = 0 for (let bucket of bucketList) { - const client = ObjectStore() + const client = ObjectStore(bucket) try { - await client.headBucket({ - Bucket: bucket, - }) + await client.headBucket().promise() } catch (err) { errorCount++ continue } - const list = await client.listObjectsV2({ - Bucket: bucket, - }) - fullList = fullList.concat( - list.Contents?.map(el => ({ ...el, bucket })) || [] - ) + const list = (await client.listObjectsV2().promise()) as { Contents: any[] } + fullList = fullList.concat(list.Contents.map(el => ({ ...el, bucket }))) } if (errorCount === bucketList.length) { throw new Error("Unable to access MinIO/S3 - check environment config.") @@ -50,13 +43,7 @@ export async function exportObjects() { const dirs = possiblePath.slice(0, possiblePath.length - 1) fs.mkdirSync(join(path, object.bucket, ...dirs), { recursive: true }) } - if (data instanceof stream.Readable) { - data.pipe( - fs.createWriteStream(join(path, object.bucket, ...possiblePath)) - ) - } else { - fs.writeFileSync(join(path, object.bucket, ...possiblePath), data) - } + fs.writeFileSync(join(path, object.bucket, ...possiblePath), data) bar.update(++count) } bar.stop() @@ -73,7 +60,7 @@ export async function importObjects() { const bar = progressBar(total) let count = 0 for (let bucket of buckets) { - const client = ObjectStore() + const client = ObjectStore(bucket) await createBucketIfNotExists(client, bucket) const files = await uploadDirectory(bucket, join(path, bucket), "/") count += files.length diff --git a/packages/server/package.json b/packages/server/package.json index fd448629e8..8cd49a0fe8 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -50,10 +50,6 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "10.0.3", - "@aws-sdk/client-dynamodb": "3.709.0", - "@aws-sdk/client-s3": "3.709.0", - "@aws-sdk/lib-dynamodb": "3.709.0", - "@aws-sdk/s3-request-presigner": "3.709.0", "@azure/msal-node": "^2.5.1", "@budibase/backend-core": "*", "@budibase/client": "*", @@ -74,6 +70,7 @@ "airtable": "0.12.2", "arangojs": "7.2.0", "archiver": "7.0.1", + "aws-sdk": "2.1692.0", "bcrypt": "5.1.0", "bcryptjs": "2.4.3", "bson": "^6.9.0", diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 7ffd075ec0..4169087a63 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -230,7 +230,7 @@ export async function fetchAppPackage( const license = await licensing.cache.getCachedLicense() // Enrich plugin URLs - application.usedPlugins = await objectStore.enrichPluginURLs( + application.usedPlugins = objectStore.enrichPluginURLs( application.usedPlugins ) diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 8b5c61e875..0dd5e77c50 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -18,8 +18,7 @@ import { objectStore, utils, } from "@budibase/backend-core" -import { getSignedUrl } from "@aws-sdk/s3-request-presigner" -import { PutObjectCommand, S3 } from "@aws-sdk/client-s3" +import AWS from "aws-sdk" import fs from "fs" import sdk from "../../../sdk" import * as pro from "@budibase/pro" @@ -129,9 +128,9 @@ export const uploadFile = async function ( return { size: file.size, name: file.name, - url: await objectStore.getAppFileUrl(s3Key), + url: objectStore.getAppFileUrl(s3Key), extension, - key: response.Key!, + key: response.Key, } }) ) @@ -211,11 +210,11 @@ export const serveApp = async function (ctx: UserCtx) { usedPlugins: plugins, favicon: branding.faviconUrl !== "" - ? await objectStore.getGlobalFileUrl("settings", "faviconUrl") + ? objectStore.getGlobalFileUrl("settings", "faviconUrl") : "", logo: config?.logoUrl !== "" - ? await objectStore.getGlobalFileUrl("settings", "logoUrl") + ? objectStore.getGlobalFileUrl("settings", "logoUrl") : "", appMigrating: needMigrations, nonce: ctx.state.nonce, @@ -244,7 +243,7 @@ export const serveApp = async function (ctx: UserCtx) { metaDescription: branding?.metaDescription || "", favicon: branding.faviconUrl !== "" - ? await objectStore.getGlobalFileUrl("settings", "faviconUrl") + ? objectStore.getGlobalFileUrl("settings", "faviconUrl") : "", }) @@ -335,17 +334,16 @@ export const getSignedUploadURL = async function ( ctx.throw(400, "bucket and key values are required") } try { - const s3 = new S3({ + const s3 = new AWS.S3({ region: awsRegion, endpoint: datasource?.config?.endpoint || undefined, - - credentials: { - accessKeyId: datasource?.config?.accessKeyId as string, - secretAccessKey: datasource?.config?.secretAccessKey as string, - }, + accessKeyId: datasource?.config?.accessKeyId as string, + secretAccessKey: datasource?.config?.secretAccessKey as string, + apiVersion: "2006-03-01", + signatureVersion: "v4", }) const params = { Bucket: bucket, Key: key } - signedUrl = await getSignedUrl(s3, new PutObjectCommand(params)) + signedUrl = s3.getSignedUrl("putObject", params) if (datasource?.config?.endpoint) { publicUrl = `${datasource.config.endpoint}/${bucket}/${key}` } else { diff --git a/packages/server/src/api/routes/tests/static.spec.ts b/packages/server/src/api/routes/tests/static.spec.ts index 872085c382..c2808603e9 100644 --- a/packages/server/src/api/routes/tests/static.spec.ts +++ b/packages/server/src/api/routes/tests/static.spec.ts @@ -1,10 +1,12 @@ // Directly mock the AWS SDK -jest.mock("@aws-sdk/s3-request-presigner", () => ({ - getSignedUrl: jest.fn(() => { - return `http://example.com` - }), +jest.mock("aws-sdk", () => ({ + S3: jest.fn(() => ({ + getSignedUrl: jest.fn( + (operation, params) => `http://example.com/${params.Bucket}/${params.Key}` + ), + upload: jest.fn(() => ({ Contents: {} })), + })), })) -jest.mock("@aws-sdk/client-s3") import { Datasource, SourceName } from "@budibase/types" import { setEnv } from "../../../environment" @@ -75,10 +77,7 @@ describe("/static", () => { type: "datasource", name: "Test", source: SourceName.S3, - config: { - accessKeyId: "bb", - secretAccessKey: "bb", - }, + config: {}, }, }) }) @@ -92,7 +91,7 @@ describe("/static", () => { .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) - expect(res.body.signedUrl).toEqual("http://example.com") + expect(res.body.signedUrl).toEqual("http://example.com/foo/bar") expect(res.body.publicUrl).toEqual( `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}` ) diff --git a/packages/server/src/automations/tests/createRow.spec.ts b/packages/server/src/automations/tests/createRow.spec.ts index 42b69324e2..bd78de2217 100644 --- a/packages/server/src/automations/tests/createRow.spec.ts +++ b/packages/server/src/automations/tests/createRow.spec.ts @@ -154,12 +154,11 @@ describe("test the create row action", () => { expect(result.steps[1].outputs.row.file_attachment[0]).toHaveProperty("key") let s3Key = result.steps[1].outputs.row.file_attachment[0].key - const client = objectStore.ObjectStore() + const client = objectStore.ObjectStore(objectStore.ObjectStoreBuckets.APPS) - const objectData = await client.headObject({ - Bucket: objectStore.ObjectStoreBuckets.APPS, - Key: s3Key, - }) + const objectData = await client + .headObject({ Bucket: objectStore.ObjectStoreBuckets.APPS, Key: s3Key }) + .promise() expect(objectData).toBeDefined() expect(objectData.ContentLength).toBeGreaterThan(0) @@ -230,12 +229,11 @@ describe("test the create row action", () => { ) let s3Key = result.steps[1].outputs.row.single_file_attachment.key - const client = objectStore.ObjectStore() + const client = objectStore.ObjectStore(objectStore.ObjectStoreBuckets.APPS) - const objectData = await client.headObject({ - Bucket: objectStore.ObjectStoreBuckets.APPS, - Key: s3Key, - }) + const objectData = await client + .headObject({ Bucket: objectStore.ObjectStoreBuckets.APPS, Key: s3Key }) + .promise() expect(objectData).toBeDefined() expect(objectData.ContentLength).toBeGreaterThan(0) diff --git a/packages/server/src/integrations/dynamodb.ts b/packages/server/src/integrations/dynamodb.ts index 96941ebb0e..424a3dfce0 100644 --- a/packages/server/src/integrations/dynamodb.ts +++ b/packages/server/src/integrations/dynamodb.ts @@ -7,15 +7,9 @@ import { ConnectionInfo, } from "@budibase/types" -import { - DynamoDBDocument, - PutCommandInput, - GetCommandInput, - UpdateCommandInput, - DeleteCommandInput, -} from "@aws-sdk/lib-dynamodb" -import { DynamoDB } from "@aws-sdk/client-dynamodb" +import AWS from "aws-sdk" import { AWS_REGION } from "../constants" +import { DocumentClient } from "aws-sdk/clients/dynamodb" interface DynamoDBConfig { region: string @@ -157,7 +151,7 @@ class DynamoDBIntegration implements IntegrationBase { region: config.region || AWS_REGION, endpoint: config.endpoint || undefined, } - this.client = DynamoDBDocument.from(new DynamoDB(this.config)) + this.client = new AWS.DynamoDB.DocumentClient(this.config) } async testConnection() { @@ -165,8 +159,8 @@ class DynamoDBIntegration implements IntegrationBase { connected: false, } try { - const scanRes = await new DynamoDB(this.config).listTables() - response.connected = !!scanRes.$metadata + const scanRes = await new AWS.DynamoDB(this.config).listTables().promise() + response.connected = !!scanRes.$response } catch (e: any) { response.error = e.message as string } @@ -175,13 +169,13 @@ class DynamoDBIntegration implements IntegrationBase { async create(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.put(params) + return this.client.put(params).promise() } async read(query: { table: string; json: object; index: null | string }) { @@ -190,7 +184,7 @@ class DynamoDBIntegration implements IntegrationBase { IndexName: query.index ? query.index : undefined, ...query.json, } - const response = await this.client.query(params) + const response = await this.client.query(params).promise() if (response.Items) { return response.Items } @@ -203,7 +197,7 @@ class DynamoDBIntegration implements IntegrationBase { IndexName: query.index ? query.index : undefined, ...query.json, } - const response = await this.client.scan(params) + const response = await this.client.scan(params).promise() if (response.Items) { return response.Items } @@ -214,40 +208,40 @@ class DynamoDBIntegration implements IntegrationBase { const params = { TableName: query.table, } - return new DynamoDB(this.config).describeTable(params) + return new AWS.DynamoDB(this.config).describeTable(params).promise() } async get(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.get(params) + return this.client.get(params).promise() } async update(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.update(params) + return this.client.update(params).promise() } async delete(query: { table: string - json: Omit + json: Omit }) { const params = { TableName: query.table, ...query.json, } - return this.client.delete(params) + return this.client.delete(params).promise() } } diff --git a/packages/server/src/integrations/s3.ts b/packages/server/src/integrations/s3.ts index 488c22835a..0b7d774048 100644 --- a/packages/server/src/integrations/s3.ts +++ b/packages/server/src/integrations/s3.ts @@ -7,9 +7,8 @@ import { ConnectionInfo, } from "@budibase/types" -import { S3 } from "@aws-sdk/client-s3" +import AWS from "aws-sdk" import csv from "csvtojson" -import stream from "stream" interface S3Config { region: string @@ -168,7 +167,7 @@ class S3Integration implements IntegrationBase { delete this.config.endpoint } - this.client = new S3(this.config) + this.client = new AWS.S3(this.config) } async testConnection() { @@ -176,7 +175,7 @@ class S3Integration implements IntegrationBase { connected: false, } try { - await this.client.listBuckets() + await this.client.listBuckets().promise() response.connected = true } catch (e: any) { response.error = e.message as string @@ -210,7 +209,7 @@ class S3Integration implements IntegrationBase { LocationConstraint: query.location, } } - return await this.client.createBucket(params) + return await this.client.createBucket(params).promise() } async read(query: { @@ -221,39 +220,37 @@ class S3Integration implements IntegrationBase { maxKeys: number prefix: string }) { - const response = await this.client.listObjects({ - Bucket: query.bucket, - Delimiter: query.delimiter, - Marker: query.marker, - MaxKeys: query.maxKeys, - Prefix: query.prefix, - }) + const response = await this.client + .listObjects({ + Bucket: query.bucket, + Delimiter: query.delimiter, + Marker: query.marker, + MaxKeys: query.maxKeys, + Prefix: query.prefix, + }) + .promise() return response.Contents } async readCsv(query: { bucket: string; key: string }) { - const response = await this.client.getObject({ - Bucket: query.bucket, - Key: query.key, - }) - - const fileStream = response.Body?.transformToWebStream() - - if (!fileStream || !(fileStream instanceof stream.Readable)) { - throw new Error("Unable to retrieve CSV - invalid stream") - } + const stream = this.client + .getObject({ + Bucket: query.bucket, + Key: query.key, + }) + .createReadStream() let csvError = false return new Promise((resolve, reject) => { - fileStream.on("error", (err: Error) => { + stream.on("error", (err: Error) => { reject(err) }) const response = csv() - .fromStream(fileStream) + .fromStream(stream) .on("error", () => { csvError = true }) - fileStream.on("finish", () => { + stream.on("finish", () => { resolve(response) }) }).catch(err => { @@ -266,10 +263,12 @@ class S3Integration implements IntegrationBase { } async delete(query: { bucket: string; delete: string }) { - return await this.client.deleteObjects({ - Bucket: query.bucket, - Delete: JSON.parse(query.delete), - }) + return await this.client + .deleteObjects({ + Bucket: query.bucket, + Delete: JSON.parse(query.delete), + }) + .promise() } } diff --git a/packages/server/src/integrations/tests/aws-sdk.mock.ts b/packages/server/src/integrations/tests/aws-sdk.mock.ts new file mode 100644 index 0000000000..0422adfd3c --- /dev/null +++ b/packages/server/src/integrations/tests/aws-sdk.mock.ts @@ -0,0 +1,76 @@ +const response = (body: any, extra?: any) => () => ({ + promise: () => body, + ...extra, +}) + +class DocumentClient { + put = jest.fn(response({})) + query = jest.fn( + response({ + Items: [], + }) + ) + scan = jest.fn( + response({ + Items: [ + { + Name: "test", + }, + ], + }) + ) + get = jest.fn(response({})) + update = jest.fn(response({})) + delete = jest.fn(response({})) +} + +class S3 { + listObjects = jest.fn( + response({ + Contents: [], + }) + ) + createBucket = jest.fn( + response({ + Contents: {}, + }) + ) + deleteObjects = jest.fn( + response({ + Contents: {}, + }) + ) + getSignedUrl = jest.fn((operation, params) => { + return `http://example.com/${params.Bucket}/${params.Key}` + }) + headBucket = jest.fn( + response({ + Contents: {}, + }) + ) + upload = jest.fn( + response({ + Contents: {}, + }) + ) + getObject = jest.fn( + response( + { + Body: "", + }, + { + createReadStream: jest.fn().mockReturnValue("stream"), + } + ) + ) +} + +module.exports = { + DynamoDB: { + DocumentClient, + }, + S3, + config: { + update: jest.fn(), + }, +} diff --git a/packages/server/src/integrations/tests/dynamodb.spec.ts b/packages/server/src/integrations/tests/dynamodb.spec.ts index 75fb84ae60..c992bc8bfd 100644 --- a/packages/server/src/integrations/tests/dynamodb.spec.ts +++ b/packages/server/src/integrations/tests/dynamodb.spec.ts @@ -1,20 +1,4 @@ -jest.mock("@aws-sdk/lib-dynamodb", () => ({ - DynamoDBDocument: { - from: jest.fn(() => ({ - update: jest.fn(), - put: jest.fn(), - query: jest.fn(() => ({ - Items: [], - })), - scan: jest.fn(() => ({ - Items: [], - })), - delete: jest.fn(), - get: jest.fn(), - })), - }, -})) -jest.mock("@aws-sdk/client-dynamodb") +jest.mock("aws-sdk", () => require("./aws-sdk.mock")) import { default as DynamoDBIntegration } from "../dynamodb" class TestConfiguration { @@ -73,7 +57,11 @@ describe("DynamoDB Integration", () => { TableName: tableName, IndexName: indexName, }) - expect(response).toEqual([]) + expect(response).toEqual([ + { + Name: "test", + }, + ]) }) it("calls the get method with the correct params", async () => { diff --git a/packages/server/src/integrations/tests/s3.spec.ts b/packages/server/src/integrations/tests/s3.spec.ts index 678f15bf17..abe8fb9cf1 100644 --- a/packages/server/src/integrations/tests/s3.spec.ts +++ b/packages/server/src/integrations/tests/s3.spec.ts @@ -1,52 +1,5 @@ +jest.mock("aws-sdk", () => require("./aws-sdk.mock")) import { default as S3Integration } from "../s3" -jest.mock("@aws-sdk/client-s3", () => { - class S3Mock { - response(body: any, extra?: any) { - return () => ({ - promise: () => body, - ...extra, - }) - } - - listObjects = jest.fn( - this.response({ - Contents: [], - }) - ) - createBucket = jest.fn( - this.response({ - Contents: {}, - }) - ) - deleteObjects = jest.fn( - this.response({ - Contents: {}, - }) - ) - headBucket = jest.fn( - this.response({ - Contents: {}, - }) - ) - upload = jest.fn( - this.response({ - Contents: {}, - }) - ) - getObject = jest.fn( - this.response( - { - Body: "", - }, - { - createReadStream: jest.fn().mockReturnValue("stream"), - } - ) - ) - } - - return { S3: S3Mock } -}) class TestConfiguration { integration: any diff --git a/packages/server/src/integrations/utils/utils.ts b/packages/server/src/integrations/utils/utils.ts index db9148ae90..315a8010e8 100644 --- a/packages/server/src/integrations/utils/utils.ts +++ b/packages/server/src/integrations/utils/utils.ts @@ -430,7 +430,7 @@ export async function handleFileResponse( size = details.ContentLength } } - presignedUrl = await objectStore.getPresignedUrl(bucket, key) + presignedUrl = objectStore.getPresignedUrl(bucket, key) return { data: { size, diff --git a/packages/server/src/sdk/plugins/plugins.ts b/packages/server/src/sdk/plugins/plugins.ts index bff24dcef7..63f2f22cd9 100644 --- a/packages/server/src/sdk/plugins/plugins.ts +++ b/packages/server/src/sdk/plugins/plugins.ts @@ -18,7 +18,7 @@ export async function fetch(type?: PluginType): Promise { }) ) let plugins = response.rows.map((row: any) => row.doc) as Plugin[] - plugins = await objectStore.enrichPluginURLs(plugins) + plugins = objectStore.enrichPluginURLs(plugins) if (type) { return plugins.filter((plugin: Plugin) => plugin.schema?.type === type) } else { diff --git a/packages/server/src/utilities/fileSystem/app.ts b/packages/server/src/utilities/fileSystem/app.ts index 642017d2da..9bd88ba0b1 100644 --- a/packages/server/src/utilities/fileSystem/app.ts +++ b/packages/server/src/utilities/fileSystem/app.ts @@ -78,7 +78,7 @@ export const getComponentLibraryManifest = async (library: string) => { resp = await objectStore.retrieve(ObjectStoreBuckets.APPS, path) } if (typeof resp !== "string") { - resp = resp.toString() + resp = resp.toString("utf8") } return JSON.parse(resp) } diff --git a/packages/server/src/utilities/fileSystem/plugin.ts b/packages/server/src/utilities/fileSystem/plugin.ts index 2949daef61..3e1e9bef4d 100644 --- a/packages/server/src/utilities/fileSystem/plugin.ts +++ b/packages/server/src/utilities/fileSystem/plugin.ts @@ -3,7 +3,6 @@ import { budibaseTempDir } from "../budibaseDir" import fs from "fs" import { join } from "path" import { objectStore } from "@budibase/backend-core" -import stream from "stream" const DATASOURCE_PATH = join(budibaseTempDir(), "datasource") const AUTOMATION_PATH = join(budibaseTempDir(), "automation") @@ -59,11 +58,7 @@ async function getPluginImpl(path: string, plugin: Plugin) { pluginKey ) - if (pluginJs instanceof stream.Readable) { - pluginJs.pipe(fs.createWriteStream(filename)) - } else { - fs.writeFileSync(filename, pluginJs) - } + fs.writeFileSync(filename, pluginJs) fs.writeFileSync(metadataName, hash) return require(filename) diff --git a/packages/server/src/utilities/rowProcessor/index.ts b/packages/server/src/utilities/rowProcessor/index.ts index 7c01c54f13..14b524fd95 100644 --- a/packages/server/src/utilities/rowProcessor/index.ts +++ b/packages/server/src/utilities/rowProcessor/index.ts @@ -359,9 +359,9 @@ export async function coreOutputProcessing( if (row[property] == null) { continue } - const process = async (attachment: RowAttachment) => { + const process = (attachment: RowAttachment) => { if (!attachment.url && attachment.key) { - attachment.url = await objectStore.getAppFileUrl(attachment.key) + attachment.url = objectStore.getAppFileUrl(attachment.key) } return attachment } @@ -369,13 +369,11 @@ export async function coreOutputProcessing( row[property] = JSON.parse(row[property]) } if (Array.isArray(row[property])) { - await Promise.all( - row[property].map((attachment: RowAttachment) => - process(attachment) - ) - ) + row[property].forEach((attachment: RowAttachment) => { + process(attachment) + }) } else { - await process(row[property]) + process(row[property]) } } } else if ( diff --git a/packages/worker/src/api/controllers/global/configs.ts b/packages/worker/src/api/controllers/global/configs.ts index 4ee8dcbb24..a10fce35f6 100644 --- a/packages/worker/src/api/controllers/global/configs.ts +++ b/packages/worker/src/api/controllers/global/configs.ts @@ -322,27 +322,27 @@ export async function save( } } -async function enrichOIDCLogos(oidcLogos: OIDCLogosConfig) { +function enrichOIDCLogos(oidcLogos: OIDCLogosConfig) { if (!oidcLogos) { return } - const newConfig: Record = {} - const keys = Object.keys(oidcLogos.config || {}) - - for (const key of keys) { - if (!key.endsWith("Etag")) { - const etag = oidcLogos.config[`${key}Etag`] - const objectStoreUrl = await objectStore.getGlobalFileUrl( - oidcLogos.type, - key, - etag - ) - newConfig[key] = objectStoreUrl - } else { - newConfig[key] = oidcLogos.config[key] - } - } - oidcLogos.config = newConfig + oidcLogos.config = Object.keys(oidcLogos.config || {}).reduce( + (acc: any, key: string) => { + if (!key.endsWith("Etag")) { + const etag = oidcLogos.config[`${key}Etag`] + const objectStoreUrl = objectStore.getGlobalFileUrl( + oidcLogos.type, + key, + etag + ) + acc[key] = objectStoreUrl + } else { + acc[key] = oidcLogos.config[key] + } + return acc + }, + {} + ) } export async function find(ctx: UserCtx) { @@ -370,7 +370,7 @@ export async function find(ctx: UserCtx) { async function handleConfigType(type: ConfigType, config: Config) { if (type === ConfigType.OIDC_LOGOS) { - await enrichOIDCLogos(config) + enrichOIDCLogos(config) } else if (type === ConfigType.AI) { await handleAIConfig(config) } @@ -396,7 +396,7 @@ export async function publicOidc(ctx: Ctx) { const oidcCustomLogos = await configs.getOIDCLogosDoc() if (oidcCustomLogos) { - await enrichOIDCLogos(oidcCustomLogos) + enrichOIDCLogos(oidcCustomLogos) } if (!oidcConfig) { @@ -427,7 +427,7 @@ export async function publicSettings( // enrich the logo url - empty url means deleted if (config.logoUrl && config.logoUrl !== "") { - config.logoUrl = await objectStore.getGlobalFileUrl( + config.logoUrl = objectStore.getGlobalFileUrl( "settings", "logoUrl", config.logoUrlEtag @@ -437,7 +437,7 @@ export async function publicSettings( // enrich the favicon url - empty url means deleted const faviconUrl = branding.faviconUrl && branding.faviconUrl !== "" - ? await objectStore.getGlobalFileUrl( + ? objectStore.getGlobalFileUrl( "settings", "faviconUrl", branding.faviconUrlEtag @@ -522,7 +522,7 @@ export async function upload(ctx: UserCtx) { ctx.body = { message: "File has been uploaded and url stored to config.", - url: await objectStore.getGlobalFileUrl(type, name, etag), + url: objectStore.getGlobalFileUrl(type, name, etag), } } diff --git a/yarn.lock b/yarn.lock index a9517925a8..c54385478e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,121 +150,6 @@ "@smithy/util-utf8" "^2.0.0" tslib "^2.6.2" -"@aws-sdk/client-dynamodb@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-dynamodb/-/client-dynamodb-3.709.0.tgz#589cfab9d27f7d0d2056f72e4674315ccd98b6bc" - integrity sha512-p/GVuEgfPccFUm5lxr7EPi5gQAsUO4SDdKcIV+v/dNwtH2SXEgnFN0o1TEIJtuVY3BsQyXyR1aMjeQ81O832kw== - dependencies: - "@aws-crypto/sha256-browser" "5.2.0" - "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/client-sso-oidc" "3.709.0" - "@aws-sdk/client-sts" "3.709.0" - "@aws-sdk/core" "3.709.0" - "@aws-sdk/credential-provider-node" "3.709.0" - "@aws-sdk/middleware-endpoint-discovery" "3.709.0" - "@aws-sdk/middleware-host-header" "3.709.0" - "@aws-sdk/middleware-logger" "3.709.0" - "@aws-sdk/middleware-recursion-detection" "3.709.0" - "@aws-sdk/middleware-user-agent" "3.709.0" - "@aws-sdk/region-config-resolver" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-endpoints" "3.709.0" - "@aws-sdk/util-user-agent-browser" "3.709.0" - "@aws-sdk/util-user-agent-node" "3.709.0" - "@smithy/config-resolver" "^3.0.13" - "@smithy/core" "^2.5.5" - "@smithy/fetch-http-handler" "^4.1.2" - "@smithy/hash-node" "^3.0.11" - "@smithy/invalid-dependency" "^3.0.11" - "@smithy/middleware-content-length" "^3.0.13" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/middleware-retry" "^3.0.30" - "@smithy/middleware-serde" "^3.0.11" - "@smithy/middleware-stack" "^3.0.11" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/node-http-handler" "^3.3.2" - "@smithy/protocol-http" "^4.1.8" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/url-parser" "^3.0.11" - "@smithy/util-base64" "^3.0.0" - "@smithy/util-body-length-browser" "^3.0.0" - "@smithy/util-body-length-node" "^3.0.0" - "@smithy/util-defaults-mode-browser" "^3.0.30" - "@smithy/util-defaults-mode-node" "^3.0.30" - "@smithy/util-endpoints" "^2.1.7" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-retry" "^3.0.11" - "@smithy/util-utf8" "^3.0.0" - "@smithy/util-waiter" "^3.2.0" - "@types/uuid" "^9.0.1" - tslib "^2.6.2" - uuid "^9.0.1" - -"@aws-sdk/client-s3@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.709.0.tgz#ae27e18c5ced29f0d24857e4a28fb6947cdba3a4" - integrity sha512-IvC7coELoQ4YenTdULArVdL5yk6jNRVUALX1aqv9JlPdrXxb3Om6YrM9e7AlSTLxrULTsAe1ubm8i/DmcSY/Ng== - dependencies: - "@aws-crypto/sha1-browser" "5.2.0" - "@aws-crypto/sha256-browser" "5.2.0" - "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/client-sso-oidc" "3.709.0" - "@aws-sdk/client-sts" "3.709.0" - "@aws-sdk/core" "3.709.0" - "@aws-sdk/credential-provider-node" "3.709.0" - "@aws-sdk/middleware-bucket-endpoint" "3.709.0" - "@aws-sdk/middleware-expect-continue" "3.709.0" - "@aws-sdk/middleware-flexible-checksums" "3.709.0" - "@aws-sdk/middleware-host-header" "3.709.0" - "@aws-sdk/middleware-location-constraint" "3.709.0" - "@aws-sdk/middleware-logger" "3.709.0" - "@aws-sdk/middleware-recursion-detection" "3.709.0" - "@aws-sdk/middleware-sdk-s3" "3.709.0" - "@aws-sdk/middleware-ssec" "3.709.0" - "@aws-sdk/middleware-user-agent" "3.709.0" - "@aws-sdk/region-config-resolver" "3.709.0" - "@aws-sdk/signature-v4-multi-region" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-endpoints" "3.709.0" - "@aws-sdk/util-user-agent-browser" "3.709.0" - "@aws-sdk/util-user-agent-node" "3.709.0" - "@aws-sdk/xml-builder" "3.709.0" - "@smithy/config-resolver" "^3.0.13" - "@smithy/core" "^2.5.5" - "@smithy/eventstream-serde-browser" "^3.0.14" - "@smithy/eventstream-serde-config-resolver" "^3.0.11" - "@smithy/eventstream-serde-node" "^3.0.13" - "@smithy/fetch-http-handler" "^4.1.2" - "@smithy/hash-blob-browser" "^3.1.10" - "@smithy/hash-node" "^3.0.11" - "@smithy/hash-stream-node" "^3.1.10" - "@smithy/invalid-dependency" "^3.0.11" - "@smithy/md5-js" "^3.0.11" - "@smithy/middleware-content-length" "^3.0.13" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/middleware-retry" "^3.0.30" - "@smithy/middleware-serde" "^3.0.11" - "@smithy/middleware-stack" "^3.0.11" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/node-http-handler" "^3.3.2" - "@smithy/protocol-http" "^4.1.8" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/url-parser" "^3.0.11" - "@smithy/util-base64" "^3.0.0" - "@smithy/util-body-length-browser" "^3.0.0" - "@smithy/util-body-length-node" "^3.0.0" - "@smithy/util-defaults-mode-browser" "^3.0.30" - "@smithy/util-defaults-mode-node" "^3.0.30" - "@smithy/util-endpoints" "^2.1.7" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-retry" "^3.0.11" - "@smithy/util-stream" "^3.3.2" - "@smithy/util-utf8" "^3.0.0" - "@smithy/util-waiter" "^3.2.0" - tslib "^2.6.2" - "@aws-sdk/client-s3@^3.388.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.693.0.tgz#188b621498ffaeb7b1ea5794f61e3e8d9a4bcac2" @@ -374,51 +259,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@aws-sdk/client-sso-oidc@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.709.0.tgz#959e4df4070f1d059d8d0cd5b9028d9a46ac7ecf" - integrity sha512-1w6egz17QQy661lNCRmZZlqIANEbD6g2VFAQIJbVwSiu7brg+GUns+mT1eLLLHAMQc1sL0Ds8/ybSK2SrgGgIA== - dependencies: - "@aws-crypto/sha256-browser" "5.2.0" - "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "3.709.0" - "@aws-sdk/credential-provider-node" "3.709.0" - "@aws-sdk/middleware-host-header" "3.709.0" - "@aws-sdk/middleware-logger" "3.709.0" - "@aws-sdk/middleware-recursion-detection" "3.709.0" - "@aws-sdk/middleware-user-agent" "3.709.0" - "@aws-sdk/region-config-resolver" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-endpoints" "3.709.0" - "@aws-sdk/util-user-agent-browser" "3.709.0" - "@aws-sdk/util-user-agent-node" "3.709.0" - "@smithy/config-resolver" "^3.0.13" - "@smithy/core" "^2.5.5" - "@smithy/fetch-http-handler" "^4.1.2" - "@smithy/hash-node" "^3.0.11" - "@smithy/invalid-dependency" "^3.0.11" - "@smithy/middleware-content-length" "^3.0.13" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/middleware-retry" "^3.0.30" - "@smithy/middleware-serde" "^3.0.11" - "@smithy/middleware-stack" "^3.0.11" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/node-http-handler" "^3.3.2" - "@smithy/protocol-http" "^4.1.8" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/url-parser" "^3.0.11" - "@smithy/util-base64" "^3.0.0" - "@smithy/util-body-length-browser" "^3.0.0" - "@smithy/util-body-length-node" "^3.0.0" - "@smithy/util-defaults-mode-browser" "^3.0.30" - "@smithy/util-defaults-mode-node" "^3.0.30" - "@smithy/util-endpoints" "^2.1.7" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-retry" "^3.0.11" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@aws-sdk/client-sso@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.693.0.tgz#9cd5e07e57013b8c7980512810d775d7b6f67e36" @@ -463,50 +303,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@aws-sdk/client-sso@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.709.0.tgz#b5b29161e07af6f82afd7a6e750c09b0158d19e3" - integrity sha512-Qxeo8cN0jNy6Wnbqq4wucffAGJM6sJjofoTgNtPA6cC7sPYx7aYC6OAAAo6NaMRY+WywOKdS9Wgjx2QYRxKx7w== - dependencies: - "@aws-crypto/sha256-browser" "5.2.0" - "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/core" "3.709.0" - "@aws-sdk/middleware-host-header" "3.709.0" - "@aws-sdk/middleware-logger" "3.709.0" - "@aws-sdk/middleware-recursion-detection" "3.709.0" - "@aws-sdk/middleware-user-agent" "3.709.0" - "@aws-sdk/region-config-resolver" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-endpoints" "3.709.0" - "@aws-sdk/util-user-agent-browser" "3.709.0" - "@aws-sdk/util-user-agent-node" "3.709.0" - "@smithy/config-resolver" "^3.0.13" - "@smithy/core" "^2.5.5" - "@smithy/fetch-http-handler" "^4.1.2" - "@smithy/hash-node" "^3.0.11" - "@smithy/invalid-dependency" "^3.0.11" - "@smithy/middleware-content-length" "^3.0.13" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/middleware-retry" "^3.0.30" - "@smithy/middleware-serde" "^3.0.11" - "@smithy/middleware-stack" "^3.0.11" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/node-http-handler" "^3.3.2" - "@smithy/protocol-http" "^4.1.8" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/url-parser" "^3.0.11" - "@smithy/util-base64" "^3.0.0" - "@smithy/util-body-length-browser" "^3.0.0" - "@smithy/util-body-length-node" "^3.0.0" - "@smithy/util-defaults-mode-browser" "^3.0.30" - "@smithy/util-defaults-mode-node" "^3.0.30" - "@smithy/util-endpoints" "^2.1.7" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-retry" "^3.0.11" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@aws-sdk/client-sts@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.693.0.tgz#9e2c418f4850269635632bee4d1a31057c04bcc5" @@ -553,52 +349,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@aws-sdk/client-sts@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.709.0.tgz#b9ad3c9c6419d0d149b28cdd6c115cc40c4e7906" - integrity sha512-cBAvlPg6yslXNL385UUGFPw+XY+lA9BzioNdIFkMo3fEUlTShogTtiWz4LsyLHoN6LhKojssP9DSmmWKWjCZIw== - dependencies: - "@aws-crypto/sha256-browser" "5.2.0" - "@aws-crypto/sha256-js" "5.2.0" - "@aws-sdk/client-sso-oidc" "3.709.0" - "@aws-sdk/core" "3.709.0" - "@aws-sdk/credential-provider-node" "3.709.0" - "@aws-sdk/middleware-host-header" "3.709.0" - "@aws-sdk/middleware-logger" "3.709.0" - "@aws-sdk/middleware-recursion-detection" "3.709.0" - "@aws-sdk/middleware-user-agent" "3.709.0" - "@aws-sdk/region-config-resolver" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-endpoints" "3.709.0" - "@aws-sdk/util-user-agent-browser" "3.709.0" - "@aws-sdk/util-user-agent-node" "3.709.0" - "@smithy/config-resolver" "^3.0.13" - "@smithy/core" "^2.5.5" - "@smithy/fetch-http-handler" "^4.1.2" - "@smithy/hash-node" "^3.0.11" - "@smithy/invalid-dependency" "^3.0.11" - "@smithy/middleware-content-length" "^3.0.13" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/middleware-retry" "^3.0.30" - "@smithy/middleware-serde" "^3.0.11" - "@smithy/middleware-stack" "^3.0.11" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/node-http-handler" "^3.3.2" - "@smithy/protocol-http" "^4.1.8" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/url-parser" "^3.0.11" - "@smithy/util-base64" "^3.0.0" - "@smithy/util-body-length-browser" "^3.0.0" - "@smithy/util-body-length-node" "^3.0.0" - "@smithy/util-defaults-mode-browser" "^3.0.30" - "@smithy/util-defaults-mode-node" "^3.0.30" - "@smithy/util-endpoints" "^2.1.7" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-retry" "^3.0.11" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@aws-sdk/core@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.693.0.tgz#437969dd740895a59863d737bad14646bc2e1725" @@ -616,23 +366,6 @@ fast-xml-parser "4.4.1" tslib "^2.6.2" -"@aws-sdk/core@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.709.0.tgz#d2b3d5b90f6614e3afc109ebdcaaedbb54c2d68b" - integrity sha512-7kuSpzdOTAE026j85wq/fN9UDZ70n0OHw81vFqMWwlEFtm5IQ/MRCLKcC4HkXxTdfy1PqFlmoXxWqeBa15tujw== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/core" "^2.5.5" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/property-provider" "^3.1.11" - "@smithy/protocol-http" "^4.1.8" - "@smithy/signature-v4" "^4.2.4" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/util-middleware" "^3.0.11" - fast-xml-parser "4.4.1" - tslib "^2.6.2" - "@aws-sdk/credential-provider-env@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.693.0.tgz#f97feed9809fe2800216943470015fdaaba47c4f" @@ -644,17 +377,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/credential-provider-env@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.709.0.tgz#a7f75375d8a413f9ab2bc42f743b943da6d3362d" - integrity sha512-ZMAp9LSikvHDFVa84dKpQmow6wsg956Um20cKuioPpX2GGreJFur7oduD+tRJT6FtIOHn+64YH+0MwiXLhsaIQ== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/property-provider" "^3.1.11" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/credential-provider-http@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.693.0.tgz#5caad0ac47eded1edeb63f907280580ccfaadba3" @@ -671,22 +393,6 @@ "@smithy/util-stream" "^3.3.0" tslib "^2.6.2" -"@aws-sdk/credential-provider-http@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.709.0.tgz#a378cbcc4cf373cc277944f1e84e9952f3884f5d" - integrity sha512-lIS7XLwCOyJnLD70f+VIRr8DNV1HPQe9oN6aguYrhoczqz7vDiVZLe3lh714cJqq9rdxzFypK5DqKHmcscMEPQ== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/fetch-http-handler" "^4.1.2" - "@smithy/node-http-handler" "^3.3.2" - "@smithy/property-provider" "^3.1.11" - "@smithy/protocol-http" "^4.1.8" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/util-stream" "^3.3.2" - tslib "^2.6.2" - "@aws-sdk/credential-provider-ini@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.693.0.tgz#b4557ac1092657660a15c9bd55e17c27f79ec621" @@ -705,24 +411,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/credential-provider-ini@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.709.0.tgz#b01c68d98ce4cc48f79405234e32a9de2f943ea1" - integrity sha512-qCF8IIGcPoUp+Ib3ANhbF5gElxFd+kIrtv2/1tKdvhudMANstQbMiWV0LTH47ZZR6c3as4iSrm09NZnpEoD/pA== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/credential-provider-env" "3.709.0" - "@aws-sdk/credential-provider-http" "3.709.0" - "@aws-sdk/credential-provider-process" "3.709.0" - "@aws-sdk/credential-provider-sso" "3.709.0" - "@aws-sdk/credential-provider-web-identity" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/credential-provider-imds" "^3.2.8" - "@smithy/property-provider" "^3.1.11" - "@smithy/shared-ini-file-loader" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/credential-provider-node@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.693.0.tgz#c5ceac64a69304d5b4db3fd68473480cafddb4a9" @@ -741,24 +429,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/credential-provider-node@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.709.0.tgz#270a31aae394e6c8fe7d3fdd0b92e7c3a863b933" - integrity sha512-4HRX9KYWPSjO5O/Vg03YAsebKpvTjTvpK1n7zHYBmlLMBLxUrVsL1nNKKC5p2/7OW3RL8XR1ki3QkoV7kGRxUQ== - dependencies: - "@aws-sdk/credential-provider-env" "3.709.0" - "@aws-sdk/credential-provider-http" "3.709.0" - "@aws-sdk/credential-provider-ini" "3.709.0" - "@aws-sdk/credential-provider-process" "3.709.0" - "@aws-sdk/credential-provider-sso" "3.709.0" - "@aws-sdk/credential-provider-web-identity" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/credential-provider-imds" "^3.2.8" - "@smithy/property-provider" "^3.1.11" - "@smithy/shared-ini-file-loader" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/credential-provider-process@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.693.0.tgz#e84e945f1a148f06ff697608d5309e73347e5aa9" @@ -771,18 +441,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/credential-provider-process@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.709.0.tgz#2521f810590f0874c54cc842d3d56f455a728325" - integrity sha512-IAC+jPlGQII6jhIylHOwh3RgSobqlgL59nw2qYTURr8hMCI0Z1p5y2ee646HTVt4WeCYyzUAXfxr6YI/Vitv+Q== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/property-provider" "^3.1.11" - "@smithy/shared-ini-file-loader" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/credential-provider-sso@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.693.0.tgz#72767389f533d9d17a14af63daaafcc8368ab43a" @@ -797,20 +455,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/credential-provider-sso@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.709.0.tgz#f0cb855eed86748ff0c9afa06b3a234fb04b3206" - integrity sha512-rYdTDOxazS2GdGScelsRK5CAkktRLCCdRjlwXaxrcW57j749hEqxcF5uTv9RD6WBwInfedcSywErNZB+hylQlg== - dependencies: - "@aws-sdk/client-sso" "3.709.0" - "@aws-sdk/core" "3.709.0" - "@aws-sdk/token-providers" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/property-provider" "^3.1.11" - "@smithy/shared-ini-file-loader" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/credential-provider-web-identity@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.693.0.tgz#b6133b5ef9d3582e36e02e9c66766714ff672a11" @@ -822,50 +466,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/credential-provider-web-identity@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.709.0.tgz#c2b03541cb57ae4c7d6abdca98f99a6a56833ea6" - integrity sha512-2lbDfE0IQ6gma/7BB2JpkjW5G0wGe4AS0x80oybYAYYviJmUtIR3Cn2pXun6bnAWElt4wYKl4su7oC36rs5rNA== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/property-provider" "^3.1.11" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - -"@aws-sdk/endpoint-cache@3.693.0": - version "3.693.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/endpoint-cache/-/endpoint-cache-3.693.0.tgz#4b3f0bbc16dc2907e1b977e3d8ddfc7ba008fd12" - integrity sha512-/zK0ZZncBf5FbTfo8rJMcQIXXk4Ibhe5zEMiwFNivVPR2uNC0+oqfwXz7vjxwY0t6BPE3Bs4h9uFEz4xuGCY6w== - dependencies: - mnemonist "0.38.3" - tslib "^2.6.2" - -"@aws-sdk/lib-dynamodb@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.709.0.tgz#fd90b76bce67af1a3079524710f7bc19647829ad" - integrity sha512-piIyvQ1DhoUEosKmjGnMxLClUb9tv5rPPZfgh9J4MmSygsYbE9HvC3tstje0xUudVZjsmzZpNyibl/n0LA0gdQ== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/util-dynamodb" "3.709.0" - "@smithy/core" "^2.5.5" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - -"@aws-sdk/lib-storage@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/lib-storage/-/lib-storage-3.709.0.tgz#2b12e558880418c3348cbd8f1e4e7f8db424b7b7" - integrity sha512-TnP+QSsWdiaQYS5HuB3n9H947z49m6qSEv5fth4L9xinBldLepLyyF+cua3/GlagkWqpxcATISgR9pE1PB0mhQ== - dependencies: - "@smithy/abort-controller" "^3.1.9" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/smithy-client" "^3.5.0" - buffer "5.6.0" - events "3.3.0" - stream-browserify "3.0.0" - tslib "^2.6.2" - "@aws-sdk/middleware-bucket-endpoint@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.693.0.tgz#e4823a40935d34f5e58a4fbc830d8ff92e44fc99" @@ -879,31 +479,6 @@ "@smithy/util-config-provider" "^3.0.0" tslib "^2.6.2" -"@aws-sdk/middleware-bucket-endpoint@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.709.0.tgz#a69bdebfebb7b5b174d3a396f2361f5025d168f4" - integrity sha512-03+tJOd7KIZOiqWH7Z8BOfQIWkKJgjcpKOJKZ6FR2KjWGUOE1G+bo11wF4UuHQ0RmpKnApt+pQghZmSnE7WEeg== - dependencies: - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-arn-parser" "3.693.0" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - "@smithy/util-config-provider" "^3.0.0" - tslib "^2.6.2" - -"@aws-sdk/middleware-endpoint-discovery@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.709.0.tgz#d5866603f2515f0da2c84ead99cd25b806d8ee5b" - integrity sha512-6CSHoAy3sVBJdeGiBpoRqVHpqLPqv5QuDxKsEMHoGdbGATmffyn2whTFfo5hfRYsN9WPz/XxUX2iynqQCnlrzw== - dependencies: - "@aws-sdk/endpoint-cache" "3.693.0" - "@aws-sdk/types" "3.709.0" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/middleware-expect-continue@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.693.0.tgz#d8696cee9ebea1d973d8daf872fd913b41d62cf0" @@ -914,16 +489,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/middleware-expect-continue@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.709.0.tgz#a7fec776da9de32e15088badfc09d69118f5d5ab" - integrity sha512-Tbl/DFvE4rHl8lMb9IzetwK4tf5R3VeHZkvEXQalsWoK0tbEQ8kXWi7wAYO4qbE7bFVvaxKX+irjJjTxf3BrCQ== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/middleware-flexible-checksums@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.693.0.tgz#80f07802d98ff33a6899a09c59cf51aab426aaac" @@ -943,25 +508,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@aws-sdk/middleware-flexible-checksums@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.709.0.tgz#f0fb543c2db724cb43bae215ff0aea942d06a967" - integrity sha512-wbYm9tkyCaqMeU82yjaXw7V5BxCSlSLNupENW63LC7Fvyo/aQzj6LjSMHcBpR2QwjBEhXCtF47L7aQ8SPTNhdw== - dependencies: - "@aws-crypto/crc32" "5.2.0" - "@aws-crypto/crc32c" "5.2.0" - "@aws-crypto/util" "5.2.0" - "@aws-sdk/core" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/is-array-buffer" "^3.0.0" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-stream" "^3.3.2" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@aws-sdk/middleware-host-header@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.693.0.tgz#69322909c0792df1e6be7c7fb5e2b6f76090a55c" @@ -972,16 +518,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/middleware-host-header@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.709.0.tgz#f44f5c62f9bd7e5a443603fed68143d2d9725219" - integrity sha512-8gQYCYAaIw4lOCd5WYdf15Y/61MgRsAnrb2eiTl+icMlUOOzl8aOl5iDwm/Idp0oHZTflwxM4XSvGXO83PRWcw== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/middleware-location-constraint@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.693.0.tgz#1856eaaad64d41d1f8fa53ced58a6c7cf5eccc6e" @@ -991,15 +527,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/middleware-location-constraint@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.709.0.tgz#4437d3d3cfbbdfca60664b1f237d600b94fd06a5" - integrity sha512-5YQWPXfZq7OE0jB2G0PP8K10GBod/YPJXb+1CfJS6FbQaglRoIm8KZmVEvJNnptSKyGtE62veeCcCQcfAUfFig== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/middleware-logger@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.693.0.tgz#fc10294e6963f8e5d58ba1ededd891e999f544a9" @@ -1009,15 +536,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/middleware-logger@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.709.0.tgz#b9a0b016b7ae09cb502cc4faf45964d4b5745824" - integrity sha512-jDoGSccXv9zebnpUoisjWd5u5ZPIalrmm6TjvPzZ8UqzQt3Beiz0tnQwmxQD6KRc7ADweWP5Ntiqzbw9xpVajg== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/middleware-recursion-detection@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.693.0.tgz#88a8157293775e7116707da26501da4b5e042f51" @@ -1028,16 +546,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/middleware-recursion-detection@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.709.0.tgz#d7dc253d4858d496caeb12dd6cddd87b250fb98b" - integrity sha512-PObL/wLr4lkfbQ0yXUWaoCWu/jcwfwZzCjsUiXW/H6hW9b/00enZxmx7OhtJYaR6xmh/Lcx5wbhIoDCbzdv0tw== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/middleware-sdk-s3@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.693.0.tgz#e0850854d5079f372786b2ccfe85729caa7a49d8" @@ -1058,26 +566,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@aws-sdk/middleware-sdk-s3@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.709.0.tgz#b6f22c77e64760869eb06255af58376f879742b2" - integrity sha512-FwtOG9t9xsLoLOQZ6qAdsWOjx9dsO6t28IjIDV1l6Ixiu2oC0Yks7goONjJUH0IDE4pDDDGzmuq0sn1XtHhheA== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-arn-parser" "3.693.0" - "@smithy/core" "^2.5.5" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/protocol-http" "^4.1.8" - "@smithy/signature-v4" "^4.2.4" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/util-config-provider" "^3.0.0" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-stream" "^3.3.2" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@aws-sdk/middleware-ssec@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.693.0.tgz#2ff779147d188090b3a6cda3ed12ca4085220a73" @@ -1087,15 +575,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/middleware-ssec@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.709.0.tgz#bbf5253cdce45ed2759a108fd924fff4b8e049d5" - integrity sha512-2muiLe7YkmlwZp2SKz+goZrDThGfRq3o0FcJF3Puc0XGmcEPEDjih537mCoTrGgcXNFlBc7YChd84r3t72ySaQ== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/middleware-user-agent@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.693.0.tgz#4b55cfab3fc7e671b08e1ea63a98e45a1e13e6a5" @@ -1109,19 +588,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/middleware-user-agent@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.709.0.tgz#2a467f14b3f4a9270bcdfde32e3d4e38701aaafe" - integrity sha512-ooc9ZJvgkjPhi9q05XwSfNTXkEBEIfL4hleo5rQBKwHG3aTHvwOM7LLzhdX56QZVa6sorPBp6fwULuRDSqiQHw== - dependencies: - "@aws-sdk/core" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-endpoints" "3.709.0" - "@smithy/core" "^2.5.5" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/node-http-handler@^3.374.0": version "3.374.0" resolved "https://registry.yarnpkg.com/@aws-sdk/node-http-handler/-/node-http-handler-3.374.0.tgz#8cd58b4d9814713e26034c12eabc119c113a5bc4" @@ -1142,32 +608,6 @@ "@smithy/util-middleware" "^3.0.9" tslib "^2.6.2" -"@aws-sdk/region-config-resolver@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.709.0.tgz#64547b333842e5804e1793e4d6d29578c0b34a68" - integrity sha512-/NoCAMEVKAg3kBKOrNtgOfL+ECt6nrl+L7q2SyYmrcY4tVCmwuECVqewQaHc03fTnJijfKLccw0Fj+6wOCnB6w== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/types" "^3.7.2" - "@smithy/util-config-provider" "^3.0.0" - "@smithy/util-middleware" "^3.0.11" - tslib "^2.6.2" - -"@aws-sdk/s3-request-presigner@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.709.0.tgz#d3c9d881158bdece69863be318d49e9d7d2c512f" - integrity sha512-WYmXU2ur/z6xBX9TcGwSWlSiS8rxrRl2f1HJXZzgSu9FWZ7fJssoQGvrk/w64wjNq1tEzKbd1iWXw9s9qexT3g== - dependencies: - "@aws-sdk/signature-v4-multi-region" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@aws-sdk/util-format-url" "3.709.0" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/protocol-http" "^4.1.8" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/signature-v4-multi-region@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.693.0.tgz#85bd90bb78be1a98d5a5ca41033cb0703146c2c4" @@ -1180,18 +620,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/signature-v4-multi-region@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.709.0.tgz#0c6f9d3e2978158163b63a4085356616237223c9" - integrity sha512-m0vhJEy6SLbjL11K9cHzX/ZhCIj//1GkTbYk2d4tTQFSuPyJEkjmoeHk9dYm2mJy0wH48j29OJadI1JUsR5bOw== - dependencies: - "@aws-sdk/middleware-sdk-s3" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/protocol-http" "^4.1.8" - "@smithy/signature-v4" "^4.2.4" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/token-providers@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.693.0.tgz#5ce7d6aa7a3437d4abdc0dca1be47f5158d15c85" @@ -1203,17 +631,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/token-providers@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.709.0.tgz#56305ab187660a711fd172c329dc953ca754fa80" - integrity sha512-q5Ar6k71nci43IbULFgC8a89d/3EHpmd7HvBzqVGRcHnoPwh8eZDBfbBXKH83NGwcS1qPSRYiDbVfeWPm4/1jA== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/property-provider" "^3.1.11" - "@smithy/shared-ini-file-loader" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/types@3.692.0", "@aws-sdk/types@^3.222.0": version "3.692.0" resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.692.0.tgz#c8f6c75b6ad659865b72759796d4d92c1b72069b" @@ -1222,14 +639,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/types@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.709.0.tgz#f8d7ab07e253d3ed0e3b360e09fc67c7430a73b9" - integrity sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/util-arn-parser@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.693.0.tgz#8dae27eb822ab4f88be28bb3c0fc11f1f13d3948" @@ -1237,13 +646,6 @@ dependencies: tslib "^2.6.2" -"@aws-sdk/util-dynamodb@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-dynamodb/-/util-dynamodb-3.709.0.tgz#12ced0849ff8f1ac8a1921f97fdb57813f22ec14" - integrity sha512-rGr9+Po6Ma2BHV2hIhfXdn8hWxLtmgFzFRqqtxOlRRIDN55wkb2AYXz/ydzf4kgb+PzT8sQxtn6hf7pDkl+yAg== - dependencies: - tslib "^2.6.2" - "@aws-sdk/util-endpoints@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.693.0.tgz#99f56f83fc25bdc3321f5871d6354abd56768891" @@ -1254,26 +656,6 @@ "@smithy/util-endpoints" "^2.1.5" tslib "^2.6.2" -"@aws-sdk/util-endpoints@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.709.0.tgz#32dfe339d78b699ada68392bbb3bec25441bae5c" - integrity sha512-Mbc7AtL5WGCTKC16IGeUTz+sjpC3ptBda2t0CcK0kMVw3THDdcSq6ZlNKO747cNqdbwUvW34oHteUiHv4/z88Q== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/types" "^3.7.2" - "@smithy/util-endpoints" "^2.1.7" - tslib "^2.6.2" - -"@aws-sdk/util-format-url@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-format-url/-/util-format-url-3.709.0.tgz#6ac420c297cae442f6d4065214eefc0d977e1a10" - integrity sha512-HGR11hx1KeFfoub/TACf+Yyal37lR85791Di2QPaElQThaqztLlppxale3EohKboOFf7Q/zvslJyM0fmgrlpQw== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/querystring-builder" "^3.0.11" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/util-locate-window@^3.0.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz#1160f6d055cf074ca198eb8ecf89b6311537ad6c" @@ -1291,16 +673,6 @@ bowser "^2.11.0" tslib "^2.6.2" -"@aws-sdk/util-user-agent-browser@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.709.0.tgz#ad6e867bdd348923ec10ddd6c37740ce0986cd8f" - integrity sha512-/rL2GasJzdTWUURCQKFldw2wqBtY4k4kCiA2tVZSKg3y4Ey7zO34SW8ebaeCE2/xoWOyLR2/etdKyphoo4Zrtg== - dependencies: - "@aws-sdk/types" "3.709.0" - "@smithy/types" "^3.7.2" - bowser "^2.11.0" - tslib "^2.6.2" - "@aws-sdk/util-user-agent-node@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.693.0.tgz#b26c806faa2001d4fa1d515b146eeff411513dd9" @@ -1312,17 +684,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/util-user-agent-node@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.709.0.tgz#7ff5a508bcad49963a550acadcced43d7af9960d" - integrity sha512-trBfzSCVWy7ILgqhEXgiuM7hfRCw4F4a8IK90tjk9YL0jgoJ6eJuOp7+DfCtHJaygoBxD3cdMFkOu+lluFmGBA== - dependencies: - "@aws-sdk/middleware-user-agent" "3.709.0" - "@aws-sdk/types" "3.709.0" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@aws-sdk/xml-builder@3.693.0": version "3.693.0" resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.693.0.tgz#709a46a3335b71144d9f7917a7cb3033b5a04e82" @@ -1331,14 +692,6 @@ "@smithy/types" "^3.7.0" tslib "^2.6.2" -"@aws-sdk/xml-builder@3.709.0": - version "3.709.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.709.0.tgz#5841faa1e78afcea064557a1a56709978b325758" - integrity sha512-2GPCwlNxeHspoK/Mc8nbk9cBOkSpp3j2SJUQmFnyQK6V/pR6II2oPRyZkMomug1Rc10hqlBHByMecq4zhV2uUw== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@azure/abort-controller@^1.0.0", "@azure/abort-controller@^1.0.4": version "1.1.0" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249" @@ -4871,14 +4224,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/abort-controller@^3.1.9": - version "3.1.9" - resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-3.1.9.tgz#47d323f754136a489e972d7fd465d534d72fcbff" - integrity sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/chunked-blob-reader-native@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-3.0.1.tgz#39045ed278ee1b6f4c12715c7565678557274c29" @@ -4905,17 +4250,6 @@ "@smithy/util-middleware" "^3.0.10" tslib "^2.6.2" -"@smithy/config-resolver@^3.0.13": - version "3.0.13" - resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-3.0.13.tgz#653643a77a33d0f5907a5e7582353886b07ba752" - integrity sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg== - dependencies: - "@smithy/node-config-provider" "^3.1.12" - "@smithy/types" "^3.7.2" - "@smithy/util-config-provider" "^3.0.0" - "@smithy/util-middleware" "^3.0.11" - tslib "^2.6.2" - "@smithy/core@^2.5.2", "@smithy/core@^2.5.3": version "2.5.3" resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.5.3.tgz#1d5723f676b0d6ec08c515272f0ac03aa59fac72" @@ -4930,20 +4264,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@smithy/core@^2.5.5": - version "2.5.5" - resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.5.5.tgz#c75b15caee9e58c800db3e6b99e9e373532d394a" - integrity sha512-G8G/sDDhXA7o0bOvkc7bgai6POuSld/+XhNnWAbpQTpLv2OZPvyqQ58tLPPlz0bSNsXktldDDREIv1LczFeNEw== - dependencies: - "@smithy/middleware-serde" "^3.0.11" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - "@smithy/util-body-length-browser" "^3.0.0" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-stream" "^3.3.2" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@smithy/credential-provider-imds@^3.2.6", "@smithy/credential-provider-imds@^3.2.7": version "3.2.7" resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.7.tgz#6eedf87ba0238723ec46d8ce0f18e276685a702d" @@ -4955,27 +4275,6 @@ "@smithy/url-parser" "^3.0.10" tslib "^2.6.2" -"@smithy/credential-provider-imds@^3.2.8": - version "3.2.8" - resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz#27ed2747074c86a7d627a98e56f324a65cba88de" - integrity sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw== - dependencies: - "@smithy/node-config-provider" "^3.1.12" - "@smithy/property-provider" "^3.1.11" - "@smithy/types" "^3.7.2" - "@smithy/url-parser" "^3.0.11" - tslib "^2.6.2" - -"@smithy/eventstream-codec@^3.1.10": - version "3.1.10" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-3.1.10.tgz#0c1a3457e7a23b71cd71525ceb668f8569a84dad" - integrity sha512-323B8YckSbUH0nMIpXn7HZsAVKHYHFUODa8gG9cHo0ySvA1fr5iWaNT+iIL0UCqUzG6QPHA3BSsBtRQou4mMqQ== - dependencies: - "@aws-crypto/crc32" "5.2.0" - "@smithy/types" "^3.7.2" - "@smithy/util-hex-encoding" "^3.0.0" - tslib "^2.6.2" - "@smithy/eventstream-codec@^3.1.9": version "3.1.9" resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-3.1.9.tgz#4271354e75e57d30771fca307da403896c657430" @@ -4995,23 +4294,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/eventstream-serde-browser@^3.0.14": - version "3.0.14" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.14.tgz#0c3584c7cde2e210aacdfbbd2b57c1d7e2ca3b95" - integrity sha512-kbrt0vjOIihW3V7Cqj1SXQvAI5BR8SnyQYsandva0AOR307cXAc+IhPngxIPslxTLfxwDpNu0HzCAq6g42kCPg== - dependencies: - "@smithy/eventstream-serde-universal" "^3.0.13" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - -"@smithy/eventstream-serde-config-resolver@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.11.tgz#5edceba836debea165ea93145231036f6286d67c" - integrity sha512-P2pnEp4n75O+QHjyO7cbw/vsw5l93K/8EWyjNCAAybYwUmj3M+hjSQZ9P5TVdUgEG08ueMAP5R4FkuSkElZ5tQ== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/eventstream-serde-config-resolver@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.10.tgz#5c0b2ae0bb8e11cfa77851098e46f7350047ec8d" @@ -5029,15 +4311,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/eventstream-serde-node@^3.0.13": - version "3.0.13" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.13.tgz#5aebd7b553becee277e411a2b69f6af8c9d7b3a6" - integrity sha512-zqy/9iwbj8Wysmvi7Lq7XFLeDgjRpTbCfwBhJa8WbrylTAHiAu6oQTwdY7iu2lxigbc9YYr9vPv5SzYny5tCXQ== - dependencies: - "@smithy/eventstream-serde-universal" "^3.0.13" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/eventstream-serde-universal@^3.0.12": version "3.0.12" resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.12.tgz#803d7beb29a3de4a64e91af97331a4654741c35f" @@ -5047,15 +4320,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/eventstream-serde-universal@^3.0.13": - version "3.0.13" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.13.tgz#609c922ea14a0a3eed23a28ac110344c935704eb" - integrity sha512-L1Ib66+gg9uTnqp/18Gz4MDpJPKRE44geOjOQ2SVc0eiaO5l255ADziATZgjQjqumC7yPtp1XnjHlF1srcwjKw== - dependencies: - "@smithy/eventstream-codec" "^3.1.10" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/fetch-http-handler@^4.1.0", "@smithy/fetch-http-handler@^4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.1.tgz#cead80762af4cdea11e7eeb627ea1c4835265dfa" @@ -5067,27 +4331,6 @@ "@smithy/util-base64" "^3.0.0" tslib "^2.6.2" -"@smithy/fetch-http-handler@^4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.2.tgz#f034ff16416b37d92908a1381ef5fddbf4ef1879" - integrity sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA== - dependencies: - "@smithy/protocol-http" "^4.1.8" - "@smithy/querystring-builder" "^3.0.11" - "@smithy/types" "^3.7.2" - "@smithy/util-base64" "^3.0.0" - tslib "^2.6.2" - -"@smithy/hash-blob-browser@^3.1.10": - version "3.1.10" - resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.10.tgz#985e308189c2687a15004152b97506882ffb2b13" - integrity sha512-elwslXOoNunmfS0fh55jHggyhccobFkexLYC1ZeZ1xP2BTSrcIBaHV2b4xUQOdctrSNOpMqOZH1r2XzWTEhyfA== - dependencies: - "@smithy/chunked-blob-reader" "^4.0.0" - "@smithy/chunked-blob-reader-native" "^3.0.1" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/hash-blob-browser@^3.1.8": version "3.1.9" resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.9.tgz#1f2c3ef6afbb0ce3e58a0129753850bb9267aae8" @@ -5098,16 +4341,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/hash-node@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-3.0.11.tgz#99e09ead3fc99c8cd7ca0f254ea0e35714f2a0d3" - integrity sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA== - dependencies: - "@smithy/types" "^3.7.2" - "@smithy/util-buffer-from" "^3.0.0" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@smithy/hash-node@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-3.0.10.tgz#93c857b4bff3a48884886440fd9772924887e592" @@ -5118,15 +4351,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@smithy/hash-stream-node@^3.1.10": - version "3.1.10" - resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-3.1.10.tgz#94716b4556f4ccf2807e605f47bb5b018ed7dfb0" - integrity sha512-olomK/jZQ93OMayW1zfTHwcbwBdhcZOHsyWyiZ9h9IXvc1mCD/VuvzbLb3Gy/qNJwI4MANPLctTp2BucV2oU/Q== - dependencies: - "@smithy/types" "^3.7.2" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@smithy/hash-stream-node@^3.1.8": version "3.1.9" resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-3.1.9.tgz#97eb416811b7e7b9d036f0271588151b619759e9" @@ -5136,14 +4360,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@smithy/invalid-dependency@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz#8144d7b0af9d34ab5f672e1f674f97f8740bb9ae" - integrity sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/invalid-dependency@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-3.0.10.tgz#8616dee555916c24dec3e33b1e046c525efbfee3" @@ -5166,15 +4382,6 @@ dependencies: tslib "^2.6.2" -"@smithy/md5-js@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-3.0.11.tgz#27e4dab616348ff94aed24dc75e4017c582df40f" - integrity sha512-3NM0L3i2Zm4bbgG6Ymi9NBcxXhryi3uE8fIfHJZIOfZVxOkGdjdgjR9A06SFIZCfnEIWKXZdm6Yq5/aPXFFhsQ== - dependencies: - "@smithy/types" "^3.7.2" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@smithy/md5-js@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-3.0.10.tgz#52ab927cf03cd1d24fed82d8ba936faf5632436e" @@ -5193,15 +4400,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/middleware-content-length@^3.0.13": - version "3.0.13" - resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz#6e08fe52739ac8fb3996088e0f8837e4b2ea187f" - integrity sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw== - dependencies: - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/middleware-endpoint@^3.2.2", "@smithy/middleware-endpoint@^3.2.3": version "3.2.3" resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.3.tgz#7dd3df0052fc55891522631a7751e613b6efd68a" @@ -5216,20 +4414,6 @@ "@smithy/util-middleware" "^3.0.10" tslib "^2.6.2" -"@smithy/middleware-endpoint@^3.2.5": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.5.tgz#bdcfdf1f342cf933b0b8a709996f9a8fbb8148f4" - integrity sha512-VhJNs/s/lyx4weiZdXSloBgoLoS8osV0dKIain8nGmx7of3QFKu5BSdEuk1z/U8x9iwes1i+XCiNusEvuK1ijg== - dependencies: - "@smithy/core" "^2.5.5" - "@smithy/middleware-serde" "^3.0.11" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/shared-ini-file-loader" "^3.1.12" - "@smithy/types" "^3.7.2" - "@smithy/url-parser" "^3.0.11" - "@smithy/util-middleware" "^3.0.11" - tslib "^2.6.2" - "@smithy/middleware-retry@^3.0.26": version "3.0.27" resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.27.tgz#2e4dda420178835cd2d416479505d313b601ba21" @@ -5245,21 +4429,6 @@ tslib "^2.6.2" uuid "^9.0.1" -"@smithy/middleware-retry@^3.0.30": - version "3.0.30" - resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.30.tgz#2580322d0d28ad782b5b8c07c150b14efdc3b2f9" - integrity sha512-6323RL2BvAR3VQpTjHpa52kH/iSHyxd/G9ohb2MkBk2Ucu+oMtRXT8yi7KTSIS9nb58aupG6nO0OlXnQOAcvmQ== - dependencies: - "@smithy/node-config-provider" "^3.1.12" - "@smithy/protocol-http" "^4.1.8" - "@smithy/service-error-classification" "^3.0.11" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-retry" "^3.0.11" - tslib "^2.6.2" - uuid "^9.0.1" - "@smithy/middleware-serde@^3.0.10", "@smithy/middleware-serde@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-3.0.10.tgz#5f6c0b57b10089a21d355bd95e9b7d40378454d7" @@ -5268,14 +4437,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/middleware-serde@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz#c7d54e0add4f83e05c6878a011fc664e21022f12" - integrity sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/middleware-stack@^3.0.10", "@smithy/middleware-stack@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-3.0.10.tgz#73e2fde5d151440844161773a17ee13375502baf" @@ -5284,14 +4445,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/middleware-stack@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz#453af2096924e4064d9da4e053cfdf65d9a36acc" - integrity sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/node-config-provider@^3.1.10", "@smithy/node-config-provider@^3.1.11": version "3.1.11" resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-3.1.11.tgz#95feba85a5cb3de3fe9adfff1060b35fd556d023" @@ -5302,16 +4455,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/node-config-provider@^3.1.12": - version "3.1.12" - resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz#1b1d674fc83f943dc7b3017e37f16f374e878a6c" - integrity sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ== - dependencies: - "@smithy/property-provider" "^3.1.11" - "@smithy/shared-ini-file-loader" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/node-http-handler@^1.0.2": version "1.1.0" resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-1.1.0.tgz#887cee930b520e08043c9f41e463f8d8f5dae127" @@ -5334,17 +4477,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/node-http-handler@^3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-3.3.2.tgz#b34685863b74dabdaf7860aa81b42d0d5437c7e0" - integrity sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA== - dependencies: - "@smithy/abort-controller" "^3.1.9" - "@smithy/protocol-http" "^4.1.8" - "@smithy/querystring-builder" "^3.0.11" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/property-provider@^3.1.10", "@smithy/property-provider@^3.1.9": version "3.1.10" resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-3.1.10.tgz#ae00447c1060c194c3e1b9475f7c8548a70f8486" @@ -5353,14 +4485,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/property-provider@^3.1.11": - version "3.1.11" - resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-3.1.11.tgz#161cf1c2a2ada361e417382c57f5ba6fbca8acad" - integrity sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/protocol-http@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-1.2.0.tgz#a554e4dabb14508f0bc2cdef9c3710e2b294be04" @@ -5377,14 +4501,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/protocol-http@^4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-4.1.8.tgz#0461758671335f65e8ff3fc0885ab7ed253819c9" - integrity sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/querystring-builder@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-1.1.0.tgz#de6306104640ade34e59be33949db6cc64aa9d7f" @@ -5403,15 +4519,6 @@ "@smithy/util-uri-escape" "^3.0.0" tslib "^2.6.2" -"@smithy/querystring-builder@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz#2ed04adbe725671824c5613d0d6f9376d791a909" - integrity sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg== - dependencies: - "@smithy/types" "^3.7.2" - "@smithy/util-uri-escape" "^3.0.0" - tslib "^2.6.2" - "@smithy/querystring-parser@^3.0.10": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-3.0.10.tgz#62db744a1ed2cf90f4c08d2c73d365e033b4a11c" @@ -5420,14 +4527,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/querystring-parser@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz#9d3177ea19ce8462f18d9712b395239e1ca1f969" - integrity sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/service-error-classification@^3.0.10": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-3.0.10.tgz#941c549daf0e9abb84d3def1d9e1e3f0f74f5ba6" @@ -5435,13 +4534,6 @@ dependencies: "@smithy/types" "^3.7.1" -"@smithy/service-error-classification@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz#d3d7fc0aacd2e60d022507367e55c7939e5bcb8a" - integrity sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog== - dependencies: - "@smithy/types" "^3.7.2" - "@smithy/shared-ini-file-loader@^3.1.10", "@smithy/shared-ini-file-loader@^3.1.11": version "3.1.11" resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.11.tgz#0b4f98c4a66480956fbbefc4627c5dc09d891aea" @@ -5450,14 +4542,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/shared-ini-file-loader@^3.1.12": - version "3.1.12" - resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz#d98b1b663eb18935ce2cbc79024631d34f54042a" - integrity sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/signature-v4@^4.2.2": version "4.2.3" resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-4.2.3.tgz#abbca5e5fe9158422b3125b2956791a325a27f22" @@ -5472,20 +4556,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@smithy/signature-v4@^4.2.4": - version "4.2.4" - resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-4.2.4.tgz#3501d3d09fd82768867bfc00a7be4bad62f62f4d" - integrity sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA== - dependencies: - "@smithy/is-array-buffer" "^3.0.0" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - "@smithy/util-hex-encoding" "^3.0.0" - "@smithy/util-middleware" "^3.0.11" - "@smithy/util-uri-escape" "^3.0.0" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@smithy/smithy-client@^3.4.3", "@smithy/smithy-client@^3.4.4": version "3.4.4" resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.4.4.tgz#460870dc97d945fa2f390890359cf09d01131e0f" @@ -5499,26 +4569,6 @@ "@smithy/util-stream" "^3.3.1" tslib "^2.6.2" -"@smithy/smithy-client@^3.5.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.5.0.tgz#65cff262801b009998c1196764ee69929ee06f8a" - integrity sha512-Y8FeOa7gbDfCWf7njrkoRATPa5eNLUEjlJS5z5rXatYuGkCb80LbHcu8AQR8qgAZZaNHCLyo2N+pxPsV7l+ivg== - dependencies: - "@smithy/core" "^2.5.5" - "@smithy/middleware-endpoint" "^3.2.5" - "@smithy/middleware-stack" "^3.0.11" - "@smithy/protocol-http" "^4.1.8" - "@smithy/types" "^3.7.2" - "@smithy/util-stream" "^3.3.2" - tslib "^2.6.2" - -"@smithy/types@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@smithy/types/-/types-4.0.0.tgz#7458c1c4dde3c6cf23221370acf5acd03215de6e" - integrity sha512-aNwIGSOgDOhtTRY/rrn2aeuQeKw/IFrQ998yK5l6Ah853WeWIEmFPs/EO4OpfADEdcK+igWnZytm/oUgkLgUYg== - dependencies: - tslib "^2.6.2" - "@smithy/types@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@smithy/types/-/types-1.2.0.tgz#9dc65767b0ee3d6681704fcc67665d6fc9b6a34e" @@ -5533,13 +4583,6 @@ dependencies: tslib "^2.6.2" -"@smithy/types@^3.7.2": - version "3.7.2" - resolved "https://registry.yarnpkg.com/@smithy/types/-/types-3.7.2.tgz#05cb14840ada6f966de1bf9a9c7dd86027343e10" - integrity sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg== - dependencies: - tslib "^2.6.2" - "@smithy/url-parser@^3.0.10", "@smithy/url-parser@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-3.0.10.tgz#f389985a79766cff4a99af14979f01a17ce318da" @@ -5549,15 +4592,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/url-parser@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-3.0.11.tgz#e5f5ffabfb6230159167cf4cc970705fca6b8b2d" - integrity sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw== - dependencies: - "@smithy/querystring-parser" "^3.0.11" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/util-base64@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-3.0.0.tgz#f7a9a82adf34e27a72d0719395713edf0e493017" @@ -5615,17 +4649,6 @@ bowser "^2.11.0" tslib "^2.6.2" -"@smithy/util-defaults-mode-browser@^3.0.30": - version "3.0.30" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.30.tgz#6c0d95af3f15bef8f1fe3f6217cc4f5ba8df5554" - integrity sha512-nLuGmgfcr0gzm64pqF2UT4SGWVG8UGviAdayDlVzJPNa6Z4lqvpDzdRXmLxtOdEjVlTOEdpZ9dd3ZMMu488mzg== - dependencies: - "@smithy/property-provider" "^3.1.11" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - bowser "^2.11.0" - tslib "^2.6.2" - "@smithy/util-defaults-mode-node@^3.0.26": version "3.0.27" resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.27.tgz#a7248c9d9cb620827ab57ef9d1867bfe8aef42d0" @@ -5639,19 +4662,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/util-defaults-mode-node@^3.0.30": - version "3.0.30" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.30.tgz#33cdb02f90944b9ff221e2f8e0904a63ac1e335f" - integrity sha512-OD63eWoH68vp75mYcfYyuVH+p7Li/mY4sYOROnauDrtObo1cS4uWfsy/zhOTW8F8ZPxQC1ZXZKVxoxvMGUv2Ow== - dependencies: - "@smithy/config-resolver" "^3.0.13" - "@smithy/credential-provider-imds" "^3.2.8" - "@smithy/node-config-provider" "^3.1.12" - "@smithy/property-provider" "^3.1.11" - "@smithy/smithy-client" "^3.5.0" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/util-endpoints@^2.1.5": version "2.1.6" resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-2.1.6.tgz#720cbd1a616ad7c099b77780f0cb0f1f9fc5d2df" @@ -5661,15 +4671,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/util-endpoints@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz#a088ebfab946a7219dd4763bfced82709894b82d" - integrity sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw== - dependencies: - "@smithy/node-config-provider" "^3.1.12" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/util-hex-encoding@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz#32938b33d5bf2a15796cd3f178a55b4155c535e6" @@ -5685,14 +4686,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/util-middleware@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-3.0.11.tgz#2ab5c17266b42c225e62befcffb048afa682b5bf" - integrity sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow== - dependencies: - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/util-retry@^3.0.10", "@smithy/util-retry@^3.0.9": version "3.0.10" resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-3.0.10.tgz#fc13e1b30e87af0cbecadf29ca83b171e2040440" @@ -5702,15 +4695,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/util-retry@^3.0.11": - version "3.0.11" - resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-3.0.11.tgz#d267e5ccb290165cee69732547fea17b695a7425" - integrity sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ== - dependencies: - "@smithy/service-error-classification" "^3.0.11" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@smithy/util-stream@^3.3.0", "@smithy/util-stream@^3.3.1": version "3.3.1" resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-3.3.1.tgz#a2636f435637ef90d64df2bb8e71cd63236be112" @@ -5725,20 +4709,6 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@smithy/util-stream@^3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-3.3.2.tgz#daeea26397e8541cf2499ce65bf0b8d528cba421" - integrity sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg== - dependencies: - "@smithy/fetch-http-handler" "^4.1.2" - "@smithy/node-http-handler" "^3.3.2" - "@smithy/types" "^3.7.2" - "@smithy/util-base64" "^3.0.0" - "@smithy/util-buffer-from" "^3.0.0" - "@smithy/util-hex-encoding" "^3.0.0" - "@smithy/util-utf8" "^3.0.0" - tslib "^2.6.2" - "@smithy/util-uri-escape@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-1.1.0.tgz#a8c5edaf19c0efdb9b51661e840549cf600a1808" @@ -5778,15 +4748,6 @@ "@smithy/types" "^3.7.1" tslib "^2.6.2" -"@smithy/util-waiter@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-3.2.0.tgz#1e52f870e77d2e5572025f7606053e6ff00df93d" - integrity sha512-PpjSboaDUE6yl+1qlg3Si57++e84oXdWGbuFUSAciXsVfEZJJJupR2Nb0QuXHiunt2vGR+1PTizOMvnUPaG2Qg== - dependencies: - "@smithy/abort-controller" "^3.1.9" - "@smithy/types" "^3.7.2" - tslib "^2.6.2" - "@socket.io/component-emitter@~3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" @@ -7096,11 +6057,6 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== -"@types/uuid@^9.0.1": - version "9.0.8" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" - integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== - "@types/webidl-conversions@*": version "7.0.0" resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7" @@ -8509,14 +7465,6 @@ buffer@4.9.2: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@5.6.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" - integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - buffer@6.0.3, buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -11232,7 +10180,7 @@ events@1.1.1: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== -events@3.3.0, events@^3.0.0, events@^3.3.0: +events@^3.0.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -12988,7 +11936,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -15812,13 +14760,6 @@ mlly@^1.1.0, mlly@^1.7.1: pkg-types "^1.1.1" ufo "^1.5.3" -mnemonist@0.38.3: - version "0.38.3" - resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.3.tgz#35ec79c1c1f4357cfda2fe264659c2775ccd7d9d" - integrity sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw== - dependencies: - obliterator "^1.6.1" - modify-values@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -16611,11 +15552,6 @@ object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" -obliterator@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-1.6.1.tgz#dea03e8ab821f6c4d96a299e17aef6a3af994ef3" - integrity sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig== - omggif@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" @@ -19661,14 +18597,6 @@ stoppable@^1.1.0: resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" integrity sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw== -stream-browserify@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" - integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== - dependencies: - inherits "~2.0.4" - readable-stream "^3.5.0" - stream-events@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" @@ -19716,16 +18644,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -19817,7 +18736,7 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -19831,13 +18750,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" @@ -21585,7 +20497,7 @@ worker-farm@1.7.0: dependencies: errno "~0.1.7" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -21603,15 +20515,6 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 16ec75b272124b7516bd5a50d496099701194333 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 8 Jan 2025 10:28:54 +0000 Subject: [PATCH 058/173] Bump version to 3.2.37 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 9b2cacda12..647c9f202d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.36", + "version": "3.2.37", "npmClient": "yarn", "concurrency": 20, "command": { From 913cefaf175d0c112c4132c973ce726b7b165648 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 31 Dec 2024 13:24:26 +0100 Subject: [PATCH 059/173] Type index --- .../src/fetch/{index.js => index.ts} | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) rename packages/frontend-core/src/fetch/{index.js => index.ts} (67%) diff --git a/packages/frontend-core/src/fetch/index.js b/packages/frontend-core/src/fetch/index.ts similarity index 67% rename from packages/frontend-core/src/fetch/index.js rename to packages/frontend-core/src/fetch/index.ts index 903810ac25..d9eac9482e 100644 --- a/packages/frontend-core/src/fetch/index.js +++ b/packages/frontend-core/src/fetch/index.ts @@ -10,6 +10,7 @@ import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch.js" import CustomFetch from "./CustomFetch.js" import QueryArrayFetch from "./QueryArrayFetch.js" +import { UIDatasource, UIFetchAPI } from "@budibase/types" const DataFetchMap = { table: TableFetch, @@ -29,15 +30,30 @@ const DataFetchMap = { } // Constructs a new fetch model for a certain datasource -export const fetchData = ({ API, datasource, options }) => { - const Fetch = DataFetchMap[datasource?.type] || TableFetch +export const fetchData = ({ + API, + datasource, + options, +}: { + API: UIFetchAPI + datasource: UIDatasource + options: {} +}) => { + const Fetch = + DataFetchMap[datasource?.type as keyof typeof DataFetchMap] || TableFetch return new Fetch({ API, datasource, ...options }) } // Creates an empty fetch instance with no datasource configured, so no data // will initially be loaded -const createEmptyFetchInstance = ({ API, datasource }) => { - const handler = DataFetchMap[datasource?.type] +const createEmptyFetchInstance = ({ + API, + datasource, +}: { + API: UIFetchAPI + datasource: UIDatasource +}) => { + const handler = DataFetchMap[datasource?.type as keyof typeof DataFetchMap] if (!handler) { return null } @@ -45,13 +61,27 @@ const createEmptyFetchInstance = ({ API, datasource }) => { } // Fetches the definition of any type of datasource -export const getDatasourceDefinition = async ({ API, datasource }) => { +export const getDatasourceDefinition = async ({ + API, + datasource, +}: { + API: UIFetchAPI + datasource: UIDatasource +}) => { const instance = createEmptyFetchInstance({ API, datasource }) return await instance?.getDefinition(datasource) } // Fetches the schema of any type of datasource -export const getDatasourceSchema = ({ API, datasource, definition }) => { +export const getDatasourceSchema = ({ + API, + datasource, + definition, +}: { + API: UIFetchAPI + datasource: UIDatasource + definition: {} +}) => { const instance = createEmptyFetchInstance({ API, datasource }) return instance?.getSchema(datasource, definition) } From ecfc248e606f85ddd3a60e462e07427003216855 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 31 Dec 2024 15:43:08 +0100 Subject: [PATCH 060/173] Type datafetch --- .../src/fetch/{DataFetch.js => DataFetch.ts} | 178 ++++++++++++------ packages/frontend-core/src/fetch/index.ts | 4 +- packages/shared-core/src/filters.ts | 8 +- packages/types/src/ui/stores/grid/fetch.ts | 2 + 4 files changed, 128 insertions(+), 64 deletions(-) rename packages/frontend-core/src/fetch/{DataFetch.js => DataFetch.ts} (76%) diff --git a/packages/frontend-core/src/fetch/DataFetch.js b/packages/frontend-core/src/fetch/DataFetch.ts similarity index 76% rename from packages/frontend-core/src/fetch/DataFetch.js rename to packages/frontend-core/src/fetch/DataFetch.ts index 175365a442..d8a8e15245 100644 --- a/packages/frontend-core/src/fetch/DataFetch.js +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -1,25 +1,86 @@ -import { writable, derived, get } from "svelte/store" +import { writable, derived, get, Writable, Readable } from "svelte/store" import { cloneDeep } from "lodash/fp" import { QueryUtils } from "../utils" import { convertJSONSchemaToTableSchema } from "../utils/json" -import { FieldType, SortOrder, SortType } from "@budibase/types" +import { + FieldType, + LegacyFilter, + SearchFilters, + SortOrder, + SortType, + Table, + TableSchema, + UIDatasource, + UIFetchAPI, + UIRow, + UISearchFilter, +} from "@budibase/types" const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils +interface DataFetchStore { + rows: UIRow[] + info: null + schema: TableSchema | null + loading: boolean + loaded: boolean + query: SearchFilters | null + pageNumber: number + cursor: null + cursors: any[] + resetKey: number + error: null +} + +interface DataFetchDerivedStore extends DataFetchStore { + hasNextPage: boolean + hasPrevPage: boolean + supportsSearch: boolean + supportsSort: boolean + supportsPagination: boolean +} + /** * Parent class which handles the implementation of fetching data from an * internal table or datasource plus. * For other types of datasource, this class is overridden and extended. */ -export default class DataFetch { +export default abstract class DataFetch { + API: UIFetchAPI + features: { + supportsSearch: boolean + supportsSort: boolean + supportsPagination: boolean + } + options: { + datasource: UIDatasource | null + limit: number + // Search config + filter: UISearchFilter | LegacyFilter[] | null + query: SearchFilters | null + // Sorting config + sortColumn: string | null + sortOrder: SortOrder + sortType: SortType | null + // Pagination config + paginate: boolean + // Client side feature customisation + clientSideSearching: boolean + clientSideSorting: boolean + clientSideLimiting: boolean + } + store: Writable + derivedStore: Readable + /** * Constructs a new DataFetch instance. * @param opts the fetch options */ - constructor(opts) { - // API client - this.API = null - + constructor(opts: { + API: UIFetchAPI + datasource?: UIDatasource + options?: {} + }) { // Feature flags this.features = { supportsSearch: false, @@ -118,7 +179,10 @@ export default class DataFetch { /** * Gets the default sort column for this datasource */ - getDefaultSortColumn(definition, schema) { + getDefaultSortColumn( + definition: { primaryDisplay?: string } | null, + schema: Record + ) { if (definition?.primaryDisplay && schema[definition.primaryDisplay]) { return definition.primaryDisplay } else { @@ -144,7 +208,7 @@ export default class DataFetch { } // Fetch and enrich schema - let schema = this.getSchema(datasource, definition) + let schema = this.getSchema(datasource, definition) ?? null schema = this.enrichSchema(schema) if (!schema) { return @@ -172,7 +236,7 @@ export default class DataFetch { if ( fieldSchema?.type === FieldType.NUMBER || fieldSchema?.type === FieldType.BIGINT || - fieldSchema?.calculationType + ("calculationType" in fieldSchema && fieldSchema?.calculationType) ) { this.options.sortType = SortType.NUMBER } @@ -185,7 +249,7 @@ export default class DataFetch { // Build the query let query = this.options.query if (!query) { - query = buildQuery(filter) + query = buildQuery(filter ?? undefined) } // Update store @@ -239,7 +303,7 @@ export default class DataFetch { // If we don't support sorting, do a client-side sort if (!this.features.supportsSort && clientSideSorting) { - rows = sort(rows, sortColumn, sortOrder, sortType) + rows = sort(rows, sortColumn as any, sortOrder, sortType) } // If we don't support pagination, do a client-side limit @@ -256,18 +320,13 @@ export default class DataFetch { } } - /** - * Fetches a single page of data from the remote resource. - * Must be overridden by a datasource specific child class. - */ - async getData() { - return { - rows: [], - info: null, - hasNextPage: false, - cursor: null, - } - } + abstract getData(): Promise<{ + rows: UIRow[] + info: any + hasNextPage: boolean + cursor: any + error: any + }> /** * Gets the definition for this datasource. @@ -275,13 +334,13 @@ export default class DataFetch { * @param datasource * @return {object} the definition */ - async getDefinition(datasource) { + async getDefinition(datasource: UIDatasource | null) { if (!datasource?.tableId) { return null } try { return await this.API.fetchTableDefinition(datasource.tableId) - } catch (error) { + } catch (error: any) { this.store.update(state => ({ ...state, error, @@ -293,11 +352,11 @@ export default class DataFetch { /** * Gets the schema definition for a datasource. * Defaults to getting the "schema" property of the definition. - * @param datasource the datasource + * @param _datasource the datasource * @param definition the datasource definition * @return {object} the schema */ - getSchema(datasource, definition) { + getSchema(_datasource: UIDatasource | null, definition: Table | null) { return definition?.schema } @@ -307,44 +366,48 @@ export default class DataFetch { * @param schema the datasource schema * @return {object} the enriched datasource schema */ - enrichSchema(schema) { + enrichSchema(schema: TableSchema | null): TableSchema | null { if (schema == null) { return null } // Check for any JSON fields so we can add any top level properties - let jsonAdditions = {} - Object.keys(schema).forEach(fieldKey => { + let jsonAdditions: Record = {} + for (const fieldKey of Object.keys(schema)) { const fieldSchema = schema[fieldKey] if (fieldSchema?.type === FieldType.JSON) { const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, { squashObjects: true, - }) - Object.keys(jsonSchema).forEach(jsonKey => { - jsonAdditions[`${fieldKey}.${jsonKey}`] = { - type: jsonSchema[jsonKey].type, - nestedJSON: true, + }) as Record | null // TODO: remove when convertJSONSchemaToTableSchema is typed + if (jsonSchema) { + for (const jsonKey of Object.keys(jsonSchema)) { + jsonAdditions[`${fieldKey}.${jsonKey}`] = { + type: jsonSchema[jsonKey].type, + nestedJSON: true, + } } - }) + } } - }) - schema = { ...schema, ...jsonAdditions } + } // Ensure schema is in the correct structure - let enrichedSchema = {} - Object.entries(schema).forEach(([fieldName, fieldSchema]) => { - if (typeof fieldSchema === "string") { - enrichedSchema[fieldName] = { - type: fieldSchema, - name: fieldName, - } - } else { - enrichedSchema[fieldName] = { - ...fieldSchema, - name: fieldName, + let enrichedSchema: TableSchema = {} + Object.entries({ ...schema, ...jsonAdditions }).forEach( + ([fieldName, fieldSchema]) => { + if (typeof fieldSchema === "string") { + enrichedSchema[fieldName] = { + type: fieldSchema, + name: fieldName, + } + } else { + enrichedSchema[fieldName] = { + ...fieldSchema, + type: fieldSchema.type as any, // TODO: check type union definition conflicts + name: fieldName, + } } } - }) + ) return enrichedSchema } @@ -353,7 +416,7 @@ export default class DataFetch { * Determine the feature flag for this datasource definition * @param definition */ - determineFeatureFlags(_definition) { + determineFeatureFlags(_definition: Table | null) { return { supportsSearch: false, supportsSort: false, @@ -365,12 +428,11 @@ export default class DataFetch { * Resets the data set and updates options * @param newOptions any new options */ - async update(newOptions) { + async update(newOptions: any) { // Check if any settings have actually changed let refresh = false - const entries = Object.entries(newOptions || {}) - for (let [key, value] of entries) { - const oldVal = this.options[key] == null ? null : this.options[key] + for (const [key, value] of Object.entries(newOptions || {})) { + const oldVal = this.options[key as keyof typeof this.options] ?? null const newVal = value == null ? null : value if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) { refresh = true @@ -437,7 +499,7 @@ export default class DataFetch { * @param state the current store state * @return {boolean} whether there is a next page of data or not */ - hasNextPage(state) { + hasNextPage(state: DataFetchStore): boolean { return state.cursors[state.pageNumber + 1] != null } @@ -447,7 +509,7 @@ export default class DataFetch { * @param state the current store state * @return {boolean} whether there is a previous page of data or not */ - hasPrevPage(state) { + hasPrevPage(state: { pageNumber: number }): boolean { return state.pageNumber > 0 } diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index d9eac9482e..a08748a77e 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -10,7 +10,7 @@ import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch.js" import CustomFetch from "./CustomFetch.js" import QueryArrayFetch from "./QueryArrayFetch.js" -import { UIDatasource, UIFetchAPI } from "@budibase/types" +import { Table, UIDatasource, UIFetchAPI } from "@budibase/types" const DataFetchMap = { table: TableFetch, @@ -80,7 +80,7 @@ export const getDatasourceSchema = ({ }: { API: UIFetchAPI datasource: UIDatasource - definition: {} + definition: Table }) => { const instance = createEmptyFetchInstance({ API, datasource }) return instance?.getSchema(datasource, definition) diff --git a/packages/shared-core/src/filters.ts b/packages/shared-core/src/filters.ts index a023015b7e..a1e8534a95 100644 --- a/packages/shared-core/src/filters.ts +++ b/packages/shared-core/src/filters.ts @@ -552,7 +552,7 @@ export function search>( */ export function runQuery>( docs: T[], - query: SearchFilters + query: SearchFilters | null ): T[] { if (!docs || !Array.isArray(docs)) { return [] @@ -876,7 +876,7 @@ export function sort>( docs: T[], sort: keyof T, sortOrder: SortOrder, - sortType = SortType.STRING + sortType: SortType | null = SortType.STRING ): T[] { if (!sort || !sortOrder || !sortType) { return docs @@ -911,8 +911,8 @@ export function sort>( * @param docs the data * @param limit the number of docs to limit to */ -export function limit(docs: T[], limit: string): T[] { - const numLimit = parseFloat(limit) +export function limit(docs: T[], limit: string | number): T[] { + const numLimit = typeof limit === "number" ? limit : parseFloat(limit) if (isNaN(numLimit)) { return docs } diff --git a/packages/types/src/ui/stores/grid/fetch.ts b/packages/types/src/ui/stores/grid/fetch.ts index 8901acc08b..0be9ca17b4 100644 --- a/packages/types/src/ui/stores/grid/fetch.ts +++ b/packages/types/src/ui/stores/grid/fetch.ts @@ -1,12 +1,14 @@ import { Row, SortOrder, + Table, UIDatasource, UILegacyFilter, UISearchFilter, } from "@budibase/types" export interface UIFetchAPI { + fetchTableDefinition(tableId: string): Promise definition: UIDatasource getInitialData: () => Promise From d7cfd51caf50ba6603a711e8a0295e1ee3f7417b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 10:23:39 +0100 Subject: [PATCH 061/173] Type tablefetch --- packages/frontend-core/src/fetch/DataFetch.ts | 6 +++--- .../src/fetch/{TableFetch.js => TableFetch.ts} | 2 +- packages/types/src/ui/stores/grid/fetch.ts | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) rename packages/frontend-core/src/fetch/{TableFetch.js => TableFetch.ts} (96%) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index d8a8e15245..67ed07a835 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -322,10 +322,10 @@ export default abstract class DataFetch { abstract getData(): Promise<{ rows: UIRow[] - info: any + info?: any hasNextPage: boolean - cursor: any - error: any + cursor?: any + error?: any }> /** diff --git a/packages/frontend-core/src/fetch/TableFetch.js b/packages/frontend-core/src/fetch/TableFetch.ts similarity index 96% rename from packages/frontend-core/src/fetch/TableFetch.js rename to packages/frontend-core/src/fetch/TableFetch.ts index 777d16aa45..0615f83dc2 100644 --- a/packages/frontend-core/src/fetch/TableFetch.js +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -14,7 +14,7 @@ export default class TableFetch extends DataFetch { async getData() { const { datasource, limit, sortColumn, sortOrder, sortType, paginate } = this.options - const { tableId } = datasource + const { tableId } = datasource! const { cursor, query } = get(this.store) // Search table diff --git a/packages/types/src/ui/stores/grid/fetch.ts b/packages/types/src/ui/stores/grid/fetch.ts index 0be9ca17b4..772e68eb14 100644 --- a/packages/types/src/ui/stores/grid/fetch.ts +++ b/packages/types/src/ui/stores/grid/fetch.ts @@ -1,6 +1,8 @@ import { Row, + SearchFilters, SortOrder, + SortType, Table, UIDatasource, UILegacyFilter, @@ -15,6 +17,19 @@ export interface UIFetchAPI { loading: any loaded: boolean + searchTable( + tableId: string, + arg1: { + query: SearchFilters | null + limit: number + sort: string | null + sortOrder: string + sortType: SortType | null + paginate: boolean + bookmark: null + } + ): any + resetKey: string | null error: any From 89eba3189703454ed1055251713b98629cb53a14 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 12:16:53 +0100 Subject: [PATCH 062/173] Use tempaltes --- packages/frontend-core/src/fetch/DataFetch.ts | 14 ++++------- .../frontend-core/src/fetch/TableFetch.ts | 6 ++--- packages/types/src/ui/stores/grid/fetch.ts | 23 +++++++++---------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 67ed07a835..7355afd967 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -45,7 +45,7 @@ interface DataFetchDerivedStore extends DataFetchStore { * internal table or datasource plus. * For other types of datasource, this class is overridden and extended. */ -export default abstract class DataFetch { +export default abstract class DataFetch { API: UIFetchAPI features: { supportsSearch: boolean @@ -53,7 +53,7 @@ export default abstract class DataFetch { supportsPagination: boolean } options: { - datasource: UIDatasource | null + datasource: T limit: number // Search config filter: UISearchFilter | LegacyFilter[] | null @@ -76,11 +76,7 @@ export default abstract class DataFetch { * Constructs a new DataFetch instance. * @param opts the fetch options */ - constructor(opts: { - API: UIFetchAPI - datasource?: UIDatasource - options?: {} - }) { + constructor(opts: { API: UIFetchAPI; datasource: T; options?: {} }) { // Feature flags this.features = { supportsSearch: false, @@ -90,7 +86,7 @@ export default abstract class DataFetch { // Config this.options = { - datasource: null, + datasource: opts.datasource, limit: 10, // Search config @@ -182,7 +178,7 @@ export default abstract class DataFetch { getDefaultSortColumn( definition: { primaryDisplay?: string } | null, schema: Record - ) { + ): string | null { if (definition?.primaryDisplay && schema[definition.primaryDisplay]) { return definition.primaryDisplay } else { diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 0615f83dc2..e3a2e317be 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -1,8 +1,8 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch.js" -import { SortOrder } from "@budibase/types" +import { SortOrder, UITable } from "@budibase/types" -export default class TableFetch extends DataFetch { +export default class TableFetch extends DataFetch { determineFeatureFlags() { return { supportsSearch: true, @@ -14,7 +14,7 @@ export default class TableFetch extends DataFetch { async getData() { const { datasource, limit, sortColumn, sortOrder, sortType, paginate } = this.options - const { tableId } = datasource! + const { tableId } = datasource const { cursor, query } = get(this.store) // Search table diff --git a/packages/types/src/ui/stores/grid/fetch.ts b/packages/types/src/ui/stores/grid/fetch.ts index 772e68eb14..a81f436fde 100644 --- a/packages/types/src/ui/stores/grid/fetch.ts +++ b/packages/types/src/ui/stores/grid/fetch.ts @@ -9,6 +9,16 @@ import { UISearchFilter, } from "@budibase/types" +interface SearchOptions { + query: SearchFilters | null + limit: number + sort: string | null + sortOrder: string + sortType: SortType | null + paginate: boolean + bookmark: null +} + export interface UIFetchAPI { fetchTableDefinition(tableId: string): Promise
definition: UIDatasource @@ -17,18 +27,7 @@ export interface UIFetchAPI { loading: any loaded: boolean - searchTable( - tableId: string, - arg1: { - query: SearchFilters | null - limit: number - sort: string | null - sortOrder: string - sortType: SortType | null - paginate: boolean - bookmark: null - } - ): any + searchTable(tableId: string, options: SearchOptions): any resetKey: string | null error: any From 97eb4a2e79824923b41c47d3a51f9f2d76175a2a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 12:33:54 +0100 Subject: [PATCH 063/173] Type view fetch --- packages/frontend-core/src/fetch/DataFetch.ts | 22 ++++++++++------- .../fetch/{ViewV2Fetch.js => ViewV2Fetch.ts} | 24 +++++++++++-------- .../types/src/ui/stores/grid/datasource.ts | 4 +--- packages/types/src/ui/stores/grid/fetch.ts | 9 +++++-- packages/types/src/ui/stores/grid/view.ts | 3 ++- 5 files changed, 37 insertions(+), 25 deletions(-) rename packages/frontend-core/src/fetch/{ViewV2Fetch.js => ViewV2Fetch.ts} (70%) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 7355afd967..ea28cd7240 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -8,7 +8,6 @@ import { SearchFilters, SortOrder, SortType, - Table, TableSchema, UIDatasource, UIFetchAPI, @@ -18,7 +17,7 @@ import { const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils -interface DataFetchStore { +interface DataFetchStore { rows: UIRow[] info: null schema: TableSchema | null @@ -30,9 +29,11 @@ interface DataFetchStore { cursors: any[] resetKey: number error: null + definition?: T | null } -interface DataFetchDerivedStore extends DataFetchStore { +interface DataFetchDerivedStore + extends DataFetchStore { hasNextPage: boolean hasPrevPage: boolean supportsSearch: boolean @@ -69,8 +70,8 @@ export default abstract class DataFetch { clientSideSorting: boolean clientSideLimiting: boolean } - store: Writable - derivedStore: Readable + store: Writable> + derivedStore: Readable> /** * Constructs a new DataFetch instance. @@ -335,7 +336,7 @@ export default abstract class DataFetch { return null } try { - return await this.API.fetchTableDefinition(datasource.tableId) + return (await this.API.fetchTableDefinition(datasource.tableId)) as T } catch (error: any) { this.store.update(state => ({ ...state, @@ -352,7 +353,10 @@ export default abstract class DataFetch { * @param definition the datasource definition * @return {object} the schema */ - getSchema(_datasource: UIDatasource | null, definition: Table | null) { + getSchema( + _datasource: UIDatasource | null, + definition: T | null + ): TableSchema | undefined { return definition?.schema } @@ -412,7 +416,7 @@ export default abstract class DataFetch { * Determine the feature flag for this datasource definition * @param definition */ - determineFeatureFlags(_definition: Table | null) { + determineFeatureFlags(_definition: T | null) { return { supportsSearch: false, supportsSort: false, @@ -495,7 +499,7 @@ export default abstract class DataFetch { * @param state the current store state * @return {boolean} whether there is a next page of data or not */ - hasNextPage(state: DataFetchStore): boolean { + hasNextPage(state: DataFetchStore): boolean { return state.cursors[state.pageNumber + 1] != null } diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.js b/packages/frontend-core/src/fetch/ViewV2Fetch.ts similarity index 70% rename from packages/frontend-core/src/fetch/ViewV2Fetch.js rename to packages/frontend-core/src/fetch/ViewV2Fetch.ts index 8436646077..337c090c66 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.js +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -1,8 +1,9 @@ -import { ViewV2Type } from "@budibase/types" +import { SortOrder, UIView, ViewV2Type } from "@budibase/types" import DataFetch from "./DataFetch.js" import { get } from "svelte/store" +import { isCalculationField } from "packages/shared-core/src/helpers/views.js" -export default class ViewV2Fetch extends DataFetch { +export default class ViewV2Fetch extends DataFetch { determineFeatureFlags() { return { supportsSearch: true, @@ -11,18 +12,18 @@ export default class ViewV2Fetch extends DataFetch { } } - getSchema(datasource, definition) { + getSchema(_datasource: UIView | null, definition: UIView | null) { return definition?.schema } - async getDefinition(datasource) { + async getDefinition(datasource: UIView | null): Promise { if (!datasource?.id) { return null } try { const res = await this.API.viewV2.fetchDefinition(datasource.id) return res?.data - } catch (error) { + } catch (error: any) { this.store.update(state => ({ ...state, error, @@ -31,7 +32,10 @@ export default class ViewV2Fetch extends DataFetch { } } - getDefaultSortColumn() { + getDefaultSortColumn( + _definition: { primaryDisplay?: string } | null, + _schema: Record + ) { return null } @@ -42,8 +46,8 @@ export default class ViewV2Fetch extends DataFetch { // If this is a calculation view and we have no calculations, return nothing if ( - definition.type === ViewV2Type.CALCULATION && - !Object.values(definition.schema || {}).some(x => x.calculationType) + definition?.type === ViewV2Type.CALCULATION && + !Object.values(definition.schema || {}).some(isCalculationField) ) { return { rows: [], @@ -56,9 +60,9 @@ export default class ViewV2Fetch extends DataFetch { // If sort/filter params are not defined, update options to store the // params built in to this view. This ensures that we can accurately // compare old and new params and skip a redundant API call. - if (!sortColumn && definition.sort?.field) { + if (!sortColumn && definition?.sort?.field) { this.options.sortColumn = definition.sort.field - this.options.sortOrder = definition.sort.order + this.options.sortOrder = definition.sort.order || SortOrder.ASCENDING } try { diff --git a/packages/types/src/ui/stores/grid/datasource.ts b/packages/types/src/ui/stores/grid/datasource.ts index 9533bbb8f0..9927518133 100644 --- a/packages/types/src/ui/stores/grid/datasource.ts +++ b/packages/types/src/ui/stores/grid/datasource.ts @@ -1,8 +1,6 @@ import { UITable, UIView } from "@budibase/types" -export type UIDatasource = (UITable | UIView) & { - type: string -} +export type UIDatasource = UITable | UIView export interface UIFieldMutation { visible?: boolean diff --git a/packages/types/src/ui/stores/grid/fetch.ts b/packages/types/src/ui/stores/grid/fetch.ts index a81f436fde..a8732c66e3 100644 --- a/packages/types/src/ui/stores/grid/fetch.ts +++ b/packages/types/src/ui/stores/grid/fetch.ts @@ -10,10 +10,10 @@ import { } from "@budibase/types" interface SearchOptions { - query: SearchFilters | null + query?: SearchFilters | null | undefined limit: number sort: string | null - sortOrder: string + sortOrder: string | undefined sortType: SortType | null paginate: boolean bookmark: null @@ -29,6 +29,11 @@ export interface UIFetchAPI { searchTable(tableId: string, options: SearchOptions): any + viewV2: { + fetchDefinition: (datasourceId: string) => Promise + fetch: (datasourceId: string, options: SearchOptions) => any + } + resetKey: string | null error: any diff --git a/packages/types/src/ui/stores/grid/view.ts b/packages/types/src/ui/stores/grid/view.ts index f81cc34aaf..270faaa160 100644 --- a/packages/types/src/ui/stores/grid/view.ts +++ b/packages/types/src/ui/stores/grid/view.ts @@ -1,6 +1,7 @@ import { ViewV2 } from "@budibase/types" import { UIFieldSchema } from "./table" -export interface UIView extends ViewV2 { +export interface UIView extends Omit { + type: string schema: Record } From 163ca349a91d335c8344867761f892bcac994da1 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 13:21:36 +0100 Subject: [PATCH 064/173] Create apis --- packages/types/src/ui/stores/grid/fetch.ts | 35 +++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/types/src/ui/stores/grid/fetch.ts b/packages/types/src/ui/stores/grid/fetch.ts index a8732c66e3..5f42db24b0 100644 --- a/packages/types/src/ui/stores/grid/fetch.ts +++ b/packages/types/src/ui/stores/grid/fetch.ts @@ -19,20 +19,41 @@ interface SearchOptions { bookmark: null } -export interface UIFetchAPI { +interface TableAPI { fetchTableDefinition(tableId: string): Promise
+ searchTable(tableId: string, options: SearchOptions): any +} + +interface ViewV2API { + fetchDefinition: (datasourceId: string) => Promise + fetch: (datasourceId: string, options: SearchOptions) => any +} + +interface UserAPI { + searchUsers: (opts: { + bookmark: null + query: + | SearchFilters + | { + string: { + email: null + } + } + | null + appId: string + paginate: boolean + limit: number + }) => Promise +} + +export interface UIFetchAPI extends TableAPI, UserAPI { definition: UIDatasource getInitialData: () => Promise loading: any loaded: boolean - searchTable(tableId: string, options: SearchOptions): any - - viewV2: { - fetchDefinition: (datasourceId: string) => Promise - fetch: (datasourceId: string, options: SearchOptions) => any - } + viewV2: ViewV2API resetKey: string | null error: any From 1899af919077c8ca87030c2c27517ddb4565f549 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 13:33:24 +0100 Subject: [PATCH 065/173] More types --- packages/frontend-core/src/fetch/DataFetch.ts | 57 ++++++++----------- .../frontend-core/src/fetch/TableFetch.ts | 23 +++++++- .../frontend-core/src/fetch/ViewV2Fetch.ts | 8 +-- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index ea28cd7240..389ddd2f17 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -17,7 +17,7 @@ import { const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils -interface DataFetchStore { +interface DataFetchStore { rows: UIRow[] info: null schema: TableSchema | null @@ -32,8 +32,7 @@ interface DataFetchStore { definition?: T | null } -interface DataFetchDerivedStore - extends DataFetchStore { +interface DataFetchDerivedStore extends DataFetchStore { hasNextPage: boolean hasPrevPage: boolean supportsSearch: boolean @@ -46,7 +45,10 @@ interface DataFetchDerivedStore * internal table or datasource plus. * For other types of datasource, this class is overridden and extended. */ -export default abstract class DataFetch { +export default abstract class DataFetch< + TDatasource extends UIDatasource | null, + TDefinition extends { primaryDisplay?: string } +> { API: UIFetchAPI features: { supportsSearch: boolean @@ -54,7 +56,7 @@ export default abstract class DataFetch { supportsPagination: boolean } options: { - datasource: T + datasource: TDatasource limit: number // Search config filter: UISearchFilter | LegacyFilter[] | null @@ -70,14 +72,18 @@ export default abstract class DataFetch { clientSideSorting: boolean clientSideLimiting: boolean } - store: Writable> - derivedStore: Readable> + store: Writable> + derivedStore: Readable> /** * Constructs a new DataFetch instance. * @param opts the fetch options */ - constructor(opts: { API: UIFetchAPI; datasource: T; options?: {} }) { + constructor(opts: { + API: UIFetchAPI + datasource: TDatasource + options?: {} + }) { // Feature flags this.features = { supportsSearch: false, @@ -327,38 +333,23 @@ export default abstract class DataFetch { /** * Gets the definition for this datasource. - * Defaults to fetching a table definition. * @param datasource * @return {object} the definition */ - async getDefinition(datasource: UIDatasource | null) { - if (!datasource?.tableId) { - return null - } - try { - return (await this.API.fetchTableDefinition(datasource.tableId)) as T - } catch (error: any) { - this.store.update(state => ({ - ...state, - error, - })) - return null - } - } + abstract getDefinition( + datasource: UIDatasource | null + ): Promise /** * Gets the schema definition for a datasource. - * Defaults to getting the "schema" property of the definition. - * @param _datasource the datasource + * @param datasource the datasource * @param definition the datasource definition * @return {object} the schema */ - getSchema( - _datasource: UIDatasource | null, - definition: T | null - ): TableSchema | undefined { - return definition?.schema - } + abstract getSchema( + datasource: UIDatasource | null, + definition: TDefinition | null + ): any /** * Enriches a datasource schema with nested fields and ensures the structure @@ -416,7 +407,7 @@ export default abstract class DataFetch { * Determine the feature flag for this datasource definition * @param definition */ - determineFeatureFlags(_definition: T | null) { + determineFeatureFlags(_definition: TDefinition | null) { return { supportsSearch: false, supportsSort: false, @@ -499,7 +490,7 @@ export default abstract class DataFetch { * @param state the current store state * @return {boolean} whether there is a next page of data or not */ - hasNextPage(state: DataFetchStore): boolean { + hasNextPage(state: DataFetchStore): boolean { return state.cursors[state.pageNumber + 1] != null } diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index e3a2e317be..3c4a1b7abc 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -1,8 +1,8 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch.js" -import { SortOrder, UITable } from "@budibase/types" +import { SortOrder, Table, UITable } from "@budibase/types" -export default class TableFetch extends DataFetch { +export default class TableFetch extends DataFetch { determineFeatureFlags() { return { supportsSearch: true, @@ -11,6 +11,25 @@ export default class TableFetch extends DataFetch { } } + async getDefinition(datasource: UITable | null) { + if (!datasource?.tableId) { + return null + } + try { + return await this.API.fetchTableDefinition(datasource.tableId) + } catch (error: any) { + this.store.update(state => ({ + ...state, + error, + })) + return null + } + } + + getSchema(_datasource: UITable | null, definition: Table | null) { + return definition?.schema + } + async getData() { const { datasource, limit, sortColumn, sortOrder, sortType, paginate } = this.options diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 337c090c66..d880b3a549 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -1,9 +1,9 @@ -import { SortOrder, UIView, ViewV2Type } from "@budibase/types" +import { SortOrder, UIView, ViewV2, ViewV2Type } from "@budibase/types" import DataFetch from "./DataFetch.js" import { get } from "svelte/store" import { isCalculationField } from "packages/shared-core/src/helpers/views.js" -export default class ViewV2Fetch extends DataFetch { +export default class ViewV2Fetch extends DataFetch { determineFeatureFlags() { return { supportsSearch: true, @@ -12,11 +12,11 @@ export default class ViewV2Fetch extends DataFetch { } } - getSchema(_datasource: UIView | null, definition: UIView | null) { + getSchema(_datasource: UIView, definition: ViewV2) { return definition?.schema } - async getDefinition(datasource: UIView | null): Promise { + async getDefinition(datasource: UIView | null): Promise { if (!datasource?.id) { return null } From c7255362b0b8b1a72f785602526515d16669c62a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 13:36:38 +0100 Subject: [PATCH 066/173] Cleanup --- packages/frontend-core/src/fetch/DataFetch.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 389ddd2f17..2dc42c2425 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -9,7 +9,6 @@ import { SortOrder, SortType, TableSchema, - UIDatasource, UIFetchAPI, UIRow, UISearchFilter, @@ -46,8 +45,8 @@ interface DataFetchDerivedStore extends DataFetchStore { * For other types of datasource, this class is overridden and extended. */ export default abstract class DataFetch< - TDatasource extends UIDatasource | null, - TDefinition extends { primaryDisplay?: string } + TDatasource extends {}, + TDefinition extends {} > { API: UIFetchAPI features: { @@ -337,7 +336,7 @@ export default abstract class DataFetch< * @return {object} the definition */ abstract getDefinition( - datasource: UIDatasource | null + datasource: TDatasource | null ): Promise /** @@ -347,7 +346,7 @@ export default abstract class DataFetch< * @return {object} the schema */ abstract getSchema( - datasource: UIDatasource | null, + datasource: TDatasource | null, definition: TDefinition | null ): any From 54d5047b34932b4beab6f582d3a2b7059d6d488f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 13:38:38 +0100 Subject: [PATCH 067/173] Convert UserFetch --- .../src/fetch/{UserFetch.js => UserFetch.ts} | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) rename packages/frontend-core/src/fetch/{UserFetch.js => UserFetch.ts} (77%) diff --git a/packages/frontend-core/src/fetch/UserFetch.js b/packages/frontend-core/src/fetch/UserFetch.ts similarity index 77% rename from packages/frontend-core/src/fetch/UserFetch.js rename to packages/frontend-core/src/fetch/UserFetch.ts index 36f61542b5..730d96ebd5 100644 --- a/packages/frontend-core/src/fetch/UserFetch.js +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -2,9 +2,10 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch.js" import { TableNames } from "../constants" import { utils } from "@budibase/shared-core" +import { Table, UIFetchAPI } from "@budibase/types" -export default class UserFetch extends DataFetch { - constructor(opts) { +export default class UserFetch extends DataFetch<{ tableId: string }, {}> { + constructor(opts: { API: UIFetchAPI; datasource: Table; options?: {} }) { super({ ...opts, datasource: { @@ -27,12 +28,16 @@ export default class UserFetch extends DataFetch { } } + getSchema(_datasource: any, definition: Table | null) { + return definition?.schema + } + async getData() { const { limit, paginate } = this.options const { cursor, query } = get(this.store) // Convert old format to new one - we now allow use of the lucene format - const { appId, paginated, ...rest } = query || {} + const { appId, paginated, ...rest } = query || ({} as any) // TODO const finalQuery = utils.isSupportedUserSearch(rest) ? query : { string: { email: null } } From 65fa3e04346985c2d9f4293fb0e007d0c79f41e0 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 15:36:27 +0100 Subject: [PATCH 068/173] Use APIClient --- packages/frontend-core/src/fetch/DataFetch.ts | 16 ++++++---------- packages/frontend-core/src/fetch/TableFetch.ts | 4 ++-- packages/frontend-core/src/fetch/ViewV2Fetch.ts | 8 +++++--- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 2dc42c2425..ad709c9c77 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -5,19 +5,19 @@ import { convertJSONSchemaToTableSchema } from "../utils/json" import { FieldType, LegacyFilter, + Row, SearchFilters, SortOrder, SortType, TableSchema, - UIFetchAPI, - UIRow, UISearchFilter, } from "@budibase/types" +import { APIClient } from "../api/types" const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils interface DataFetchStore { - rows: UIRow[] + rows: Row[] info: null schema: TableSchema | null loading: boolean @@ -48,7 +48,7 @@ export default abstract class DataFetch< TDatasource extends {}, TDefinition extends {} > { - API: UIFetchAPI + API: APIClient features: { supportsSearch: boolean supportsSort: boolean @@ -78,11 +78,7 @@ export default abstract class DataFetch< * Constructs a new DataFetch instance. * @param opts the fetch options */ - constructor(opts: { - API: UIFetchAPI - datasource: TDatasource - options?: {} - }) { + constructor(opts: { API: APIClient; datasource: TDatasource; options?: {} }) { // Feature flags this.features = { supportsSearch: false, @@ -323,7 +319,7 @@ export default abstract class DataFetch< } abstract getData(): Promise<{ - rows: UIRow[] + rows: Row[] info?: any hasNextPage: boolean cursor?: any diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 3c4a1b7abc..08dc111b28 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -39,10 +39,10 @@ export default class TableFetch extends DataFetch { // Search table try { const res = await this.API.searchTable(tableId, { - query, + query: query ?? undefined, limit, sort: sortColumn, - sortOrder: sortOrder?.toLowerCase() ?? SortOrder.ASCENDING, + sortOrder: sortOrder ?? SortOrder.ASCENDING, sortType, paginate, bookmark: cursor, diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index d880b3a549..91d2385d3c 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -1,7 +1,7 @@ import { SortOrder, UIView, ViewV2, ViewV2Type } from "@budibase/types" import DataFetch from "./DataFetch.js" import { get } from "svelte/store" -import { isCalculationField } from "packages/shared-core/src/helpers/views.js" +import { helpers } from "@budibase/shared-core" export default class ViewV2Fetch extends DataFetch { determineFeatureFlags() { @@ -47,7 +47,9 @@ export default class ViewV2Fetch extends DataFetch { // If this is a calculation view and we have no calculations, return nothing if ( definition?.type === ViewV2Type.CALCULATION && - !Object.values(definition.schema || {}).some(isCalculationField) + !Object.values(definition.schema || {}).some( + helpers.views.isCalculationField + ) ) { return { rows: [], @@ -72,7 +74,7 @@ export default class ViewV2Fetch extends DataFetch { limit, bookmark: cursor, sort: sortColumn, - sortOrder: sortOrder?.toLowerCase(), + sortOrder: sortOrder, sortType, }) return { From 1f51489368acccbbeda3deb6ed219f4a60a3c723 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 15:48:04 +0100 Subject: [PATCH 069/173] Type views --- packages/frontend-core/src/api/viewsV2.ts | 13 ++++++--- .../frontend-core/src/fetch/ViewV2Fetch.ts | 28 +++++++++++++++---- .../server/src/api/controllers/row/views.ts | 11 ++++++-- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/packages/frontend-core/src/api/viewsV2.ts b/packages/frontend-core/src/api/viewsV2.ts index 5018448e8c..4a867e8f6a 100644 --- a/packages/frontend-core/src/api/viewsV2.ts +++ b/packages/frontend-core/src/api/viewsV2.ts @@ -1,6 +1,7 @@ import { CreateViewRequest, CreateViewResponse, + PaginatedSearchRowResponse, SearchRowResponse, SearchViewRowRequest, UpdateViewRequest, @@ -13,10 +14,14 @@ export interface ViewV2Endpoints { fetchDefinition: (viewId: string) => Promise create: (view: CreateViewRequest) => Promise update: (view: UpdateViewRequest) => Promise - fetch: ( + fetch: ( viewId: string, - opts: SearchViewRowRequest - ) => Promise + opts: T + ) => Promise< + T extends { paginate: true } + ? PaginatedSearchRowResponse + : SearchRowResponse + > delete: (viewId: string) => Promise } @@ -59,7 +64,7 @@ export const buildViewV2Endpoints = (API: BaseAPIClient): ViewV2Endpoints => ({ * @param viewId the id of the view * @param opts the search options */ - fetch: async (viewId, opts) => { + fetch: async (viewId, opts: SearchViewRowRequest) => { return await API.post({ url: `/api/v2/views/${encodeURIComponent(viewId)}/search`, body: opts, diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 91d2385d3c..d3b607a171 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -68,7 +68,7 @@ export default class ViewV2Fetch extends DataFetch { } try { - const res = await this.API.viewV2.fetch(datasource.id, { + const request = { ...(query ? { query } : {}), paginate, limit, @@ -76,11 +76,27 @@ export default class ViewV2Fetch extends DataFetch { sort: sortColumn, sortOrder: sortOrder, sortType, - }) - return { - rows: res?.rows || [], - hasNextPage: res?.hasNextPage || false, - cursor: res?.bookmark || null, + } + if (paginate) { + const res = await this.API.viewV2.fetch(datasource.id, { + ...request, + paginate, + }) + return { + rows: res?.rows || [], + hasNextPage: res?.hasNextPage || false, + cursor: res?.bookmark || null, + } + } else { + const res = await this.API.viewV2.fetch(datasource.id, { + ...request, + paginate, + }) + return { + rows: res?.rows || [], + hasNextPage: false, + cursor: null, + } } } catch (error) { return { diff --git a/packages/server/src/api/controllers/row/views.ts b/packages/server/src/api/controllers/row/views.ts index 0655a3b38f..dcf8680348 100644 --- a/packages/server/src/api/controllers/row/views.ts +++ b/packages/server/src/api/controllers/row/views.ts @@ -1,16 +1,16 @@ import { UserCtx, ViewV2, - SearchRowResponse, SearchViewRowRequest, RequiredKeys, RowSearchParams, + PaginatedSearchRowResponse, } from "@budibase/types" import sdk from "../../../sdk" import { context } from "@budibase/backend-core" export async function searchView( - ctx: UserCtx + ctx: UserCtx ) { const { viewId } = ctx.params @@ -49,7 +49,12 @@ export async function searchView( user: sdk.users.getUserContextBindings(ctx.user), }) result.rows.forEach(r => (r._viewId = view.id)) - ctx.body = result + + ctx.body = { + rows: result.rows, + bookmark: result.bookmark, + hasNextPage: result.hasNextPage, + } } function getSortOptions(request: SearchViewRowRequest, view: ViewV2) { From f0d60c606329558308bd9024865b5046e6f12f05 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 15:55:50 +0100 Subject: [PATCH 070/173] Fix user types --- packages/frontend-core/src/fetch/UserFetch.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 730d96ebd5..be73793768 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -2,10 +2,11 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch.js" import { TableNames } from "../constants" import { utils } from "@budibase/shared-core" -import { Table, UIFetchAPI } from "@budibase/types" +import { BasicOperator, SearchUsersRequest, Table } from "@budibase/types" +import { APIClient } from "../api/types.js" export default class UserFetch extends DataFetch<{ tableId: string }, {}> { - constructor(opts: { API: UIFetchAPI; datasource: Table; options?: {} }) { + constructor(opts: { API: APIClient; datasource: Table; options?: {} }) { super({ ...opts, datasource: { @@ -40,12 +41,12 @@ export default class UserFetch extends DataFetch<{ tableId: string }, {}> { const { appId, paginated, ...rest } = query || ({} as any) // TODO const finalQuery = utils.isSupportedUserSearch(rest) ? query - : { string: { email: null } } + : { [BasicOperator.EMPTY]: { email: true } } // TODO: check try { const opts = { - bookmark: cursor, - query: finalQuery, + bookmark: cursor ?? undefined, + query: finalQuery ?? undefined, appId: appId, paginate: paginated || paginate, limit, From 69ad15f79cb1b3dc482bf1557c35868d401f090c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 16:25:25 +0100 Subject: [PATCH 071/173] Fix types --- packages/frontend-core/src/api/views.ts | 2 +- packages/frontend-core/src/fetch/DataFetch.ts | 2 +- packages/frontend-core/src/fetch/TableFetch.ts | 2 +- packages/frontend-core/src/fetch/UserFetch.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend-core/src/api/views.ts b/packages/frontend-core/src/api/views.ts index 3f8ac8aa41..083a3890e8 100644 --- a/packages/frontend-core/src/api/views.ts +++ b/packages/frontend-core/src/api/views.ts @@ -3,7 +3,7 @@ import { BaseAPIClient } from "./types" export interface ViewEndpoints { // Missing request or response types - fetchViewData: (name: string, opts: any) => Promise + fetchViewData: (name: string, opts?: any) => Promise exportView: (name: string, format: string) => Promise saveView: (view: any) => Promise deleteView: (name: string) => Promise diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index ad709c9c77..73f4e8bd11 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -321,7 +321,7 @@ export default abstract class DataFetch< abstract getData(): Promise<{ rows: Row[] info?: any - hasNextPage: boolean + hasNextPage?: boolean cursor?: any error?: any }> diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 08dc111b28..3ea6063882 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -11,7 +11,7 @@ export default class TableFetch extends DataFetch { } } - async getDefinition(datasource: UITable | null) { + async getDefinition(datasource: UITable) { if (!datasource?.tableId) { return null } diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index be73793768..571825cd3b 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -2,7 +2,7 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch.js" import { TableNames } from "../constants" import { utils } from "@budibase/shared-core" -import { BasicOperator, SearchUsersRequest, Table } from "@budibase/types" +import { BasicOperator, Table } from "@budibase/types" import { APIClient } from "../api/types.js" export default class UserFetch extends DataFetch<{ tableId: string }, {}> { From b420fda5249943dbe52eb2c6485cdd09bec71046 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 16:25:37 +0100 Subject: [PATCH 072/173] Convert ViewFetch --- .../src/fetch/{ViewFetch.js => ViewFetch.ts} | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) rename packages/frontend-core/src/fetch/{ViewFetch.js => ViewFetch.ts} (50%) diff --git a/packages/frontend-core/src/fetch/ViewFetch.js b/packages/frontend-core/src/fetch/ViewFetch.ts similarity index 50% rename from packages/frontend-core/src/fetch/ViewFetch.js rename to packages/frontend-core/src/fetch/ViewFetch.ts index eb89f9b67a..65fad90564 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.js +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -1,7 +1,25 @@ +import { Table, View } from "@budibase/types" import DataFetch from "./DataFetch.js" -export default class ViewFetch extends DataFetch { - getSchema(datasource, definition) { +type ViewV1 = View & { name: string } + +export default class ViewFetch extends DataFetch { + async getDefinition(datasource: ViewV1) { + if (!datasource?.tableId) { + return null + } + try { + return await this.API.fetchTableDefinition(datasource.tableId) + } catch (error: any) { + this.store.update(state => ({ + ...state, + error, + })) + return null + } + } + + getSchema(datasource: ViewV1, definition: Table) { return definition?.views?.[datasource.name]?.schema } From 2b863cca61ac9096fcf132e8af6c36e46ddac163 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 2 Jan 2025 16:27:43 +0100 Subject: [PATCH 073/173] Fix imports --- packages/client/src/utils/schema.js | 6 +++--- packages/frontend-core/src/fetch/CustomFetch.js | 2 +- packages/frontend-core/src/fetch/FieldFetch.js | 2 +- packages/frontend-core/src/fetch/GroupUserFetch.js | 2 +- packages/frontend-core/src/fetch/NestedProviderFetch.js | 2 +- packages/frontend-core/src/fetch/QueryFetch.js | 2 +- packages/frontend-core/src/fetch/RelationshipFetch.js | 2 +- packages/frontend-core/src/fetch/TableFetch.ts | 2 +- packages/frontend-core/src/fetch/UserFetch.ts | 2 +- packages/frontend-core/src/fetch/ViewFetch.ts | 2 +- packages/frontend-core/src/fetch/ViewV2Fetch.ts | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index ec1cef53ce..9e8b9f3d4c 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -1,12 +1,12 @@ import { API } from "api" -import TableFetch from "@budibase/frontend-core/src/fetch/TableFetch.js" -import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch.js" +import TableFetch from "@budibase/frontend-core/src/fetch/TableFetch" +import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch" import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch.js" import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch.js" import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch.js" import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch.js" import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch.js" -import ViewV2Fetch from "@budibase/frontend-core/src/fetch/ViewV2Fetch.js" +import ViewV2Fetch from "@budibase/frontend-core/src/fetch/ViewV2Fetch" import QueryArrayFetch from "@budibase/frontend-core/src/fetch/QueryArrayFetch" /** diff --git a/packages/frontend-core/src/fetch/CustomFetch.js b/packages/frontend-core/src/fetch/CustomFetch.js index fc62d790e2..39d3bd6f4c 100644 --- a/packages/frontend-core/src/fetch/CustomFetch.js +++ b/packages/frontend-core/src/fetch/CustomFetch.js @@ -1,4 +1,4 @@ -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" export default class CustomFetch extends DataFetch { // Gets the correct Budibase type for a JS value diff --git a/packages/frontend-core/src/fetch/FieldFetch.js b/packages/frontend-core/src/fetch/FieldFetch.js index 9402a45a83..7c9d715761 100644 --- a/packages/frontend-core/src/fetch/FieldFetch.js +++ b/packages/frontend-core/src/fetch/FieldFetch.js @@ -1,4 +1,4 @@ -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" export default class FieldFetch extends DataFetch { async getDefinition(datasource) { diff --git a/packages/frontend-core/src/fetch/GroupUserFetch.js b/packages/frontend-core/src/fetch/GroupUserFetch.js index bd2cf264c5..e40b565728 100644 --- a/packages/frontend-core/src/fetch/GroupUserFetch.js +++ b/packages/frontend-core/src/fetch/GroupUserFetch.js @@ -1,5 +1,5 @@ import { get } from "svelte/store" -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" import { TableNames } from "../constants" export default class GroupUserFetch extends DataFetch { diff --git a/packages/frontend-core/src/fetch/NestedProviderFetch.js b/packages/frontend-core/src/fetch/NestedProviderFetch.js index 0a08b00cb4..06c74cb6c4 100644 --- a/packages/frontend-core/src/fetch/NestedProviderFetch.js +++ b/packages/frontend-core/src/fetch/NestedProviderFetch.js @@ -1,4 +1,4 @@ -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" export default class NestedProviderFetch extends DataFetch { async getDefinition(datasource) { diff --git a/packages/frontend-core/src/fetch/QueryFetch.js b/packages/frontend-core/src/fetch/QueryFetch.js index 9fac9704d3..4f7954c068 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.js +++ b/packages/frontend-core/src/fetch/QueryFetch.js @@ -1,4 +1,4 @@ -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" import { Helpers } from "@budibase/bbui" import { get } from "svelte/store" diff --git a/packages/frontend-core/src/fetch/RelationshipFetch.js b/packages/frontend-core/src/fetch/RelationshipFetch.js index 0dec535724..61f0207558 100644 --- a/packages/frontend-core/src/fetch/RelationshipFetch.js +++ b/packages/frontend-core/src/fetch/RelationshipFetch.js @@ -1,4 +1,4 @@ -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" export default class RelationshipFetch extends DataFetch { async getData() { diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 3ea6063882..58ad554d6a 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -1,5 +1,5 @@ import { get } from "svelte/store" -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" import { SortOrder, Table, UITable } from "@budibase/types" export default class TableFetch extends DataFetch { diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 571825cd3b..a0f95afe3e 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -1,5 +1,5 @@ import { get } from "svelte/store" -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" import { TableNames } from "../constants" import { utils } from "@budibase/shared-core" import { BasicOperator, Table } from "@budibase/types" diff --git a/packages/frontend-core/src/fetch/ViewFetch.ts b/packages/frontend-core/src/fetch/ViewFetch.ts index 65fad90564..cbdd1d425b 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.ts +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -1,5 +1,5 @@ import { Table, View } from "@budibase/types" -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" type ViewV1 = View & { name: string } diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index d3b607a171..7973dbf298 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -1,5 +1,5 @@ import { SortOrder, UIView, ViewV2, ViewV2Type } from "@budibase/types" -import DataFetch from "./DataFetch.js" +import DataFetch from "./DataFetch" import { get } from "svelte/store" import { helpers } from "@budibase/shared-core" From 543660dc2e9448730eb89e71402d5f753acf16b3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 3 Jan 2025 12:34:36 +0100 Subject: [PATCH 074/173] Convert fieldFetch --- .../fetch/{FieldFetch.js => FieldFetch.ts} | 30 +++++++++++++++---- .../frontend-core/src/fetch/JSONArrayFetch.js | 2 +- .../src/fetch/QueryArrayFetch.js | 2 +- packages/frontend-core/src/fetch/index.ts | 2 +- 4 files changed, 28 insertions(+), 8 deletions(-) rename packages/frontend-core/src/fetch/{FieldFetch.js => FieldFetch.ts} (52%) diff --git a/packages/frontend-core/src/fetch/FieldFetch.js b/packages/frontend-core/src/fetch/FieldFetch.ts similarity index 52% rename from packages/frontend-core/src/fetch/FieldFetch.js rename to packages/frontend-core/src/fetch/FieldFetch.ts index 7c9d715761..7f0dfdf331 100644 --- a/packages/frontend-core/src/fetch/FieldFetch.js +++ b/packages/frontend-core/src/fetch/FieldFetch.ts @@ -1,9 +1,29 @@ +import { Row, TableSchema } from "@budibase/types" import DataFetch from "./DataFetch" -export default class FieldFetch extends DataFetch { - async getDefinition(datasource) { +interface FieldDatasource { + fieldType: "attachment" | "array" + value: string[] | Row[] +} + +function isArrayOfStrings(value: string[] | Row[]): value is string[] { + return Array.isArray(value) && !!value[0] && typeof value[0] !== "object" +} + +export default class FieldFetch extends DataFetch< + FieldDatasource, + { schema?: Record } +> { + getSchema( + _datasource: FieldDatasource, + definition: { schema?: TableSchema } + ) { + return definition?.schema + } + + async getDefinition(datasource: FieldDatasource) { // Field sources have their schema statically defined - let schema + let schema: Record | undefined if (datasource.fieldType === "attachment") { schema = { url: { @@ -28,8 +48,8 @@ export default class FieldFetch extends DataFetch { // These sources will be available directly from context const data = datasource?.value || [] - let rows - if (Array.isArray(data) && data[0] && typeof data[0] !== "object") { + let rows: Row[] + if (isArrayOfStrings(data)) { rows = data.map(value => ({ value })) } else { rows = data diff --git a/packages/frontend-core/src/fetch/JSONArrayFetch.js b/packages/frontend-core/src/fetch/JSONArrayFetch.js index ab2af3e2c7..f7de74a4b8 100644 --- a/packages/frontend-core/src/fetch/JSONArrayFetch.js +++ b/packages/frontend-core/src/fetch/JSONArrayFetch.js @@ -1,4 +1,4 @@ -import FieldFetch from "./FieldFetch.js" +import FieldFetch from "./FieldFetch" import { getJSONArrayDatasourceSchema } from "../utils/json" export default class JSONArrayFetch extends FieldFetch { diff --git a/packages/frontend-core/src/fetch/QueryArrayFetch.js b/packages/frontend-core/src/fetch/QueryArrayFetch.js index 0b36b640a6..222697b78f 100644 --- a/packages/frontend-core/src/fetch/QueryArrayFetch.js +++ b/packages/frontend-core/src/fetch/QueryArrayFetch.js @@ -1,4 +1,4 @@ -import FieldFetch from "./FieldFetch.js" +import FieldFetch from "./FieldFetch" import { getJSONArrayDatasourceSchema, generateQueryArraySchemas, diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index a08748a77e..502b2d3162 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -4,7 +4,7 @@ import ViewV2Fetch from "./ViewV2Fetch.js" import QueryFetch from "./QueryFetch.js" import RelationshipFetch from "./RelationshipFetch.js" import NestedProviderFetch from "./NestedProviderFetch.js" -import FieldFetch from "./FieldFetch.js" +import FieldFetch from "./FieldFetch" import JSONArrayFetch from "./JSONArrayFetch.js" import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch.js" From 97b0883c6b8b1da5ee8912fe7a861129e932b2f2 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 3 Jan 2025 12:34:43 +0100 Subject: [PATCH 075/173] Convert fieldFetch --- packages/client/src/utils/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 9e8b9f3d4c..2b5dae0acf 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -4,7 +4,7 @@ import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch" import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch.js" import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch.js" import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch.js" -import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch.js" +import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch" import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch.js" import ViewV2Fetch from "@budibase/frontend-core/src/fetch/ViewV2Fetch" import QueryArrayFetch from "@budibase/frontend-core/src/fetch/QueryArrayFetch" From 550cdd7268d102117dcba98ec210383b6e65c5b4 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 3 Jan 2025 12:48:35 +0100 Subject: [PATCH 076/173] Fix field selector on datasource picker --- .../controls/DataSourceSelect/DataSourceSelect.svelte | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte index e7a30e68dd..b23ef5348d 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte @@ -43,7 +43,6 @@ export let showDataProviders = true const dispatch = createEventDispatcher() - const arrayTypes = ["attachment", "array"] let anchorRight, dropdownRight let drawer @@ -116,8 +115,11 @@ } }) $: fields = bindings - .filter(x => arrayTypes.includes(x.fieldSchema?.type)) - .filter(x => x.fieldSchema?.tableId != null) + .filter( + x => + x.fieldSchema?.type === "attachment" || + (x.fieldSchema?.type === "array" && x.tableId) + ) .map(binding => { const { providerId, readableBinding, runtimeBinding } = binding const { name, type, tableId } = binding.fieldSchema From 1d661c6290cc54c5b5fd27669fee530375a5a64b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 3 Jan 2025 15:37:04 +0100 Subject: [PATCH 077/173] Fix sort issue (with broken ts) --- packages/frontend-core/src/fetch/TableFetch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 58ad554d6a..344ce30e54 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -42,7 +42,7 @@ export default class TableFetch extends DataFetch { query: query ?? undefined, limit, sort: sortColumn, - sortOrder: sortOrder ?? SortOrder.ASCENDING, + sortOrder: sortOrder?.toLowerCase() ?? SortOrder.ASCENDING, sortType, paginate, bookmark: cursor, From af22eb30a60da04b39dc44834974a3bfcc06ac68 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 10:14:18 +0100 Subject: [PATCH 078/173] Type relationship fetch --- packages/client/src/utils/schema.js | 2 +- .../src/fetch/RelationshipFetch.js | 20 -------- .../src/fetch/RelationshipFetch.ts | 50 +++++++++++++++++++ packages/frontend-core/src/fetch/index.ts | 2 +- 4 files changed, 52 insertions(+), 22 deletions(-) delete mode 100644 packages/frontend-core/src/fetch/RelationshipFetch.js create mode 100644 packages/frontend-core/src/fetch/RelationshipFetch.ts diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 2b5dae0acf..87859f1ef8 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -2,7 +2,7 @@ import { API } from "api" import TableFetch from "@budibase/frontend-core/src/fetch/TableFetch" import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch" import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch.js" -import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch.js" +import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch" import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch.js" import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch" import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch.js" diff --git a/packages/frontend-core/src/fetch/RelationshipFetch.js b/packages/frontend-core/src/fetch/RelationshipFetch.js deleted file mode 100644 index 61f0207558..0000000000 --- a/packages/frontend-core/src/fetch/RelationshipFetch.js +++ /dev/null @@ -1,20 +0,0 @@ -import DataFetch from "./DataFetch" - -export default class RelationshipFetch extends DataFetch { - async getData() { - const { datasource } = this.options - if (!datasource?.rowId || !datasource?.rowTableId) { - return { rows: [] } - } - try { - const res = await this.API.fetchRelationshipData( - datasource.rowTableId, - datasource.rowId, - datasource.fieldName - ) - return { rows: res } - } catch (error) { - return { rows: [] } - } - } -} diff --git a/packages/frontend-core/src/fetch/RelationshipFetch.ts b/packages/frontend-core/src/fetch/RelationshipFetch.ts new file mode 100644 index 0000000000..ab50285b4b --- /dev/null +++ b/packages/frontend-core/src/fetch/RelationshipFetch.ts @@ -0,0 +1,50 @@ +import { Table } from "@budibase/types" +import DataFetch from "./DataFetch" + +interface RelationshipDatasource { + tableId: string + rowId: string + rowTableId: string + fieldName: string +} + +export default class RelationshipFetch extends DataFetch< + RelationshipDatasource, + Table +> { + getSchema(_datasource: any, definition: any) { + return definition?.schema + } + + async getDefinition(datasource: RelationshipDatasource) { + if (!datasource?.tableId) { + return null + } + try { + return await this.API.fetchTableDefinition(datasource.tableId) + } catch (error: any) { + this.store.update(state => ({ + ...state, + error, + })) + return null + } + } + + async getData() { + const { datasource } = this.options + if (!datasource?.rowId || !datasource?.rowTableId) { + return { rows: [] } + } + try { + const res = await this.API.fetchRelationshipData( + datasource.rowTableId, + datasource.rowId, + datasource.fieldName + ) + return { rows: res } + } catch (error) { + return { rows: [] } + } + } +} diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 502b2d3162..0fbda7a414 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -2,7 +2,7 @@ import TableFetch from "./TableFetch.js" import ViewFetch from "./ViewFetch.js" import ViewV2Fetch from "./ViewV2Fetch.js" import QueryFetch from "./QueryFetch.js" -import RelationshipFetch from "./RelationshipFetch.js" +import RelationshipFetch from "./RelationshipFetch" import NestedProviderFetch from "./NestedProviderFetch.js" import FieldFetch from "./FieldFetch" import JSONArrayFetch from "./JSONArrayFetch.js" From 8d748338739adc9cb66bf80497a0e8723ac4a32c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 11:02:09 +0100 Subject: [PATCH 079/173] Type groupUserFetch --- packages/frontend-core/src/fetch/DataFetch.ts | 35 ++++++++++++------- .../{GroupUserFetch.js => GroupUserFetch.ts} | 25 +++++++++++-- packages/frontend-core/src/fetch/index.ts | 2 +- 3 files changed, 45 insertions(+), 17 deletions(-) rename packages/frontend-core/src/fetch/{GroupUserFetch.js => GroupUserFetch.ts} (67%) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 73f4e8bd11..ef05f7b8ef 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -16,22 +16,23 @@ import { APIClient } from "../api/types" const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils -interface DataFetchStore { +interface DataFetchStore { rows: Row[] info: null schema: TableSchema | null loading: boolean loaded: boolean - query: SearchFilters | null + query: TQuery pageNumber: number cursor: null cursors: any[] resetKey: number error: null - definition?: T | null + definition?: TDefinition | null } -interface DataFetchDerivedStore extends DataFetchStore { +interface DataFetchDerivedStore + extends DataFetchStore { hasNextPage: boolean hasPrevPage: boolean supportsSearch: boolean @@ -39,6 +40,13 @@ interface DataFetchDerivedStore extends DataFetchStore { supportsPagination: boolean } +interface DataFetchParams { + API: APIClient + datasource: TDatasource + query: TQuery + options?: {} +} + /** * Parent class which handles the implementation of fetching data from an * internal table or datasource plus. @@ -46,7 +54,8 @@ interface DataFetchDerivedStore extends DataFetchStore { */ export default abstract class DataFetch< TDatasource extends {}, - TDefinition extends {} + TDefinition extends {}, + TQuery extends {} = SearchFilters > { API: APIClient features: { @@ -59,7 +68,7 @@ export default abstract class DataFetch< limit: number // Search config filter: UISearchFilter | LegacyFilter[] | null - query: SearchFilters | null + query: TQuery // Sorting config sortColumn: string | null sortOrder: SortOrder @@ -71,14 +80,14 @@ export default abstract class DataFetch< clientSideSorting: boolean clientSideLimiting: boolean } - store: Writable> - derivedStore: Readable> + store: Writable> + derivedStore: Readable> /** * Constructs a new DataFetch instance. * @param opts the fetch options */ - constructor(opts: { API: APIClient; datasource: TDatasource; options?: {} }) { + constructor(opts: DataFetchParams) { // Feature flags this.features = { supportsSearch: false, @@ -93,7 +102,7 @@ export default abstract class DataFetch< // Search config filter: null, - query: null, + query: opts.query, // Sorting config sortColumn: null, @@ -116,7 +125,7 @@ export default abstract class DataFetch< schema: null, loading: false, loaded: false, - query: null, + query: opts.query, pageNumber: 0, cursor: null, cursors: [], @@ -247,7 +256,7 @@ export default abstract class DataFetch< // Build the query let query = this.options.query if (!query) { - query = buildQuery(filter ?? undefined) + query = buildQuery(filter ?? undefined) as TQuery } // Update store @@ -485,7 +494,7 @@ export default abstract class DataFetch< * @param state the current store state * @return {boolean} whether there is a next page of data or not */ - hasNextPage(state: DataFetchStore): boolean { + hasNextPage(state: DataFetchStore): boolean { return state.cursors[state.pageNumber + 1] != null } diff --git a/packages/frontend-core/src/fetch/GroupUserFetch.js b/packages/frontend-core/src/fetch/GroupUserFetch.ts similarity index 67% rename from packages/frontend-core/src/fetch/GroupUserFetch.js rename to packages/frontend-core/src/fetch/GroupUserFetch.ts index e40b565728..77b5e1de43 100644 --- a/packages/frontend-core/src/fetch/GroupUserFetch.js +++ b/packages/frontend-core/src/fetch/GroupUserFetch.ts @@ -1,9 +1,23 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch" import { TableNames } from "../constants" +import { APIClient } from "../api/types" -export default class GroupUserFetch extends DataFetch { - constructor(opts) { +interface GroupUserQuery { + groupId: string + emailSearch: string +} + +export default class GroupUserFetch extends DataFetch< + any, + any, + GroupUserQuery +> { + constructor(opts: { + API: APIClient + datasource: any + query: GroupUserQuery + }) { super({ ...opts, datasource: { @@ -12,6 +26,10 @@ export default class GroupUserFetch extends DataFetch { }) } + getSchema(_datasource: any, definition: any) { + return definition?.schema + } + determineFeatureFlags() { return { supportsSearch: true, @@ -28,11 +46,12 @@ export default class GroupUserFetch extends DataFetch { async getData() { const { query, cursor } = get(this.store) + try { const res = await this.API.getGroupUsers({ id: query.groupId, emailSearch: query.emailSearch, - bookmark: cursor, + bookmark: cursor ?? undefined, }) return { diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 0fbda7a414..ef471aa8e4 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -7,7 +7,7 @@ import NestedProviderFetch from "./NestedProviderFetch.js" import FieldFetch from "./FieldFetch" import JSONArrayFetch from "./JSONArrayFetch.js" import UserFetch from "./UserFetch.js" -import GroupUserFetch from "./GroupUserFetch.js" +import GroupUserFetch from "./GroupUserFetch" import CustomFetch from "./CustomFetch.js" import QueryArrayFetch from "./QueryArrayFetch.js" import { Table, UIDatasource, UIFetchAPI } from "@budibase/types" From c52dd568723ae2c1933a1bb40eb91f5782421f39 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 11:17:42 +0100 Subject: [PATCH 080/173] Fix userFetch query --- packages/frontend-core/src/fetch/UserFetch.ts | 36 ++++++++++++++----- packages/shared-core/src/utils.ts | 4 ++- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index a0f95afe3e..e276af3592 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -2,11 +2,30 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch" import { TableNames } from "../constants" import { utils } from "@budibase/shared-core" -import { BasicOperator, Table } from "@budibase/types" +import { + BasicOperator, + SearchFilters, + SearchUsersRequest, + Table, +} from "@budibase/types" import { APIClient } from "../api/types.js" -export default class UserFetch extends DataFetch<{ tableId: string }, {}> { - constructor(opts: { API: APIClient; datasource: Table; options?: {} }) { +interface UserFetchQuery { + appId: string + paginated: boolean +} + +export default class UserFetch extends DataFetch< + { tableId: string }, + {}, + UserFetchQuery +> { + constructor(opts: { + API: APIClient + datasource: Table + options?: {} + query: UserFetchQuery + }) { super({ ...opts, datasource: { @@ -38,13 +57,14 @@ export default class UserFetch extends DataFetch<{ tableId: string }, {}> { const { cursor, query } = get(this.store) // Convert old format to new one - we now allow use of the lucene format - const { appId, paginated, ...rest } = query || ({} as any) // TODO - const finalQuery = utils.isSupportedUserSearch(rest) - ? query - : { [BasicOperator.EMPTY]: { email: true } } // TODO: check + const { appId, paginated, ...rest } = query || {} + + const finalQuery: SearchFilters = utils.isSupportedUserSearch(rest) + ? rest + : { [BasicOperator.EMPTY]: { email: true } } try { - const opts = { + const opts: SearchUsersRequest = { bookmark: cursor ?? undefined, query: finalQuery ?? undefined, appId: appId, diff --git a/packages/shared-core/src/utils.ts b/packages/shared-core/src/utils.ts index e2c40a8849..fac8fa61ee 100644 --- a/packages/shared-core/src/utils.ts +++ b/packages/shared-core/src/utils.ts @@ -109,7 +109,9 @@ export function trimOtherProps(object: any, allowedProps: string[]) { return result } -export function isSupportedUserSearch(query: SearchFilters) { +export function isSupportedUserSearch( + query: SearchFilters +): query is SearchFilters { const allowed = [ { op: BasicOperator.STRING, key: "email" }, { op: BasicOperator.EQUAL, key: "_id" }, From dedf2e58594841fc62cc10897f5208614fec479c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 11:22:22 +0100 Subject: [PATCH 081/173] Fix types --- packages/frontend-core/src/fetch/index.ts | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index ef471aa8e4..4d5b2f147a 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -10,7 +10,8 @@ import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch" import CustomFetch from "./CustomFetch.js" import QueryArrayFetch from "./QueryArrayFetch.js" -import { Table, UIDatasource, UIFetchAPI } from "@budibase/types" +import { Table, UIDatasource } from "@budibase/types" +import { APIClient } from "../api/types.js" const DataFetchMap = { table: TableFetch, @@ -30,15 +31,7 @@ const DataFetchMap = { } // Constructs a new fetch model for a certain datasource -export const fetchData = ({ - API, - datasource, - options, -}: { - API: UIFetchAPI - datasource: UIDatasource - options: {} -}) => { +export const fetchData = ({ API, datasource, options }: any) => { const Fetch = DataFetchMap[datasource?.type as keyof typeof DataFetchMap] || TableFetch return new Fetch({ API, datasource, ...options }) @@ -50,14 +43,14 @@ const createEmptyFetchInstance = ({ API, datasource, }: { - API: UIFetchAPI - datasource: UIDatasource + API: APIClient + datasource: any }) => { const handler = DataFetchMap[datasource?.type as keyof typeof DataFetchMap] if (!handler) { return null } - return new handler({ API }) + return new handler({ API, datasource: null as any, query: null as any }) } // Fetches the definition of any type of datasource @@ -65,7 +58,7 @@ export const getDatasourceDefinition = async ({ API, datasource, }: { - API: UIFetchAPI + API: APIClient datasource: UIDatasource }) => { const instance = createEmptyFetchInstance({ API, datasource }) @@ -78,7 +71,7 @@ export const getDatasourceSchema = ({ datasource, definition, }: { - API: UIFetchAPI + API: APIClient datasource: UIDatasource definition: Table }) => { From 0eddc1a00eb1819800471eabed148adbefbebb96 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 11:47:10 +0100 Subject: [PATCH 082/173] Type QueryFetch --- packages/client/src/utils/schema.js | 2 +- packages/frontend-core/src/fetch/DataFetch.ts | 11 ++++++-- .../fetch/{QueryFetch.js => QueryFetch.ts} | 28 +++++++++++++++---- packages/frontend-core/src/fetch/index.ts | 2 +- 4 files changed, 34 insertions(+), 9 deletions(-) rename packages/frontend-core/src/fetch/{QueryFetch.js => QueryFetch.ts} (82%) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 87859f1ef8..3a1b5acaaa 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -1,7 +1,7 @@ import { API } from "api" import TableFetch from "@budibase/frontend-core/src/fetch/TableFetch" import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch" -import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch.js" +import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch" import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch" import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch.js" import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch" diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index ef05f7b8ef..60cb96cf8c 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -40,7 +40,10 @@ interface DataFetchDerivedStore supportsPagination: boolean } -interface DataFetchParams { +export interface DataFetchParams< + TDatasource, + TQuery = SearchFilters | undefined +> { API: APIClient datasource: TDatasource query: TQuery @@ -411,7 +414,11 @@ export default abstract class DataFetch< * Determine the feature flag for this datasource definition * @param definition */ - determineFeatureFlags(_definition: TDefinition | null) { + determineFeatureFlags(_definition: TDefinition | null): { + supportsPagination: boolean + supportsSearch?: boolean + supportsSort?: boolean + } { return { supportsSearch: false, supportsSort: false, diff --git a/packages/frontend-core/src/fetch/QueryFetch.js b/packages/frontend-core/src/fetch/QueryFetch.ts similarity index 82% rename from packages/frontend-core/src/fetch/QueryFetch.js rename to packages/frontend-core/src/fetch/QueryFetch.ts index 4f7954c068..c671781fcd 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.js +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -1,9 +1,21 @@ import DataFetch from "./DataFetch" import { Helpers } from "@budibase/bbui" +import { Query } from "@budibase/types" import { get } from "svelte/store" -export default class QueryFetch extends DataFetch { - determineFeatureFlags(definition) { +interface QueryDatasource { + _id: string + fields: any + queryParams: any + parameters: any +} + +export default class QueryFetch extends DataFetch { + getSchema(_datasource: any, definition: any) { + return definition?.schema + } + + determineFeatureFlags(definition: Query) { const supportsPagination = !!definition?.fields?.pagination?.type && !!definition?.fields?.pagination?.location && @@ -11,7 +23,7 @@ export default class QueryFetch extends DataFetch { return { supportsPagination } } - async getDefinition(datasource) { + async getDefinition(datasource: QueryDatasource) { if (!datasource?._id) { return null } @@ -48,9 +60,15 @@ export default class QueryFetch extends DataFetch { } // Add pagination to query if supported - let queryPayload = { parameters } + const queryPayload: { + parameters: any + pagination?: { + page: number | null + limit: number + } + } = { parameters } if (paginate && supportsPagination) { - const requestCursor = type === "page" ? parseInt(cursor || 1) : cursor + const requestCursor = type === "page" ? parseInt(cursor || "1") : cursor queryPayload.pagination = { page: requestCursor, limit } } diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 4d5b2f147a..fc029324ba 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -1,7 +1,7 @@ import TableFetch from "./TableFetch.js" import ViewFetch from "./ViewFetch.js" import ViewV2Fetch from "./ViewV2Fetch.js" -import QueryFetch from "./QueryFetch.js" +import QueryFetch from "./QueryFetch" import RelationshipFetch from "./RelationshipFetch" import NestedProviderFetch from "./NestedProviderFetch.js" import FieldFetch from "./FieldFetch" From 8c0e7a12d681c3c95aaba9f61e3b2cad166ad2b4 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 11:54:42 +0100 Subject: [PATCH 083/173] Remove anys --- packages/server/src/api/controllers/query/index.ts | 4 ++-- packages/types/src/documents/app/query.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/query/index.ts b/packages/server/src/api/controllers/query/index.ts index 7084d065fa..b522008cad 100644 --- a/packages/server/src/api/controllers/query/index.ts +++ b/packages/server/src/api/controllers/query/index.ts @@ -355,7 +355,7 @@ async function execute( ExecuteQueryRequest, ExecuteV2QueryResponse | ExecuteV1QueryResponse >, - opts: any = { rowsOnly: false, isAutomation: false } + opts = { rowsOnly: false, isAutomation: false } ) { const db = context.getAppDB() @@ -416,7 +416,7 @@ export async function executeV1( export async function executeV2( ctx: UserCtx ) { - return execute(ctx, { rowsOnly: false }) + return execute(ctx, { rowsOnly: false, isAutomation: false }) } export async function executeV2AsAutomation( diff --git a/packages/types/src/documents/app/query.ts b/packages/types/src/documents/app/query.ts index a545ca144e..43e7563b31 100644 --- a/packages/types/src/documents/app/query.ts +++ b/packages/types/src/documents/app/query.ts @@ -1,4 +1,5 @@ import { Document } from "../document" +import { Row } from "./row" export interface QuerySchema { name?: string @@ -29,7 +30,7 @@ export interface QueryParameter { } export interface QueryResponse { - rows: any[] + rows: Row[] keys: string[] info: any extra: any From f4ed2176c96bd62cad45afcdbc68cd40eac29a2a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 12:06:37 +0100 Subject: [PATCH 084/173] Fix types --- packages/frontend-core/src/fetch/QueryFetch.ts | 2 +- packages/types/src/api/web/app/query.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/QueryFetch.ts b/packages/frontend-core/src/fetch/QueryFetch.ts index c671781fcd..d85b5ffbcd 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.ts +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -83,7 +83,7 @@ export default class QueryFetch extends DataFetch { if (paginate && supportsPagination) { if (type === "page") { // For "page number" pagination, increment the existing page number - nextCursor = queryPayload.pagination.page + 1 + nextCursor = queryPayload.pagination!.page! + 1 hasNextPage = data?.length === limit && limit > 0 } else { // For "cursor" pagination, the cursor should be in the response diff --git a/packages/types/src/api/web/app/query.ts b/packages/types/src/api/web/app/query.ts index 302f0d03e5..75cc37e1a9 100644 --- a/packages/types/src/api/web/app/query.ts +++ b/packages/types/src/api/web/app/query.ts @@ -40,6 +40,10 @@ export interface ExecuteQueryRequest { export type ExecuteV1QueryResponse = Record[] export interface ExecuteV2QueryResponse { data: Record[] + pagination?: { + page: number + cursor: string + } } export interface DeleteQueryResponse { From 89485aa9d11aca31163e97e971a9579959b5e3e8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 12:39:40 +0100 Subject: [PATCH 085/173] Extend types --- packages/frontend-core/src/fetch/FieldFetch.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/FieldFetch.ts b/packages/frontend-core/src/fetch/FieldFetch.ts index 7f0dfdf331..5e89d6e881 100644 --- a/packages/frontend-core/src/fetch/FieldFetch.ts +++ b/packages/frontend-core/src/fetch/FieldFetch.ts @@ -1,7 +1,8 @@ import { Row, TableSchema } from "@budibase/types" import DataFetch from "./DataFetch" -interface FieldDatasource { +export interface FieldDatasource { + tableId: string fieldType: "attachment" | "array" value: string[] | Row[] } From 364e997fc2f338d051cfd32c36f3a066c4323375 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 12:41:37 +0100 Subject: [PATCH 086/173] Type jsonArrayFetch --- packages/client/src/utils/schema.js | 2 +- packages/frontend-core/src/fetch/FieldFetch.ts | 12 +++++++++--- .../fetch/{JSONArrayFetch.js => JSONArrayFetch.ts} | 9 ++++++--- packages/frontend-core/src/fetch/index.ts | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) rename packages/frontend-core/src/fetch/{JSONArrayFetch.js => JSONArrayFetch.ts} (63%) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 3a1b5acaaa..f9cd7dbc60 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -5,7 +5,7 @@ import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch" import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch" import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch.js" import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch" -import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch.js" +import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch" import ViewV2Fetch from "@budibase/frontend-core/src/fetch/ViewV2Fetch" import QueryArrayFetch from "@budibase/frontend-core/src/fetch/QueryArrayFetch" diff --git a/packages/frontend-core/src/fetch/FieldFetch.ts b/packages/frontend-core/src/fetch/FieldFetch.ts index 5e89d6e881..6809dee00e 100644 --- a/packages/frontend-core/src/fetch/FieldFetch.ts +++ b/packages/frontend-core/src/fetch/FieldFetch.ts @@ -7,13 +7,17 @@ export interface FieldDatasource { value: string[] | Row[] } +export interface FieldDefinition { + schema?: Record | null +} + function isArrayOfStrings(value: string[] | Row[]): value is string[] { return Array.isArray(value) && !!value[0] && typeof value[0] !== "object" } export default class FieldFetch extends DataFetch< FieldDatasource, - { schema?: Record } + FieldDefinition > { getSchema( _datasource: FieldDatasource, @@ -22,9 +26,11 @@ export default class FieldFetch extends DataFetch< return definition?.schema } - async getDefinition(datasource: FieldDatasource) { + async getDefinition( + datasource: FieldDatasource + ): Promise { // Field sources have their schema statically defined - let schema: Record | undefined + let schema if (datasource.fieldType === "attachment") { schema = { url: { diff --git a/packages/frontend-core/src/fetch/JSONArrayFetch.js b/packages/frontend-core/src/fetch/JSONArrayFetch.ts similarity index 63% rename from packages/frontend-core/src/fetch/JSONArrayFetch.js rename to packages/frontend-core/src/fetch/JSONArrayFetch.ts index f7de74a4b8..a254bc3ae4 100644 --- a/packages/frontend-core/src/fetch/JSONArrayFetch.js +++ b/packages/frontend-core/src/fetch/JSONArrayFetch.ts @@ -1,13 +1,16 @@ -import FieldFetch from "./FieldFetch" +import FieldFetch, { FieldDatasource } from "./FieldFetch" import { getJSONArrayDatasourceSchema } from "../utils/json" export default class JSONArrayFetch extends FieldFetch { - async getDefinition(datasource) { + async getDefinition(datasource: FieldDatasource) { // JSON arrays need their table definitions fetched. // We can then extract their schema as a subset of the table schema. try { const table = await this.API.fetchTableDefinition(datasource.tableId) - const schema = getJSONArrayDatasourceSchema(table?.schema, datasource) + const schema: Record | null = getJSONArrayDatasourceSchema( + table?.schema, + datasource + ) return { schema } } catch (error) { return null diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index fc029324ba..3976adc3d9 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -5,7 +5,7 @@ import QueryFetch from "./QueryFetch" import RelationshipFetch from "./RelationshipFetch" import NestedProviderFetch from "./NestedProviderFetch.js" import FieldFetch from "./FieldFetch" -import JSONArrayFetch from "./JSONArrayFetch.js" +import JSONArrayFetch from "./JSONArrayFetch" import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch" import CustomFetch from "./CustomFetch.js" From 690a442e61106ad250cd7838772ec6072f229722 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 13:08:17 +0100 Subject: [PATCH 087/173] convert QueryArrayFetch --- .../fetch/{QueryArrayFetch.js => QueryArrayFetch.ts} | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) rename packages/frontend-core/src/fetch/{QueryArrayFetch.js => QueryArrayFetch.ts} (68%) diff --git a/packages/frontend-core/src/fetch/QueryArrayFetch.js b/packages/frontend-core/src/fetch/QueryArrayFetch.ts similarity index 68% rename from packages/frontend-core/src/fetch/QueryArrayFetch.js rename to packages/frontend-core/src/fetch/QueryArrayFetch.ts index 222697b78f..15f86ae7fc 100644 --- a/packages/frontend-core/src/fetch/QueryArrayFetch.js +++ b/packages/frontend-core/src/fetch/QueryArrayFetch.ts @@ -1,11 +1,11 @@ -import FieldFetch from "./FieldFetch" +import FieldFetch, { FieldDatasource } from "./FieldFetch" import { getJSONArrayDatasourceSchema, generateQueryArraySchemas, } from "../utils/json" export default class QueryArrayFetch extends FieldFetch { - async getDefinition(datasource) { + async getDefinition(datasource: FieldDatasource) { if (!datasource?.tableId) { return null } @@ -17,7 +17,11 @@ export default class QueryArrayFetch extends FieldFetch { table?.schema, table?.nestedSchemaFields ) - return { schema: getJSONArrayDatasourceSchema(schema, datasource) } + const result: { + schema: Record | null + } = { schema: getJSONArrayDatasourceSchema(schema, datasource) } + + return result } catch (error) { return null } From f76ec8d2c9602960e84fe8858dcfa5156c3595c1 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 13:32:44 +0100 Subject: [PATCH 088/173] Fix types --- packages/server/src/threads/definitions.ts | 5 ++++- packages/types/src/documents/app/query.ts | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/server/src/threads/definitions.ts b/packages/server/src/threads/definitions.ts index 85e546280d..44a76a60a3 100644 --- a/packages/server/src/threads/definitions.ts +++ b/packages/server/src/threads/definitions.ts @@ -3,7 +3,10 @@ import { Datasource, Row, Query } from "@budibase/types" export type WorkerCallback = (error: any, response?: any) => void export interface QueryEvent - extends Omit { + extends Omit< + Query, + "datasourceId" | "name" | "parameters" | "readable" | "nestedSchemaFields" + > { appId?: string datasource: Datasource pagination?: any diff --git a/packages/types/src/documents/app/query.ts b/packages/types/src/documents/app/query.ts index 43e7563b31..477a7787b9 100644 --- a/packages/types/src/documents/app/query.ts +++ b/packages/types/src/documents/app/query.ts @@ -14,6 +14,7 @@ export interface Query extends Document { fields: RestQueryFields | any transformer: string | null schema: Record + nestedSchemaFields: Record> readable: boolean queryVerb: string // flag to state whether the default bindings are empty strings (old behaviour) or null From 91300c54e903bf4f925a778011bb756092873286 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 13:34:42 +0100 Subject: [PATCH 089/173] Type nestedProvider --- packages/client/src/utils/schema.js | 2 +- .../{NestedProviderFetch.js => NestedProviderFetch.ts} | 8 ++++++-- packages/frontend-core/src/fetch/index.ts | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) rename packages/frontend-core/src/fetch/{NestedProviderFetch.js => NestedProviderFetch.ts} (69%) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index f9cd7dbc60..ffab142cf3 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -3,7 +3,7 @@ import TableFetch from "@budibase/frontend-core/src/fetch/TableFetch" import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch" import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch" import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch" -import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch.js" +import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch" import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch" import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch" import ViewV2Fetch from "@budibase/frontend-core/src/fetch/ViewV2Fetch" diff --git a/packages/frontend-core/src/fetch/NestedProviderFetch.js b/packages/frontend-core/src/fetch/NestedProviderFetch.ts similarity index 69% rename from packages/frontend-core/src/fetch/NestedProviderFetch.js rename to packages/frontend-core/src/fetch/NestedProviderFetch.ts index 06c74cb6c4..a442e7ec07 100644 --- a/packages/frontend-core/src/fetch/NestedProviderFetch.js +++ b/packages/frontend-core/src/fetch/NestedProviderFetch.ts @@ -1,7 +1,11 @@ import DataFetch from "./DataFetch" -export default class NestedProviderFetch extends DataFetch { - async getDefinition(datasource) { +export default class NestedProviderFetch extends DataFetch { + getSchema(_datasource: any, definition: any) { + return definition?.schema + } + + async getDefinition(datasource: any) { // Nested providers should already have exposed their own schema return { schema: datasource?.value?.schema, diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 3976adc3d9..dd03e715ed 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -3,7 +3,7 @@ import ViewFetch from "./ViewFetch.js" import ViewV2Fetch from "./ViewV2Fetch.js" import QueryFetch from "./QueryFetch" import RelationshipFetch from "./RelationshipFetch" -import NestedProviderFetch from "./NestedProviderFetch.js" +import NestedProviderFetch from "./NestedProviderFetch" import FieldFetch from "./FieldFetch" import JSONArrayFetch from "./JSONArrayFetch" import UserFetch from "./UserFetch.js" From bf02515ff0c546440ce9a9c16e0f5e7cfe304459 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 13:42:51 +0100 Subject: [PATCH 090/173] Fix types --- .../frontend-core/src/components/grid/stores/rows.ts | 7 ++++--- packages/frontend-core/src/fetch/DataFetch.ts | 11 +++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/rows.ts b/packages/frontend-core/src/components/grid/stores/rows.ts index d6b80df885..b9c9b3fe1e 100644 --- a/packages/frontend-core/src/components/grid/stores/rows.ts +++ b/packages/frontend-core/src/components/grid/stores/rows.ts @@ -10,9 +10,10 @@ import { import { tick } from "svelte" import { Helpers } from "@budibase/bbui" import { sleep } from "../../../utils/utils" -import { FieldType, Row, UIFetchAPI, UIRow } from "@budibase/types" +import { FieldType, Row, UIRow } from "@budibase/types" import { getRelatedTableValues } from "../../../utils" import { Store as StoreContext } from "." +import DataFetch from "../../../fetch/DataFetch" interface IndexedUIRow extends UIRow { __idx: number @@ -20,7 +21,7 @@ interface IndexedUIRow extends UIRow { interface RowStore { rows: Writable - fetch: Writable + fetch: Writable | null> loaded: Writable refreshing: Writable loading: Writable @@ -225,7 +226,7 @@ export const createActions = (context: StoreContext): RowActionStore => { }) // Subscribe to changes of this fetch model - unsubscribe = newFetch.subscribe(async ($fetch: UIFetchAPI) => { + unsubscribe = newFetch.subscribe(async $fetch => { if ($fetch.error) { // Present a helpful error to the user let message = "An unknown error occurred" diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 60cb96cf8c..68cff15040 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -26,8 +26,11 @@ interface DataFetchStore { pageNumber: number cursor: null cursors: any[] - resetKey: number - error: null + resetKey: string + error: { + message: string + status: number + } | null definition?: TDefinition | null } @@ -132,7 +135,7 @@ export default abstract class DataFetch< pageNumber: 0, cursor: null, cursors: [], - resetKey: Math.random(), + resetKey: Math.random().toString(), error: null, }) @@ -284,7 +287,7 @@ export default abstract class DataFetch< info: page.info, cursors: paginate && page.hasNextPage ? [null, page.cursor] : [null], error: page.error, - resetKey: Math.random(), + resetKey: Math.random().toString(), })) } From 30cf6ff2ad2332cca6d54a9375c1ebcf6b842ef4 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 13:46:00 +0100 Subject: [PATCH 091/173] Type customFetch --- .../fetch/{CustomFetch.js => CustomFetch.ts} | 22 +++++++++++-------- packages/frontend-core/src/fetch/index.ts | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) rename packages/frontend-core/src/fetch/{CustomFetch.js => CustomFetch.ts} (89%) diff --git a/packages/frontend-core/src/fetch/CustomFetch.js b/packages/frontend-core/src/fetch/CustomFetch.ts similarity index 89% rename from packages/frontend-core/src/fetch/CustomFetch.js rename to packages/frontend-core/src/fetch/CustomFetch.ts index 39d3bd6f4c..64739ad6f1 100644 --- a/packages/frontend-core/src/fetch/CustomFetch.js +++ b/packages/frontend-core/src/fetch/CustomFetch.ts @@ -1,8 +1,12 @@ import DataFetch from "./DataFetch" -export default class CustomFetch extends DataFetch { +export default class CustomFetch extends DataFetch { + getSchema(_datasource: any, definition: any) { + return definition?.schema + } + // Gets the correct Budibase type for a JS value - getType(value) { + getType(value: any) { if (value == null) { return "string" } @@ -22,7 +26,7 @@ export default class CustomFetch extends DataFetch { } // Parses the custom data into an array format - parseCustomData(data) { + parseCustomData(data: any) { if (!data) { return [] } @@ -55,7 +59,7 @@ export default class CustomFetch extends DataFetch { } // Enriches the custom data to ensure the structure and format is usable - enrichCustomData(data) { + enrichCustomData(data: any[]) { if (!data?.length) { return [] } @@ -72,7 +76,7 @@ export default class CustomFetch extends DataFetch { // Try parsing strings if (typeof value === "string") { const split = value.split(",").map(x => x.trim()) - let obj = {} + let obj: Record = {} for (let i = 0; i < split.length; i++) { const suffix = i === 0 ? "" : ` ${i + 1}` const key = `Value${suffix}` @@ -87,13 +91,13 @@ export default class CustomFetch extends DataFetch { } // Extracts and parses the custom data from the datasource definition - getCustomData(datasource) { + getCustomData(datasource: { data: any }) { return this.enrichCustomData(this.parseCustomData(datasource?.data)) } - async getDefinition(datasource) { + async getDefinition(datasource: any) { // Try and work out the schema from the array provided - let schema = {} + let schema: any = {} const data = this.getCustomData(datasource) if (!data?.length) { return { schema } @@ -107,7 +111,7 @@ export default class CustomFetch extends DataFetch { } if (!schema[key]) { let type = this.getType(datum[key]) - let constraints = {} + let constraints: any = {} // Determine whether we should render text columns as options instead if (type === "string") { diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index dd03e715ed..3afeec7684 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -8,7 +8,7 @@ import FieldFetch from "./FieldFetch" import JSONArrayFetch from "./JSONArrayFetch" import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch" -import CustomFetch from "./CustomFetch.js" +import CustomFetch from "./CustomFetch" import QueryArrayFetch from "./QueryArrayFetch.js" import { Table, UIDatasource } from "@budibase/types" import { APIClient } from "../api/types.js" From 090429fc56b242f931b61275377ad77e09ed7e0b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 14:01:55 +0100 Subject: [PATCH 092/173] Fix sort order enum type --- packages/frontend-core/src/fetch/DataFetch.ts | 5 +++++ packages/frontend-core/src/fetch/TableFetch.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 68cff15040..0dcda4e150 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -253,9 +253,14 @@ export default abstract class DataFetch< ) { this.options.sortType = SortType.NUMBER } + // If no sort order, default to ascending if (!this.options.sortOrder) { this.options.sortOrder = SortOrder.ASCENDING + } else { + // Ensure sortOrder matches the enum + this.options.sortOrder = + this.options.sortOrder.toLowerCase() as SortOrder } } diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 344ce30e54..58ad554d6a 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -42,7 +42,7 @@ export default class TableFetch extends DataFetch { query: query ?? undefined, limit, sort: sortColumn, - sortOrder: sortOrder?.toLowerCase() ?? SortOrder.ASCENDING, + sortOrder: sortOrder ?? SortOrder.ASCENDING, sortType, paginate, bookmark: cursor, From dcf52b5dc96670ad0cfc31750f059110cf42b231 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 15:33:05 +0100 Subject: [PATCH 093/173] Fix typings --- packages/frontend-core/src/components/grid/stores/config.ts | 2 +- .../frontend-core/src/components/grid/stores/datasource.ts | 6 +++--- packages/frontend-core/src/fetch/index.ts | 4 ++-- packages/types/src/ui/stores/grid/view.ts | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/config.ts b/packages/frontend-core/src/components/grid/stores/config.ts index e334b58495..2ddaf1b65c 100644 --- a/packages/frontend-core/src/components/grid/stores/config.ts +++ b/packages/frontend-core/src/components/grid/stores/config.ts @@ -69,7 +69,7 @@ export const deriveStores = (context: StoreContext): ConfigDerivedStore => { } // Disable features for non DS+ - if (!["table", "viewV2"].includes(type)) { + if (type && !["table", "viewV2"].includes(type)) { config.canAddRows = false config.canEditRows = false config.canDeleteRows = false diff --git a/packages/frontend-core/src/components/grid/stores/datasource.ts b/packages/frontend-core/src/components/grid/stores/datasource.ts index 74101701ed..fe8ff60fd3 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.ts +++ b/packages/frontend-core/src/components/grid/stores/datasource.ts @@ -74,7 +74,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { let schema: Record = getDatasourceSchema({ API, datasource: get(datasource), - definition: $definition, + definition: $definition ?? undefined, }) if (!schema) { return null @@ -136,7 +136,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { if (type === "viewV2" && $definition?.type === ViewV2Type.CALCULATION) { return false } - return ["table", "viewV2", "link"].includes(type) + return !!type && ["table", "viewV2", "link"].includes(type) } ) @@ -186,7 +186,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { API, datasource: get(datasource), }) - definition.set(def) + definition.set((def as any) ?? null) } // Saves the datasource definition diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 3afeec7684..4f4eafe8e8 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -10,7 +10,7 @@ import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch" import CustomFetch from "./CustomFetch" import QueryArrayFetch from "./QueryArrayFetch.js" -import { Table, UIDatasource } from "@budibase/types" +import { TableSchema, UIDatasource } from "@budibase/types" import { APIClient } from "../api/types.js" const DataFetchMap = { @@ -73,7 +73,7 @@ export const getDatasourceSchema = ({ }: { API: APIClient datasource: UIDatasource - definition: Table + definition?: { schema?: TableSchema } }) => { const instance = createEmptyFetchInstance({ API, datasource }) return instance?.getSchema(datasource, definition) diff --git a/packages/types/src/ui/stores/grid/view.ts b/packages/types/src/ui/stores/grid/view.ts index 270faaa160..f81cc34aaf 100644 --- a/packages/types/src/ui/stores/grid/view.ts +++ b/packages/types/src/ui/stores/grid/view.ts @@ -1,7 +1,6 @@ import { ViewV2 } from "@budibase/types" import { UIFieldSchema } from "./table" -export interface UIView extends Omit { - type: string +export interface UIView extends ViewV2 { schema: Record } From ed2e35dea06285cdf7677418cb676a3add90189f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 7 Jan 2025 16:02:34 +0100 Subject: [PATCH 094/173] Dry --- .../src/components/grid/stores/datasource.ts | 4 ++-- packages/frontend-core/src/fetch/CustomFetch.ts | 4 ---- packages/frontend-core/src/fetch/DataFetch.ts | 12 +++++++----- packages/frontend-core/src/fetch/FieldFetch.ts | 9 +-------- packages/frontend-core/src/fetch/GroupUserFetch.ts | 4 ---- .../frontend-core/src/fetch/NestedProviderFetch.ts | 4 ---- packages/frontend-core/src/fetch/QueryFetch.ts | 4 ---- .../frontend-core/src/fetch/RelationshipFetch.ts | 4 ---- packages/frontend-core/src/fetch/TableFetch.ts | 4 ---- packages/frontend-core/src/fetch/UserFetch.ts | 4 ---- packages/frontend-core/src/fetch/ViewV2Fetch.ts | 4 ---- 11 files changed, 10 insertions(+), 47 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasource.ts b/packages/frontend-core/src/components/grid/stores/datasource.ts index fe8ff60fd3..4c20e9493f 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.ts +++ b/packages/frontend-core/src/components/grid/stores/datasource.ts @@ -71,7 +71,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { } = context const schema = derived(definition, $definition => { - let schema: Record = getDatasourceSchema({ + const schema: Record | null | undefined = getDatasourceSchema({ API, datasource: get(datasource), definition: $definition ?? undefined, @@ -82,7 +82,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { // Ensure schema is configured as objects. // Certain datasources like queries use primitives. - Object.keys(schema || {}).forEach(key => { + Object.keys(schema).forEach(key => { if (typeof schema[key] !== "object") { schema[key] = { name: key, type: schema[key] } } diff --git a/packages/frontend-core/src/fetch/CustomFetch.ts b/packages/frontend-core/src/fetch/CustomFetch.ts index 64739ad6f1..9db9a935a5 100644 --- a/packages/frontend-core/src/fetch/CustomFetch.ts +++ b/packages/frontend-core/src/fetch/CustomFetch.ts @@ -1,10 +1,6 @@ import DataFetch from "./DataFetch" export default class CustomFetch extends DataFetch { - getSchema(_datasource: any, definition: any) { - return definition?.schema - } - // Gets the correct Budibase type for a JS value getType(value: any) { if (value == null) { diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 0dcda4e150..f34f6ddeb7 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -60,7 +60,10 @@ export interface DataFetchParams< */ export default abstract class DataFetch< TDatasource extends {}, - TDefinition extends {}, + TDefinition extends { + schema?: Record | null + primaryDisplay?: string + }, TQuery extends {} = SearchFilters > { API: APIClient @@ -361,10 +364,9 @@ export default abstract class DataFetch< * @param definition the datasource definition * @return {object} the schema */ - abstract getSchema( - datasource: TDatasource | null, - definition: TDefinition | null - ): any + getSchema(_datasource: TDatasource | null, definition: TDefinition | null) { + return definition?.schema + } /** * Enriches a datasource schema with nested fields and ensures the structure diff --git a/packages/frontend-core/src/fetch/FieldFetch.ts b/packages/frontend-core/src/fetch/FieldFetch.ts index 6809dee00e..636fb63f3d 100644 --- a/packages/frontend-core/src/fetch/FieldFetch.ts +++ b/packages/frontend-core/src/fetch/FieldFetch.ts @@ -1,4 +1,4 @@ -import { Row, TableSchema } from "@budibase/types" +import { Row } from "@budibase/types" import DataFetch from "./DataFetch" export interface FieldDatasource { @@ -19,13 +19,6 @@ export default class FieldFetch extends DataFetch< FieldDatasource, FieldDefinition > { - getSchema( - _datasource: FieldDatasource, - definition: { schema?: TableSchema } - ) { - return definition?.schema - } - async getDefinition( datasource: FieldDatasource ): Promise { diff --git a/packages/frontend-core/src/fetch/GroupUserFetch.ts b/packages/frontend-core/src/fetch/GroupUserFetch.ts index 77b5e1de43..0c5ac7486d 100644 --- a/packages/frontend-core/src/fetch/GroupUserFetch.ts +++ b/packages/frontend-core/src/fetch/GroupUserFetch.ts @@ -26,10 +26,6 @@ export default class GroupUserFetch extends DataFetch< }) } - getSchema(_datasource: any, definition: any) { - return definition?.schema - } - determineFeatureFlags() { return { supportsSearch: true, diff --git a/packages/frontend-core/src/fetch/NestedProviderFetch.ts b/packages/frontend-core/src/fetch/NestedProviderFetch.ts index a442e7ec07..71eb5177db 100644 --- a/packages/frontend-core/src/fetch/NestedProviderFetch.ts +++ b/packages/frontend-core/src/fetch/NestedProviderFetch.ts @@ -1,10 +1,6 @@ import DataFetch from "./DataFetch" export default class NestedProviderFetch extends DataFetch { - getSchema(_datasource: any, definition: any) { - return definition?.schema - } - async getDefinition(datasource: any) { // Nested providers should already have exposed their own schema return { diff --git a/packages/frontend-core/src/fetch/QueryFetch.ts b/packages/frontend-core/src/fetch/QueryFetch.ts index d85b5ffbcd..dec7cd2183 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.ts +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -11,10 +11,6 @@ interface QueryDatasource { } export default class QueryFetch extends DataFetch { - getSchema(_datasource: any, definition: any) { - return definition?.schema - } - determineFeatureFlags(definition: Query) { const supportsPagination = !!definition?.fields?.pagination?.type && diff --git a/packages/frontend-core/src/fetch/RelationshipFetch.ts b/packages/frontend-core/src/fetch/RelationshipFetch.ts index ab50285b4b..7b6e93fbcc 100644 --- a/packages/frontend-core/src/fetch/RelationshipFetch.ts +++ b/packages/frontend-core/src/fetch/RelationshipFetch.ts @@ -12,10 +12,6 @@ export default class RelationshipFetch extends DataFetch< RelationshipDatasource, Table > { - getSchema(_datasource: any, definition: any) { - return definition?.schema - } - async getDefinition(datasource: RelationshipDatasource) { if (!datasource?.tableId) { return null diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 58ad554d6a..48a3413716 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -26,10 +26,6 @@ export default class TableFetch extends DataFetch { } } - getSchema(_datasource: UITable | null, definition: Table | null) { - return definition?.schema - } - async getData() { const { datasource, limit, sortColumn, sortOrder, sortType, paginate } = this.options diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index e276af3592..43efc7767f 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -48,10 +48,6 @@ export default class UserFetch extends DataFetch< } } - getSchema(_datasource: any, definition: Table | null) { - return definition?.schema - } - async getData() { const { limit, paginate } = this.options const { cursor, query } = get(this.store) diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 7973dbf298..d541a692b6 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -12,10 +12,6 @@ export default class ViewV2Fetch extends DataFetch { } } - getSchema(_datasource: UIView, definition: ViewV2) { - return definition?.schema - } - async getDefinition(datasource: UIView | null): Promise { if (!datasource?.id) { return null From a1ac0ac0b08c8595b78d031ca9299722fe1ef5a9 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 12:22:17 +0100 Subject: [PATCH 095/173] Fix type --- packages/types/src/documents/app/query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/documents/app/query.ts b/packages/types/src/documents/app/query.ts index 477a7787b9..d287a5b2c3 100644 --- a/packages/types/src/documents/app/query.ts +++ b/packages/types/src/documents/app/query.ts @@ -14,7 +14,7 @@ export interface Query extends Document { fields: RestQueryFields | any transformer: string | null schema: Record - nestedSchemaFields: Record> + nestedSchemaFields?: Record> readable: boolean queryVerb: string // flag to state whether the default bindings are empty strings (old behaviour) or null From 022df7cda41710e276f98aa12a1bfd240c8b1dba Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 12:28:36 +0100 Subject: [PATCH 096/173] Lint --- packages/frontend-core/src/fetch/ViewFetch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/ViewFetch.ts b/packages/frontend-core/src/fetch/ViewFetch.ts index cbdd1d425b..fe891b9e66 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.ts +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -34,7 +34,7 @@ export default class ViewFetch extends DataFetch { }) return { rows: res || [] } } catch (error) { - console.error(error) + console.error(error, { datasource }) return { rows: [] } } } From d465f7e0574297e8bb01a41b6cd757986fc82a41 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 12:42:33 +0100 Subject: [PATCH 097/173] Type anys --- packages/frontend-core/src/api/views.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/frontend-core/src/api/views.ts b/packages/frontend-core/src/api/views.ts index 083a3890e8..83f7e97df0 100644 --- a/packages/frontend-core/src/api/views.ts +++ b/packages/frontend-core/src/api/views.ts @@ -3,7 +3,15 @@ import { BaseAPIClient } from "./types" export interface ViewEndpoints { // Missing request or response types - fetchViewData: (name: string, opts?: any) => Promise + fetchViewData: ( + name: string, + opts: { + calculation?: string + field?: string + groupBy?: string + tableId: string + } + ) => Promise exportView: (name: string, format: string) => Promise saveView: (view: any) => Promise deleteView: (name: string) => Promise @@ -20,7 +28,7 @@ export const buildViewEndpoints = (API: BaseAPIClient): ViewEndpoints => ({ fetchViewData: async (name, { field, groupBy, calculation }) => { const params = new URLSearchParams() if (calculation) { - params.set("field", field) + params.set("field", field!) params.set("calculation", calculation) } if (groupBy) { From 7d7c27fa928640d075ce9233932b2761e6d740d7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 12:49:17 +0100 Subject: [PATCH 098/173] Simplify determineFeatureFlags --- packages/frontend-core/src/fetch/DataFetch.ts | 9 ++++----- packages/frontend-core/src/fetch/GroupUserFetch.ts | 2 +- packages/frontend-core/src/fetch/QueryFetch.ts | 3 ++- packages/frontend-core/src/fetch/TableFetch.ts | 2 +- packages/frontend-core/src/fetch/UserFetch.ts | 2 +- packages/frontend-core/src/fetch/ViewV2Fetch.ts | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index f34f6ddeb7..a7ed7237ba 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -216,7 +216,7 @@ export default abstract class DataFetch< const definition = await this.getDefinition(datasource) // Determine feature flags - const features = this.determineFeatureFlags(definition) + const features = await this.determineFeatureFlags() this.features = { supportsSearch: !!features?.supportsSearch, supportsSort: !!features?.supportsSort, @@ -421,14 +421,13 @@ export default abstract class DataFetch< } /** - * Determine the feature flag for this datasource definition - * @param definition + * Determine the feature flag for this datasource */ - determineFeatureFlags(_definition: TDefinition | null): { + async determineFeatureFlags(): Promise<{ supportsPagination: boolean supportsSearch?: boolean supportsSort?: boolean - } { + }> { return { supportsSearch: false, supportsSort: false, diff --git a/packages/frontend-core/src/fetch/GroupUserFetch.ts b/packages/frontend-core/src/fetch/GroupUserFetch.ts index 0c5ac7486d..2f5cacd1a2 100644 --- a/packages/frontend-core/src/fetch/GroupUserFetch.ts +++ b/packages/frontend-core/src/fetch/GroupUserFetch.ts @@ -26,7 +26,7 @@ export default class GroupUserFetch extends DataFetch< }) } - determineFeatureFlags() { + async determineFeatureFlags() { return { supportsSearch: true, supportsSort: false, diff --git a/packages/frontend-core/src/fetch/QueryFetch.ts b/packages/frontend-core/src/fetch/QueryFetch.ts index dec7cd2183..a6ddcd8f01 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.ts +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -11,7 +11,8 @@ interface QueryDatasource { } export default class QueryFetch extends DataFetch { - determineFeatureFlags(definition: Query) { + async determineFeatureFlags() { + const definition = await this.getDefinition(this.options.datasource) const supportsPagination = !!definition?.fields?.pagination?.type && !!definition?.fields?.pagination?.location && diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 48a3413716..433de69b59 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -3,7 +3,7 @@ import DataFetch from "./DataFetch" import { SortOrder, Table, UITable } from "@budibase/types" export default class TableFetch extends DataFetch { - determineFeatureFlags() { + async determineFeatureFlags() { return { supportsSearch: true, supportsSort: true, diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 43efc7767f..199dacde00 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -34,7 +34,7 @@ export default class UserFetch extends DataFetch< }) } - determineFeatureFlags() { + async determineFeatureFlags() { return { supportsSearch: true, supportsSort: false, diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index d541a692b6..74ad08f2f4 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -4,7 +4,7 @@ import { get } from "svelte/store" import { helpers } from "@budibase/shared-core" export default class ViewV2Fetch extends DataFetch { - determineFeatureFlags() { + async determineFeatureFlags() { return { supportsSearch: true, supportsSort: true, From f053438a649694233f7849e94df0bdd22ab60859 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 12:55:26 +0100 Subject: [PATCH 099/173] Clean classes --- packages/frontend-core/src/fetch/DataFetch.ts | 18 +++++++----------- .../frontend-core/src/fetch/ViewV2Fetch.ts | 5 +---- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index a7ed7237ba..3e2b0d7dcf 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -223,13 +223,13 @@ export default abstract class DataFetch< supportsPagination: paginate && !!features?.supportsPagination, } - // Fetch and enrich schema - let schema = this.getSchema(datasource, definition) ?? null - schema = this.enrichSchema(schema) - if (!schema) { + if (!definition?.schema) { return } + // Fetch and enrich schema + const schema = this.enrichSchema(definition.schema) + // If an invalid sort column is specified, delete it if (this.options.sortColumn && !schema[this.options.sortColumn]) { this.options.sortColumn = null @@ -374,11 +374,7 @@ export default abstract class DataFetch< * @param schema the datasource schema * @return {object} the enriched datasource schema */ - enrichSchema(schema: TableSchema | null): TableSchema | null { - if (schema == null) { - return null - } - + private enrichSchema(schema: TableSchema): TableSchema { // Check for any JSON fields so we can add any top level properties let jsonAdditions: Record = {} for (const fieldKey of Object.keys(schema)) { @@ -510,7 +506,7 @@ export default abstract class DataFetch< * @param state the current store state * @return {boolean} whether there is a next page of data or not */ - hasNextPage(state: DataFetchStore): boolean { + private hasNextPage(state: DataFetchStore): boolean { return state.cursors[state.pageNumber + 1] != null } @@ -520,7 +516,7 @@ export default abstract class DataFetch< * @param state the current store state * @return {boolean} whether there is a previous page of data or not */ - hasPrevPage(state: { pageNumber: number }): boolean { + private hasPrevPage(state: { pageNumber: number }): boolean { return state.pageNumber > 0 } diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 74ad08f2f4..197b5b4ae5 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -28,10 +28,7 @@ export default class ViewV2Fetch extends DataFetch { } } - getDefaultSortColumn( - _definition: { primaryDisplay?: string } | null, - _schema: Record - ) { + getDefaultSortColumn() { return null } From 5d63fe251f050e406692b3e302e8be7abcb58cbb Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 12:57:25 +0100 Subject: [PATCH 100/173] Simplify --- packages/frontend-core/src/fetch/DataFetch.ts | 5 ++--- packages/frontend-core/src/fetch/ViewFetch.ts | 3 ++- packages/frontend-core/src/fetch/index.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 3e2b0d7dcf..b5eb774e45 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -360,12 +360,11 @@ export default abstract class DataFetch< /** * Gets the schema definition for a datasource. - * @param datasource the datasource * @param definition the datasource definition * @return {object} the schema */ - getSchema(_datasource: TDatasource | null, definition: TDefinition | null) { - return definition?.schema + getSchema(definition: TDefinition | null): Record | undefined { + return definition?.schema ?? undefined } /** diff --git a/packages/frontend-core/src/fetch/ViewFetch.ts b/packages/frontend-core/src/fetch/ViewFetch.ts index fe891b9e66..2238d226ab 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.ts +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -19,7 +19,8 @@ export default class ViewFetch extends DataFetch { } } - getSchema(datasource: ViewV1, definition: Table) { + getSchema(definition: Table) { + const { datasource } = this.options return definition?.views?.[datasource.name]?.schema } diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 4f4eafe8e8..52233bd3fb 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -76,5 +76,5 @@ export const getDatasourceSchema = ({ definition?: { schema?: TableSchema } }) => { const instance = createEmptyFetchInstance({ API, datasource }) - return instance?.getSchema(datasource, definition) + return instance?.getSchema(definition) } From 3741b7144e8b635ce11578fdf597c8f1e758a786 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 13:05:27 +0100 Subject: [PATCH 101/173] Clean code --- packages/frontend-core/src/fetch/UserFetch.ts | 7 ++----- packages/frontend-core/src/fetch/ViewV2Fetch.ts | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 199dacde00..b865c32d63 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -23,7 +23,6 @@ export default class UserFetch extends DataFetch< constructor(opts: { API: APIClient datasource: Table - options?: {} query: UserFetchQuery }) { super({ @@ -43,9 +42,7 @@ export default class UserFetch extends DataFetch< } async getDefinition() { - return { - schema: {}, - } + return { schema: {} } } async getData() { @@ -53,7 +50,7 @@ export default class UserFetch extends DataFetch< const { cursor, query } = get(this.store) // Convert old format to new one - we now allow use of the lucene format - const { appId, paginated, ...rest } = query || {} + const { appId, paginated, ...rest } = query const finalQuery: SearchFilters = utils.isSupportedUserSearch(rest) ? rest diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 197b5b4ae5..3bb04d5bc4 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -62,7 +62,7 @@ export default class ViewV2Fetch extends DataFetch { try { const request = { - ...(query ? { query } : {}), + query, paginate, limit, bookmark: cursor, From 265b22f2b8a93d2f8a00358da206299609baadea Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 13:23:18 +0100 Subject: [PATCH 102/173] Type query --- packages/bbui/src/helpers.d.ts | 1 + packages/frontend-core/src/fetch/QueryFetch.ts | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 packages/bbui/src/helpers.d.ts diff --git a/packages/bbui/src/helpers.d.ts b/packages/bbui/src/helpers.d.ts new file mode 100644 index 0000000000..98c6060590 --- /dev/null +++ b/packages/bbui/src/helpers.d.ts @@ -0,0 +1 @@ +export const cloneDeep: (obj: T) => T diff --git a/packages/frontend-core/src/fetch/QueryFetch.ts b/packages/frontend-core/src/fetch/QueryFetch.ts index a6ddcd8f01..f8506fefec 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.ts +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -5,9 +5,15 @@ import { get } from "svelte/store" interface QueryDatasource { _id: string - fields: any - queryParams: any - parameters: any + fields: Record & { + pagination?: { + type: string + location: string + pageParam: string + } + } + queryParams: Record + parameters: { name: string; default: string }[] } export default class QueryFetch extends DataFetch { @@ -49,8 +55,8 @@ export default class QueryFetch extends DataFetch { const type = definition?.fields?.pagination?.type // Set the default query params - let parameters = Helpers.cloneDeep(datasource?.queryParams || {}) - for (let param of datasource?.parameters || {}) { + const parameters = Helpers.cloneDeep(datasource.queryParams) + for (const param of datasource?.parameters || []) { if (!parameters[param.name]) { parameters[param.name] = param.default } From 0112087af15e5b3a903adee612ca33f08fe1d184 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 13:37:28 +0100 Subject: [PATCH 103/173] Improve typing --- packages/frontend-core/src/fetch/QueryFetch.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/frontend-core/src/fetch/QueryFetch.ts b/packages/frontend-core/src/fetch/QueryFetch.ts index f8506fefec..0825d39660 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.ts +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -1,6 +1,6 @@ import DataFetch from "./DataFetch" import { Helpers } from "@budibase/bbui" -import { Query } from "@budibase/types" +import { ExecuteQueryRequest, Query } from "@budibase/types" import { get } from "svelte/store" interface QueryDatasource { @@ -12,7 +12,7 @@ interface QueryDatasource { pageParam: string } } - queryParams: Record + queryParams?: Record parameters: { name: string; default: string }[] } @@ -55,7 +55,7 @@ export default class QueryFetch extends DataFetch { const type = definition?.fields?.pagination?.type // Set the default query params - const parameters = Helpers.cloneDeep(datasource.queryParams) + const parameters = Helpers.cloneDeep(datasource.queryParams || {}) for (const param of datasource?.parameters || []) { if (!parameters[param.name]) { parameters[param.name] = param.default @@ -63,13 +63,7 @@ export default class QueryFetch extends DataFetch { } // Add pagination to query if supported - const queryPayload: { - parameters: any - pagination?: { - page: number | null - limit: number - } - } = { parameters } + const queryPayload: ExecuteQueryRequest = { parameters } if (paginate && supportsPagination) { const requestCursor = type === "page" ? parseInt(cursor || "1") : cursor queryPayload.pagination = { page: requestCursor, limit } From af0312e5fe501e1b0f739b1c391877023f388186 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 13:48:45 +0100 Subject: [PATCH 104/173] Proper type QueryArrayFetch --- packages/frontend-core/src/fetch/QueryArrayFetch.ts | 10 +++++----- packages/frontend-core/src/utils/json.d.ts | 13 +++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 packages/frontend-core/src/utils/json.d.ts diff --git a/packages/frontend-core/src/fetch/QueryArrayFetch.ts b/packages/frontend-core/src/fetch/QueryArrayFetch.ts index 15f86ae7fc..ce9177e554 100644 --- a/packages/frontend-core/src/fetch/QueryArrayFetch.ts +++ b/packages/frontend-core/src/fetch/QueryArrayFetch.ts @@ -14,12 +14,12 @@ export default class QueryArrayFetch extends FieldFetch { try { const table = await this.API.fetchQueryDefinition(datasource.tableId) const schema = generateQueryArraySchemas( - table?.schema, - table?.nestedSchemaFields + table.schema, + table.nestedSchemaFields ) - const result: { - schema: Record | null - } = { schema: getJSONArrayDatasourceSchema(schema, datasource) } + const result = { + schema: getJSONArrayDatasourceSchema(schema, datasource), + } return result } catch (error) { diff --git a/packages/frontend-core/src/utils/json.d.ts b/packages/frontend-core/src/utils/json.d.ts new file mode 100644 index 0000000000..ebda694c15 --- /dev/null +++ b/packages/frontend-core/src/utils/json.d.ts @@ -0,0 +1,13 @@ +import { QuerySchema } from "@budibase/types" + +type Schema = Record + +export const getJSONArrayDatasourceSchema: ( + tableSchema: Schema, + datasource: any +) => Record + +export const generateQueryArraySchemas: ( + schema: Schema, + nestedSchemaFields?: Record +) => Schema From fc4336a9f30d52197f1ff40304be455bf346e8f4 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 13:54:21 +0100 Subject: [PATCH 105/173] Add typings --- packages/frontend-core/src/utils/json.d.ts | 10 +++++++++- packages/types/src/documents/app/table/schema.ts | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/frontend-core/src/utils/json.d.ts b/packages/frontend-core/src/utils/json.d.ts index ebda694c15..4f26f4b264 100644 --- a/packages/frontend-core/src/utils/json.d.ts +++ b/packages/frontend-core/src/utils/json.d.ts @@ -1,4 +1,4 @@ -import { QuerySchema } from "@budibase/types" +import { JsonFieldMetadata, QuerySchema } from "@budibase/types" type Schema = Record @@ -11,3 +11,11 @@ export const generateQueryArraySchemas: ( schema: Schema, nestedSchemaFields?: Record ) => Schema + +export const convertJSONSchemaToTableSchema: ( + jsonSchema: JsonFieldMetadata, + options: { + squashObjects?: boolean + prefixKeys?: string + } +) => Record diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index 771192e2f5..58af430f7e 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -227,6 +227,7 @@ interface OtherFieldMetadata extends BaseFieldSchema { | FieldType.OPTIONS | FieldType.BOOLEAN | FieldType.BIGINT + | FieldType.JSON > } From 88760d473e960668e57537597824652bbd946d31 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 13:54:37 +0100 Subject: [PATCH 106/173] Proper type nestedProvider --- .../src/fetch/NestedProviderFetch.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/frontend-core/src/fetch/NestedProviderFetch.ts b/packages/frontend-core/src/fetch/NestedProviderFetch.ts index 71eb5177db..4bcdd697a2 100644 --- a/packages/frontend-core/src/fetch/NestedProviderFetch.ts +++ b/packages/frontend-core/src/fetch/NestedProviderFetch.ts @@ -1,7 +1,23 @@ +import { Row, TableSchema } from "@budibase/types" import DataFetch from "./DataFetch" -export default class NestedProviderFetch extends DataFetch { - async getDefinition(datasource: any) { +interface NestedProviderDatasource { + value?: { + schema: TableSchema + primaryDisplay: string + rows: Row[] + } +} + +interface NestedProviderDefinition { + schema?: TableSchema + primaryDisplay?: string +} +export default class NestedProviderFetch extends DataFetch< + NestedProviderDatasource, + NestedProviderDefinition +> { + async getDefinition(datasource: NestedProviderDatasource) { // Nested providers should already have exposed their own schema return { schema: datasource?.value?.schema, From fae3c6b3eb76119a88448be10c177b603dbdb85c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 13:58:20 +0100 Subject: [PATCH 107/173] Type GroupUserFetch --- packages/frontend-core/src/constants.ts | 4 ++-- packages/frontend-core/src/fetch/GroupUserFetch.ts | 14 +++++++------- packages/frontend-core/src/fetch/JSONArrayFetch.ts | 5 +---- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/frontend-core/src/constants.ts b/packages/frontend-core/src/constants.ts index 8a39e8c106..907d91825f 100644 --- a/packages/frontend-core/src/constants.ts +++ b/packages/frontend-core/src/constants.ts @@ -32,8 +32,8 @@ export const Cookies = { } // Table names -export const TableNames = { - USERS: "ta_users", +export const enum TableNames { + USERS = "ta_users", } export const BudibaseRoles = { diff --git a/packages/frontend-core/src/fetch/GroupUserFetch.ts b/packages/frontend-core/src/fetch/GroupUserFetch.ts index 2f5cacd1a2..bc7688330a 100644 --- a/packages/frontend-core/src/fetch/GroupUserFetch.ts +++ b/packages/frontend-core/src/fetch/GroupUserFetch.ts @@ -8,16 +8,16 @@ interface GroupUserQuery { emailSearch: string } +interface GroupUserDatasource { + tableId: TableNames.USERS +} + export default class GroupUserFetch extends DataFetch< - any, - any, + GroupUserDatasource, + {}, GroupUserQuery > { - constructor(opts: { - API: APIClient - datasource: any - query: GroupUserQuery - }) { + constructor(opts: { API: APIClient; query: GroupUserQuery }) { super({ ...opts, datasource: { diff --git a/packages/frontend-core/src/fetch/JSONArrayFetch.ts b/packages/frontend-core/src/fetch/JSONArrayFetch.ts index a254bc3ae4..f0cbaa87c5 100644 --- a/packages/frontend-core/src/fetch/JSONArrayFetch.ts +++ b/packages/frontend-core/src/fetch/JSONArrayFetch.ts @@ -7,10 +7,7 @@ export default class JSONArrayFetch extends FieldFetch { // We can then extract their schema as a subset of the table schema. try { const table = await this.API.fetchTableDefinition(datasource.tableId) - const schema: Record | null = getJSONArrayDatasourceSchema( - table?.schema, - datasource - ) + const schema = getJSONArrayDatasourceSchema(table?.schema, datasource) return { schema } } catch (error) { return null From 2fb243a7c7881489590c4b31e768cbc7affb856a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 14:09:05 +0100 Subject: [PATCH 108/173] Fix customFetch --- .../frontend-core/src/fetch/CustomFetch.ts | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/frontend-core/src/fetch/CustomFetch.ts b/packages/frontend-core/src/fetch/CustomFetch.ts index 9db9a935a5..176d878a54 100644 --- a/packages/frontend-core/src/fetch/CustomFetch.ts +++ b/packages/frontend-core/src/fetch/CustomFetch.ts @@ -1,6 +1,15 @@ import DataFetch from "./DataFetch" -export default class CustomFetch extends DataFetch { +interface CustomDatasource { + data: any +} + +type CustomDefinition = Record + +export default class CustomFetch extends DataFetch< + CustomDatasource, + CustomDefinition +> { // Gets the correct Budibase type for a JS value getType(value: any) { if (value == null) { @@ -55,7 +64,7 @@ export default class CustomFetch extends DataFetch { } // Enriches the custom data to ensure the structure and format is usable - enrichCustomData(data: any[]) { + enrichCustomData(data: (string | any)[]) { if (!data?.length) { return [] } @@ -72,7 +81,7 @@ export default class CustomFetch extends DataFetch { // Try parsing strings if (typeof value === "string") { const split = value.split(",").map(x => x.trim()) - let obj: Record = {} + const obj: Record = {} for (let i = 0; i < split.length; i++) { const suffix = i === 0 ? "" : ` ${i + 1}` const key = `Value${suffix}` @@ -87,27 +96,27 @@ export default class CustomFetch extends DataFetch { } // Extracts and parses the custom data from the datasource definition - getCustomData(datasource: { data: any }) { + getCustomData(datasource: CustomDatasource) { return this.enrichCustomData(this.parseCustomData(datasource?.data)) } - async getDefinition(datasource: any) { + async getDefinition(datasource: CustomDatasource) { // Try and work out the schema from the array provided - let schema: any = {} + const schema: CustomDefinition = {} const data = this.getCustomData(datasource) if (!data?.length) { return { schema } } // Go through every object and extract all valid keys - for (let datum of data) { - for (let key of Object.keys(datum)) { + for (const datum of data) { + for (const key of Object.keys(datum)) { if (key === "_id") { continue } if (!schema[key]) { let type = this.getType(datum[key]) - let constraints: any = {} + const constraints: any = {} // Determine whether we should render text columns as options instead if (type === "string") { From 819ca2129e1c9d6f138951314af08ed86ab9b226 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 14:17:10 +0100 Subject: [PATCH 109/173] Clean types --- .../frontend-core/src/fetch/GroupUserFetch.ts | 5 ++--- packages/frontend-core/src/fetch/UserFetch.ts | 16 +++++++--------- packages/frontend-core/src/fetch/ViewV2Fetch.ts | 5 +---- packages/frontend-core/src/fetch/index.ts | 6 +++--- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/packages/frontend-core/src/fetch/GroupUserFetch.ts b/packages/frontend-core/src/fetch/GroupUserFetch.ts index bc7688330a..a14623bfb0 100644 --- a/packages/frontend-core/src/fetch/GroupUserFetch.ts +++ b/packages/frontend-core/src/fetch/GroupUserFetch.ts @@ -1,7 +1,6 @@ import { get } from "svelte/store" -import DataFetch from "./DataFetch" +import DataFetch, { DataFetchParams } from "./DataFetch" import { TableNames } from "../constants" -import { APIClient } from "../api/types" interface GroupUserQuery { groupId: string @@ -17,7 +16,7 @@ export default class GroupUserFetch extends DataFetch< {}, GroupUserQuery > { - constructor(opts: { API: APIClient; query: GroupUserQuery }) { + constructor(opts: DataFetchParams) { super({ ...opts, datasource: { diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index b865c32d63..8f1ef36cac 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -1,30 +1,28 @@ import { get } from "svelte/store" -import DataFetch from "./DataFetch" +import DataFetch, { DataFetchParams } from "./DataFetch" import { TableNames } from "../constants" import { utils } from "@budibase/shared-core" import { BasicOperator, SearchFilters, SearchUsersRequest, - Table, } from "@budibase/types" -import { APIClient } from "../api/types.js" interface UserFetchQuery { appId: string paginated: boolean } +interface UserDatasource { + tableId: string +} + export default class UserFetch extends DataFetch< - { tableId: string }, + UserDatasource, {}, UserFetchQuery > { - constructor(opts: { - API: APIClient - datasource: Table - query: UserFetchQuery - }) { + constructor(opts: DataFetchParams) { super({ ...opts, datasource: { diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 3bb04d5bc4..1be1ba295c 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -12,10 +12,7 @@ export default class ViewV2Fetch extends DataFetch { } } - async getDefinition(datasource: UIView | null): Promise { - if (!datasource?.id) { - return null - } + async getDefinition(datasource: UIView) { try { const res = await this.API.viewV2.fetchDefinition(datasource.id) return res?.data diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 52233bd3fb..1577f76034 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -10,7 +10,7 @@ import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch" import CustomFetch from "./CustomFetch" import QueryArrayFetch from "./QueryArrayFetch.js" -import { TableSchema, UIDatasource } from "@budibase/types" +import { UIDatasource } from "@budibase/types" import { APIClient } from "../api/types.js" const DataFetchMap = { @@ -59,7 +59,7 @@ export const getDatasourceDefinition = async ({ datasource, }: { API: APIClient - datasource: UIDatasource + datasource: any }) => { const instance = createEmptyFetchInstance({ API, datasource }) return await instance?.getDefinition(datasource) @@ -73,7 +73,7 @@ export const getDatasourceSchema = ({ }: { API: APIClient datasource: UIDatasource - definition?: { schema?: TableSchema } + definition?: any }) => { const instance = createEmptyFetchInstance({ API, datasource }) return instance?.getSchema(definition) From b9fb4416bb428acab70288fdc7966454670b738f Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Jan 2025 13:18:40 +0000 Subject: [PATCH 110/173] Allow use of AI fields in view calculations. --- packages/pro | 2 +- .../src/api/controllers/row/staticFormula.ts | 6 ++ .../server/src/api/routes/tests/row.spec.ts | 40 ++++---- .../src/api/routes/tests/viewV2.spec.ts | 97 ++++++++++++++++++- .../src/tests/utilities/mocks/openai.ts | 46 +++++++++ .../src/utilities/rowProcessor/utils.ts | 2 +- packages/types/src/documents/app/row.ts | 1 + .../types/src/documents/app/table/schema.ts | 2 +- 8 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 packages/server/src/tests/utilities/mocks/openai.ts diff --git a/packages/pro b/packages/pro index 32d84f109d..45f5b6fe9b 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 32d84f109d4edc526145472a7446327312151442 +Subproject commit 45f5b6fe9bbdbdf502581740ab43b82e8153260f diff --git a/packages/server/src/api/controllers/row/staticFormula.ts b/packages/server/src/api/controllers/row/staticFormula.ts index b81a164807..afa3a1f239 100644 --- a/packages/server/src/api/controllers/row/staticFormula.ts +++ b/packages/server/src/api/controllers/row/staticFormula.ts @@ -162,6 +162,12 @@ export async function finaliseRow( dynamic: false, contextRows: [enrichedRow], }) + + const flag1 = await features.isEnabled(FeatureFlag.BUDIBASE_AI) + const flag2 = await pro.features.isBudibaseAIEnabled() + const flag3 = await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS) + const flag4 = await pro.features.isAICustomConfigsEnabled() + const aiEnabled = ((await features.isEnabled(FeatureFlag.BUDIBASE_AI)) && (await pro.features.isBudibaseAIEnabled())) || diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index a3012c3760..968ce9c798 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -8,7 +8,13 @@ import { import tk from "timekeeper" import emitter from "../../../../src/events" import { outputProcessing } from "../../../utilities/rowProcessor" -import { context, InternalTable, tenancy, utils } from "@budibase/backend-core" +import { + context, + setEnv, + InternalTable, + tenancy, + utils, +} from "@budibase/backend-core" import { quotas } from "@budibase/pro" import { AIOperationEnum, @@ -42,19 +48,8 @@ import { InternalTables } from "../../../db/utils" import { withEnv } from "../../../environment" import { JsTimeoutError } from "@budibase/string-templates" import { isDate } from "../../../utilities" - -jest.mock("@budibase/pro", () => ({ - ...jest.requireActual("@budibase/pro"), - ai: { - LargeLanguageModel: { - forCurrentTenant: async () => ({ - llm: {}, - run: jest.fn(() => `Mock LLM Response`), - buildPromptFromAIOperation: jest.fn(), - }), - }, - }, -})) +import nock from "nock" +import { mockChatGPTResponse } from "../../../tests/utilities/mocks/openai" const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() tk.freeze(timestamp) @@ -99,6 +94,8 @@ if (descriptions.length) { const ds = await dsProvider() datasource = ds.datasource client = ds.client + + mocks.licenses.useCloudFree() }) afterAll(async () => { @@ -172,10 +169,6 @@ if (descriptions.length) { ) } - beforeEach(async () => { - mocks.licenses.useCloudFree() - }) - const getRowUsage = async () => { const { total } = await config.doInContext(undefined, () => quotas.getCurrentUsageValues( @@ -3224,10 +3217,17 @@ if (descriptions.length) { isInternal && describe("AI fields", () => { let table: Table + let envCleanup: () => void beforeAll(async () => { mocks.licenses.useBudibaseAI() mocks.licenses.useAICustomConfigs() + envCleanup = setEnv({ + OPENAI_API_KEY: "sk-abcdefghijklmnopqrstuvwxyz1234567890abcd", + }) + + mockChatGPTResponse("Mock LLM Response") + table = await config.api.table.save( saveTableRequest({ schema: { @@ -3251,7 +3251,9 @@ if (descriptions.length) { }) afterAll(() => { - jest.unmock("@budibase/pro") + nock.cleanAll() + envCleanup() + mocks.licenses.useCloudFree() }) it("should be able to save a row with an AI column", async () => { diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index 6ace7e256b..57efc868e9 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -1,4 +1,5 @@ import { + AIOperationEnum, ArrayOperator, BasicOperator, BBReferenceFieldSubType, @@ -42,7 +43,9 @@ import { } from "../../../integrations/tests/utils" import merge from "lodash/merge" import { quotas } from "@budibase/pro" -import { context, db, events, roles } from "@budibase/backend-core" +import { context, db, events, roles, setEnv } from "@budibase/backend-core" +import { mockChatGPTResponse } from "../../../tests/utilities/mocks/openai" +import nock from "nock" const descriptions = datasourceDescribe({ exclude: [DatabaseName.MONGODB] }) @@ -100,6 +103,7 @@ if (descriptions.length) { beforeAll(async () => { await config.init() + mocks.licenses.useCloudFree() const ds = await dsProvider() rawDatasource = ds.rawDatasource @@ -109,7 +113,6 @@ if (descriptions.length) { beforeEach(() => { jest.clearAllMocks() - mocks.licenses.useCloudFree() }) describe("view crud", () => { @@ -507,7 +510,6 @@ if (descriptions.length) { }) it("readonly fields can be used on free license", async () => { - mocks.licenses.useCloudFree() const table = await config.api.table.save( saveTableRequest({ schema: { @@ -933,6 +935,94 @@ if (descriptions.length) { } ) }) + + describe("AI fields", () => { + let envCleanup: () => void + beforeAll(() => { + mocks.licenses.useBudibaseAI() + mocks.licenses.useAICustomConfigs() + envCleanup = setEnv({ + OPENAI_API_KEY: "sk-abcdefghijklmnopqrstuvwxyz1234567890abcd", + }) + + mockChatGPTResponse(prompt => { + if (prompt.includes("elephant")) { + return "big" + } + if (prompt.includes("mouse")) { + return "small" + } + if (prompt.includes("whale")) { + return "big" + } + return "unknown" + }) + }) + + afterAll(() => { + nock.cleanAll() + envCleanup() + mocks.licenses.useCloudFree() + }) + + it("can use AI fields in view calculations", async () => { + const table = await config.api.table.save( + saveTableRequest({ + schema: { + animal: { + name: "animal", + type: FieldType.STRING, + }, + bigOrSmall: { + name: "bigOrSmall", + type: FieldType.AI, + operation: AIOperationEnum.CATEGORISE_TEXT, + categories: "big,small", + columns: ["animal"], + }, + }, + }) + ) + + const view = await config.api.viewV2.create({ + tableId: table._id!, + name: generator.guid(), + type: ViewV2Type.CALCULATION, + schema: { + bigOrSmall: { + visible: true, + }, + count: { + visible: true, + calculationType: CalculationType.COUNT, + field: "animal", + }, + }, + }) + + await config.api.row.save(table._id!, { + animal: "elephant", + }) + + await config.api.row.save(table._id!, { + animal: "mouse", + }) + + await config.api.row.save(table._id!, { + animal: "whale", + }) + + const { rows } = await config.api.row.search(view.id, { + sort: "bigOrSmall", + sortOrder: SortOrder.ASCENDING, + }) + expect(rows).toHaveLength(2) + expect(rows[0].bigOrSmall).toEqual("big") + expect(rows[1].bigOrSmall).toEqual("small") + expect(rows[0].count).toEqual(2) + expect(rows[1].count).toEqual(1) + }) + }) }) describe("update", () => { @@ -1836,7 +1926,6 @@ if (descriptions.length) { }, }) - mocks.licenses.useCloudFree() const view = await getDelegate(res) expect(view.schema?.one).toEqual( expect.objectContaining({ visible: true, readonly: true }) diff --git a/packages/server/src/tests/utilities/mocks/openai.ts b/packages/server/src/tests/utilities/mocks/openai.ts new file mode 100644 index 0000000000..b17491808c --- /dev/null +++ b/packages/server/src/tests/utilities/mocks/openai.ts @@ -0,0 +1,46 @@ +import nock from "nock" + +let chatID = 1 + +export function mockChatGPTResponse( + response: string | ((prompt: string) => string) +) { + return nock("https://api.openai.com") + .post("/v1/chat/completions") + .reply(200, (uri, requestBody) => { + let content = response + if (typeof response === "function") { + const messages = (requestBody as any).messages + content = response(messages[0].content) + } + + chatID++ + + return { + id: `chatcmpl-${chatID}`, + object: "chat.completion", + created: Math.floor(Date.now() / 1000), + model: "gpt-4o-mini", + system_fingerprint: `fp_${chatID}`, + choices: [ + { + index: 0, + message: { role: "assistant", content }, + logprobs: null, + finish_reason: "stop", + }, + ], + usage: { + prompt_tokens: 0, + completion_tokens: 0, + total_tokens: 0, + completion_tokens_details: { + reasoning_tokens: 0, + accepted_prediction_tokens: 0, + rejected_prediction_tokens: 0, + }, + }, + } + }) + .persist() +} diff --git a/packages/server/src/utilities/rowProcessor/utils.ts b/packages/server/src/utilities/rowProcessor/utils.ts index 09d3324ded..7d2f8b49f4 100644 --- a/packages/server/src/utilities/rowProcessor/utils.ts +++ b/packages/server/src/utilities/rowProcessor/utils.ts @@ -160,7 +160,7 @@ export async function processAIColumns( return tracer.trace("processAIColumn", {}, async span => { span?.addTags({ table_id: table._id, column }) - const llmResponse = await llmWrapper.run(prompt!) + const llmResponse = await llmWrapper.run(prompt) return { ...row, [column]: llmResponse, diff --git a/packages/types/src/documents/app/row.ts b/packages/types/src/documents/app/row.ts index 6b6b38a5cf..bb58933b65 100644 --- a/packages/types/src/documents/app/row.ts +++ b/packages/types/src/documents/app/row.ts @@ -154,6 +154,7 @@ export const GroupByTypes = [ FieldType.BOOLEAN, FieldType.DATETIME, FieldType.BIGINT, + FieldType.AI, ] export function canGroupBy(type: FieldType) { diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index 771192e2f5..f4a6d8481d 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -123,7 +123,7 @@ export interface AIFieldMetadata extends BaseFieldSchema { operation: AIOperationEnum columns?: string[] column?: string - categories?: string[] + categories?: string prompt?: string language?: string } From 10fca945d27f282c2e765f035f4b1582a60fb3a7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 14:27:13 +0100 Subject: [PATCH 111/173] Cleanups --- .../frontend-core/src/fetch/CustomFetch.ts | 4 ++- packages/frontend-core/src/fetch/DataFetch.ts | 15 ++++++----- .../frontend-core/src/fetch/FieldFetch.ts | 6 ++--- .../frontend-core/src/fetch/JSONArrayFetch.ts | 6 +++-- .../src/fetch/NestedProviderFetch.ts | 4 ++- .../src/fetch/QueryArrayFetch.ts | 6 +++-- .../frontend-core/src/fetch/QueryFetch.ts | 6 +++-- .../src/fetch/RelationshipFetch.ts | 4 ++- .../frontend-core/src/fetch/TableFetch.ts | 4 ++- packages/frontend-core/src/fetch/ViewFetch.ts | 4 ++- .../frontend-core/src/fetch/ViewV2Fetch.ts | 4 ++- packages/frontend-core/src/fetch/index.ts | 27 +++++++++++++------ 12 files changed, 60 insertions(+), 30 deletions(-) diff --git a/packages/frontend-core/src/fetch/CustomFetch.ts b/packages/frontend-core/src/fetch/CustomFetch.ts index 176d878a54..afd3d18ba9 100644 --- a/packages/frontend-core/src/fetch/CustomFetch.ts +++ b/packages/frontend-core/src/fetch/CustomFetch.ts @@ -100,7 +100,9 @@ export default class CustomFetch extends DataFetch< return this.enrichCustomData(this.parseCustomData(datasource?.data)) } - async getDefinition(datasource: CustomDatasource) { + async getDefinition() { + const { datasource } = this.options + // Try and work out the schema from the array provided const schema: CustomDefinition = {} const data = this.getCustomData(datasource) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index b5eb774e45..e5d899d596 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -11,6 +11,7 @@ import { SortType, TableSchema, UISearchFilter, + ViewSchema, } from "@budibase/types" import { APIClient } from "../api/types" @@ -210,10 +211,10 @@ export default abstract class DataFetch< * Fetches a fresh set of data from the server, resetting pagination */ async getInitialData() { - const { datasource, filter, paginate } = this.options + const { filter, paginate } = this.options // Fetch datasource definition and extract sort properties if configured - const definition = await this.getDefinition(datasource) + const definition = await this.getDefinition() // Determine feature flags const features = await this.determineFeatureFlags() @@ -351,19 +352,19 @@ export default abstract class DataFetch< /** * Gets the definition for this datasource. - * @param datasource + * @return {object} the definition */ - abstract getDefinition( - datasource: TDatasource | null - ): Promise + abstract getDefinition(): Promise /** * Gets the schema definition for a datasource. * @param definition the datasource definition * @return {object} the schema */ - getSchema(definition: TDefinition | null): Record | undefined { + getSchema( + definition: TDefinition | null + ): ViewSchema | Record | undefined { return definition?.schema ?? undefined } diff --git a/packages/frontend-core/src/fetch/FieldFetch.ts b/packages/frontend-core/src/fetch/FieldFetch.ts index 636fb63f3d..ac1e683c51 100644 --- a/packages/frontend-core/src/fetch/FieldFetch.ts +++ b/packages/frontend-core/src/fetch/FieldFetch.ts @@ -19,9 +19,9 @@ export default class FieldFetch extends DataFetch< FieldDatasource, FieldDefinition > { - async getDefinition( - datasource: FieldDatasource - ): Promise { + async getDefinition(): Promise { + const { datasource } = this.options + // Field sources have their schema statically defined let schema if (datasource.fieldType === "attachment") { diff --git a/packages/frontend-core/src/fetch/JSONArrayFetch.ts b/packages/frontend-core/src/fetch/JSONArrayFetch.ts index f0cbaa87c5..cae9a1e521 100644 --- a/packages/frontend-core/src/fetch/JSONArrayFetch.ts +++ b/packages/frontend-core/src/fetch/JSONArrayFetch.ts @@ -1,8 +1,10 @@ -import FieldFetch, { FieldDatasource } from "./FieldFetch" +import FieldFetch from "./FieldFetch" import { getJSONArrayDatasourceSchema } from "../utils/json" export default class JSONArrayFetch extends FieldFetch { - async getDefinition(datasource: FieldDatasource) { + async getDefinition() { + const { datasource } = this.options + // JSON arrays need their table definitions fetched. // We can then extract their schema as a subset of the table schema. try { diff --git a/packages/frontend-core/src/fetch/NestedProviderFetch.ts b/packages/frontend-core/src/fetch/NestedProviderFetch.ts index 4bcdd697a2..666340610f 100644 --- a/packages/frontend-core/src/fetch/NestedProviderFetch.ts +++ b/packages/frontend-core/src/fetch/NestedProviderFetch.ts @@ -17,7 +17,9 @@ export default class NestedProviderFetch extends DataFetch< NestedProviderDatasource, NestedProviderDefinition > { - async getDefinition(datasource: NestedProviderDatasource) { + async getDefinition() { + const { datasource } = this.options + // Nested providers should already have exposed their own schema return { schema: datasource?.value?.schema, diff --git a/packages/frontend-core/src/fetch/QueryArrayFetch.ts b/packages/frontend-core/src/fetch/QueryArrayFetch.ts index ce9177e554..9142000fe6 100644 --- a/packages/frontend-core/src/fetch/QueryArrayFetch.ts +++ b/packages/frontend-core/src/fetch/QueryArrayFetch.ts @@ -1,11 +1,13 @@ -import FieldFetch, { FieldDatasource } from "./FieldFetch" +import FieldFetch from "./FieldFetch" import { getJSONArrayDatasourceSchema, generateQueryArraySchemas, } from "../utils/json" export default class QueryArrayFetch extends FieldFetch { - async getDefinition(datasource: FieldDatasource) { + async getDefinition() { + const { datasource } = this.options + if (!datasource?.tableId) { return null } diff --git a/packages/frontend-core/src/fetch/QueryFetch.ts b/packages/frontend-core/src/fetch/QueryFetch.ts index 0825d39660..0754edd267 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.ts +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -18,7 +18,7 @@ interface QueryDatasource { export default class QueryFetch extends DataFetch { async determineFeatureFlags() { - const definition = await this.getDefinition(this.options.datasource) + const definition = await this.getDefinition() const supportsPagination = !!definition?.fields?.pagination?.type && !!definition?.fields?.pagination?.location && @@ -26,7 +26,9 @@ export default class QueryFetch extends DataFetch { return { supportsPagination } } - async getDefinition(datasource: QueryDatasource) { + async getDefinition() { + const { datasource } = this.options + if (!datasource?._id) { return null } diff --git a/packages/frontend-core/src/fetch/RelationshipFetch.ts b/packages/frontend-core/src/fetch/RelationshipFetch.ts index 7b6e93fbcc..f853a753cd 100644 --- a/packages/frontend-core/src/fetch/RelationshipFetch.ts +++ b/packages/frontend-core/src/fetch/RelationshipFetch.ts @@ -12,7 +12,9 @@ export default class RelationshipFetch extends DataFetch< RelationshipDatasource, Table > { - async getDefinition(datasource: RelationshipDatasource) { + async getDefinition() { + const { datasource } = this.options + if (!datasource?.tableId) { return null } diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index 433de69b59..c1152f2869 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -11,7 +11,9 @@ export default class TableFetch extends DataFetch { } } - async getDefinition(datasource: UITable) { + async getDefinition() { + const { datasource } = this.options + if (!datasource?.tableId) { return null } diff --git a/packages/frontend-core/src/fetch/ViewFetch.ts b/packages/frontend-core/src/fetch/ViewFetch.ts index 2238d226ab..b6830e7118 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.ts +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -4,7 +4,9 @@ import DataFetch from "./DataFetch" type ViewV1 = View & { name: string } export default class ViewFetch extends DataFetch { - async getDefinition(datasource: ViewV1) { + async getDefinition() { + const { datasource } = this.options + if (!datasource?.tableId) { return null } diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index 1be1ba295c..cdd3bab6ed 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -12,7 +12,9 @@ export default class ViewV2Fetch extends DataFetch { } } - async getDefinition(datasource: UIView) { + async getDefinition() { + const { datasource } = this.options + try { const res = await this.API.viewV2.fetchDefinition(datasource.id) return res?.data diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 1577f76034..4accb0b5ec 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -10,7 +10,6 @@ import UserFetch from "./UserFetch.js" import GroupUserFetch from "./GroupUserFetch" import CustomFetch from "./CustomFetch" import QueryArrayFetch from "./QueryArrayFetch.js" -import { UIDatasource } from "@budibase/types" import { APIClient } from "../api/types.js" const DataFetchMap = { @@ -39,12 +38,16 @@ export const fetchData = ({ API, datasource, options }: any) => { // Creates an empty fetch instance with no datasource configured, so no data // will initially be loaded -const createEmptyFetchInstance = ({ +const createEmptyFetchInstance = < + TDatasource extends { + type: keyof typeof DataFetchMap + } +>({ API, datasource, }: { API: APIClient - datasource: any + datasource: TDatasource }) => { const handler = DataFetchMap[datasource?.type as keyof typeof DataFetchMap] if (!handler) { @@ -54,25 +57,33 @@ const createEmptyFetchInstance = ({ } // Fetches the definition of any type of datasource -export const getDatasourceDefinition = async ({ +export const getDatasourceDefinition = async < + TDatasource extends { + type: keyof typeof DataFetchMap + } +>({ API, datasource, }: { API: APIClient - datasource: any + datasource: TDatasource }) => { const instance = createEmptyFetchInstance({ API, datasource }) - return await instance?.getDefinition(datasource) + return await instance?.getDefinition() } // Fetches the schema of any type of datasource -export const getDatasourceSchema = ({ +export const getDatasourceSchema = < + TDatasource extends { + type: keyof typeof DataFetchMap + } +>({ API, datasource, definition, }: { API: APIClient - datasource: UIDatasource + datasource: TDatasource definition?: any }) => { const instance = createEmptyFetchInstance({ API, datasource }) From 95d3238d1e83cb5d840055edbb0214a16b81ff97 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 14:29:28 +0100 Subject: [PATCH 112/173] Fix declarations --- packages/bbui/src/helpers.d.ts | 4 ++- packages/frontend-core/src/utils/json.d.ts | 32 ++++++++++++---------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/bbui/src/helpers.d.ts b/packages/bbui/src/helpers.d.ts index 98c6060590..79e08657b7 100644 --- a/packages/bbui/src/helpers.d.ts +++ b/packages/bbui/src/helpers.d.ts @@ -1 +1,3 @@ -export const cloneDeep: (obj: T) => T +declare module "./helpers" { + export const cloneDeep: (obj: T) => T +} diff --git a/packages/frontend-core/src/utils/json.d.ts b/packages/frontend-core/src/utils/json.d.ts index 4f26f4b264..e9b6ac5703 100644 --- a/packages/frontend-core/src/utils/json.d.ts +++ b/packages/frontend-core/src/utils/json.d.ts @@ -2,20 +2,22 @@ import { JsonFieldMetadata, QuerySchema } from "@budibase/types" type Schema = Record -export const getJSONArrayDatasourceSchema: ( - tableSchema: Schema, - datasource: any -) => Record +declare module "./json" { + export const getJSONArrayDatasourceSchema: ( + tableSchema: Schema, + datasource: any + ) => Record -export const generateQueryArraySchemas: ( - schema: Schema, - nestedSchemaFields?: Record -) => Schema + export const generateQueryArraySchemas: ( + schema: Schema, + nestedSchemaFields?: Record + ) => Schema -export const convertJSONSchemaToTableSchema: ( - jsonSchema: JsonFieldMetadata, - options: { - squashObjects?: boolean - prefixKeys?: string - } -) => Record + export const convertJSONSchemaToTableSchema: ( + jsonSchema: JsonFieldMetadata, + options: { + squashObjects?: boolean + prefixKeys?: string + } + ) => Record +} From 83bc2e17dbc4bbf30ae234d44a58a431d5851ff8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 14:45:00 +0100 Subject: [PATCH 113/173] Fix types --- .../frontend-core/src/components/grid/stores/datasource.ts | 4 ++-- packages/frontend-core/src/components/grid/stores/rows.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasource.ts b/packages/frontend-core/src/components/grid/stores/datasource.ts index 4c20e9493f..7fca6ace49 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.ts +++ b/packages/frontend-core/src/components/grid/stores/datasource.ts @@ -73,7 +73,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { const schema = derived(definition, $definition => { const schema: Record | null | undefined = getDatasourceSchema({ API, - datasource: get(datasource), + datasource: get(datasource) as any, definition: $definition ?? undefined, }) if (!schema) { @@ -184,7 +184,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { const refreshDefinition = async () => { const def = await getDatasourceDefinition({ API, - datasource: get(datasource), + datasource: get(datasource) as any, }) definition.set((def as any) ?? null) } diff --git a/packages/frontend-core/src/components/grid/stores/rows.ts b/packages/frontend-core/src/components/grid/stores/rows.ts index b9c9b3fe1e..72502b3dbd 100644 --- a/packages/frontend-core/src/components/grid/stores/rows.ts +++ b/packages/frontend-core/src/components/grid/stores/rows.ts @@ -254,7 +254,7 @@ export const createActions = (context: StoreContext): RowActionStore => { // Reset state properties when dataset changes if (!$instanceLoaded || resetRows) { - definition.set($fetch.definition) + definition.set($fetch.definition as any) } // Reset scroll state when data changes From d3ba4b103e27b58547b7ccf495c967d0edc8d012 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 15:51:48 +0100 Subject: [PATCH 114/173] Fix return type --- packages/server/src/api/controllers/row/views.ts | 1 + packages/types/src/api/web/pagination.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/server/src/api/controllers/row/views.ts b/packages/server/src/api/controllers/row/views.ts index dcf8680348..418aa462c4 100644 --- a/packages/server/src/api/controllers/row/views.ts +++ b/packages/server/src/api/controllers/row/views.ts @@ -54,6 +54,7 @@ export async function searchView( rows: result.rows, bookmark: result.bookmark, hasNextPage: result.hasNextPage, + totalRows: result.totalRows, } } diff --git a/packages/types/src/api/web/pagination.ts b/packages/types/src/api/web/pagination.ts index 48588bf6a1..f87bc97824 100644 --- a/packages/types/src/api/web/pagination.ts +++ b/packages/types/src/api/web/pagination.ts @@ -24,4 +24,5 @@ export interface PaginationRequest extends BasicPaginationRequest { export interface PaginationResponse { bookmark: string | number | undefined hasNextPage?: boolean + totalRows?: number } From 5f82a395174c6afe4930c6f04e8a65139fa4bf71 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 15:57:15 +0100 Subject: [PATCH 115/173] Undo some typings --- packages/frontend-core/src/fetch/DataFetch.ts | 2 +- packages/shared-core/src/filters.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index e5d899d596..c0be73dd2f 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -324,7 +324,7 @@ export default abstract class DataFetch< } // If we don't support sorting, do a client-side sort - if (!this.features.supportsSort && clientSideSorting) { + if (!this.features.supportsSort && clientSideSorting && sortType) { rows = sort(rows, sortColumn as any, sortOrder, sortType) } diff --git a/packages/shared-core/src/filters.ts b/packages/shared-core/src/filters.ts index a1e8534a95..b711d4cb61 100644 --- a/packages/shared-core/src/filters.ts +++ b/packages/shared-core/src/filters.ts @@ -552,7 +552,7 @@ export function search>( */ export function runQuery>( docs: T[], - query: SearchFilters | null + query: SearchFilters ): T[] { if (!docs || !Array.isArray(docs)) { return [] @@ -876,7 +876,7 @@ export function sort>( docs: T[], sort: keyof T, sortOrder: SortOrder, - sortType: SortType | null = SortType.STRING + sortType = SortType.STRING ): T[] { if (!sort || !sortOrder || !sortType) { return docs From a8abe5bc432da6b7644095d9ebb2cf533f3bdb32 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 15:58:55 +0100 Subject: [PATCH 116/173] Remove deprecated fetch --- packages/types/src/ui/stores/grid/fetch.ts | 80 ---------------------- packages/types/src/ui/stores/grid/index.ts | 1 - 2 files changed, 81 deletions(-) delete mode 100644 packages/types/src/ui/stores/grid/fetch.ts diff --git a/packages/types/src/ui/stores/grid/fetch.ts b/packages/types/src/ui/stores/grid/fetch.ts deleted file mode 100644 index 5f42db24b0..0000000000 --- a/packages/types/src/ui/stores/grid/fetch.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { - Row, - SearchFilters, - SortOrder, - SortType, - Table, - UIDatasource, - UILegacyFilter, - UISearchFilter, -} from "@budibase/types" - -interface SearchOptions { - query?: SearchFilters | null | undefined - limit: number - sort: string | null - sortOrder: string | undefined - sortType: SortType | null - paginate: boolean - bookmark: null -} - -interface TableAPI { - fetchTableDefinition(tableId: string): Promise
- searchTable(tableId: string, options: SearchOptions): any -} - -interface ViewV2API { - fetchDefinition: (datasourceId: string) => Promise - fetch: (datasourceId: string, options: SearchOptions) => any -} - -interface UserAPI { - searchUsers: (opts: { - bookmark: null - query: - | SearchFilters - | { - string: { - email: null - } - } - | null - appId: string - paginate: boolean - limit: number - }) => Promise -} - -export interface UIFetchAPI extends TableAPI, UserAPI { - definition: UIDatasource - - getInitialData: () => Promise - loading: any - loaded: boolean - - viewV2: ViewV2API - - resetKey: string | null - error: any - - hasNextPage: boolean - nextPage: () => Promise - - rows: Row[] - - options?: { - datasource?: { - tableId: string - id: string - } - } - update: ({ - sortOrder, - sortColumn, - }: { - sortOrder?: SortOrder - sortColumn?: string - filter?: UILegacyFilter[] | UISearchFilter - }) => any -} diff --git a/packages/types/src/ui/stores/grid/index.ts b/packages/types/src/ui/stores/grid/index.ts index f419134452..7c3b6d4cb4 100644 --- a/packages/types/src/ui/stores/grid/index.ts +++ b/packages/types/src/ui/stores/grid/index.ts @@ -6,4 +6,3 @@ export * from "./view" export * from "./user" export * from "./filters" export * from "./rows" -export * from "./fetch" From 0ca0ba64336e8a1514ba18e5fbd3f7f887be5127 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 16:04:39 +0100 Subject: [PATCH 117/173] Type nulls --- packages/frontend-core/src/fetch/DataFetch.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index c0be73dd2f..74450c6254 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -19,14 +19,14 @@ const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils interface DataFetchStore { rows: Row[] - info: null + info: any schema: TableSchema | null loading: boolean loaded: boolean query: TQuery pageNumber: number - cursor: null - cursors: any[] + cursor: string | null + cursors: string[] resetKey: string error: { message: string From a414505eefdcfad7da76f8422f7539effd71bc4e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 16:13:43 +0100 Subject: [PATCH 118/173] Cleanups --- .../frontend-core/src/components/grid/stores/datasource.ts | 4 ++-- packages/frontend-core/src/fetch/TableFetch.ts | 2 +- packages/frontend-core/src/fetch/UserFetch.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasource.ts b/packages/frontend-core/src/components/grid/stores/datasource.ts index 7fca6ace49..0b07796fde 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.ts +++ b/packages/frontend-core/src/components/grid/stores/datasource.ts @@ -71,7 +71,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { } = context const schema = derived(definition, $definition => { - const schema: Record | null | undefined = getDatasourceSchema({ + const schema: Record | undefined = getDatasourceSchema({ API, datasource: get(datasource) as any, definition: $definition ?? undefined, @@ -186,7 +186,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { API, datasource: get(datasource) as any, }) - definition.set((def as any) ?? null) + definition.set(def as any) } // Saves the datasource definition diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index c1152f2869..f5927262cb 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -37,7 +37,7 @@ export default class TableFetch extends DataFetch { // Search table try { const res = await this.API.searchTable(tableId, { - query: query ?? undefined, + query, limit, sort: sortColumn, sortOrder: sortOrder ?? SortOrder.ASCENDING, diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 8f1ef36cac..656cd840fe 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -52,7 +52,7 @@ export default class UserFetch extends DataFetch< const finalQuery: SearchFilters = utils.isSupportedUserSearch(rest) ? rest - : { [BasicOperator.EMPTY]: { email: true } } + : { [BasicOperator.EMPTY]: { email: null } } try { const opts: SearchUsersRequest = { From 0784a9571273abd3bddd74e14776df3f4bf23d18 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 16:33:29 +0100 Subject: [PATCH 119/173] Remove ! usage --- packages/frontend-core/src/api/views.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/frontend-core/src/api/views.ts b/packages/frontend-core/src/api/views.ts index 83f7e97df0..aa0f797f58 100644 --- a/packages/frontend-core/src/api/views.ts +++ b/packages/frontend-core/src/api/views.ts @@ -28,7 +28,9 @@ export const buildViewEndpoints = (API: BaseAPIClient): ViewEndpoints => ({ fetchViewData: async (name, { field, groupBy, calculation }) => { const params = new URLSearchParams() if (calculation) { - params.set("field", field!) + if (field) { + params.set("field", field) + } params.set("calculation", calculation) } if (groupBy) { From 3a8942f487eb0fdd625d7815aa641977ac8b078c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 17:02:34 +0100 Subject: [PATCH 120/173] Add todos --- .../src/components/grid/stores/datasource.ts | 14 ++++++++------ .../src/components/grid/stores/rows.ts | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasource.ts b/packages/frontend-core/src/components/grid/stores/datasource.ts index 0b07796fde..805ace5a8f 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.ts +++ b/packages/frontend-core/src/components/grid/stores/datasource.ts @@ -1,3 +1,5 @@ +// TODO: datasource and defitions are unions of the different implementations. At this point, the datasource does not know what type is being used, and the assignations will cause TS exceptions. Casting it "as any" for now. This should be fixed improving the type usages. + import { derived, get, Readable, Writable } from "svelte/store" import { getDatasourceDefinition, getDatasourceSchema } from "../../../fetch" import { enrichSchemaWithRelColumns, memo } from "../../../utils" @@ -73,7 +75,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { const schema = derived(definition, $definition => { const schema: Record | undefined = getDatasourceSchema({ API, - datasource: get(datasource) as any, + datasource: get(datasource) as any, // TODO: see line 1 definition: $definition ?? undefined, }) if (!schema) { @@ -130,7 +132,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { ([$datasource, $definition]) => { let type = $datasource?.type if (type === "provider") { - type = ($datasource as any).value?.datasource?.type + type = ($datasource as any).value?.datasource?.type // TODO: see line 1 } // Handle calculation views if (type === "viewV2" && $definition?.type === ViewV2Type.CALCULATION) { @@ -184,9 +186,9 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { const refreshDefinition = async () => { const def = await getDatasourceDefinition({ API, - datasource: get(datasource) as any, + datasource: get(datasource) as any, // TODO: see line 1 }) - definition.set(def as any) + definition.set(def as any) // TODO: see line 1 } // Saves the datasource definition @@ -231,7 +233,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { if ("default" in newDefinition.schema[column]) { delete newDefinition.schema[column].default } - return await saveDefinition(newDefinition as any) + return await saveDefinition(newDefinition as any) // TODO: see line 1 } // Adds a schema mutation for a single field @@ -307,7 +309,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { await saveDefinition({ ...$definition, schema: newSchema, - } as any) + } as any) // TODO: see line 1 resetSchemaMutations() } diff --git a/packages/frontend-core/src/components/grid/stores/rows.ts b/packages/frontend-core/src/components/grid/stores/rows.ts index 72502b3dbd..d227fc70df 100644 --- a/packages/frontend-core/src/components/grid/stores/rows.ts +++ b/packages/frontend-core/src/components/grid/stores/rows.ts @@ -254,7 +254,7 @@ export const createActions = (context: StoreContext): RowActionStore => { // Reset state properties when dataset changes if (!$instanceLoaded || resetRows) { - definition.set($fetch.definition as any) + definition.set($fetch.definition as any) // TODO: datasource and defitions are unions of the different implementations. At this point, the datasource does not know what type is being used, and the assignations will cause TS exceptions. Casting it "as any" for now. This should be fixed improving the type usages. } // Reset scroll state when data changes From 23f9e3f3fe02584503a6eaebf58d21a077de22c8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 17:06:19 +0100 Subject: [PATCH 121/173] Add todo --- packages/frontend-core/src/components/grid/stores/rows.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/stores/rows.ts b/packages/frontend-core/src/components/grid/stores/rows.ts index d227fc70df..07fbf02134 100644 --- a/packages/frontend-core/src/components/grid/stores/rows.ts +++ b/packages/frontend-core/src/components/grid/stores/rows.ts @@ -21,7 +21,7 @@ interface IndexedUIRow extends UIRow { interface RowStore { rows: Writable - fetch: Writable | null> + fetch: Writable | null> // TODO: type this properly, having a union of all the possible options loaded: Writable refreshing: Writable loading: Writable From 7d6b822b8a76014d03ccad31c227857b660990b1 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Jan 2025 16:12:02 +0000 Subject: [PATCH 122/173] Improve typing around AI prompts. --- packages/pro | 2 +- .../src/api/controllers/row/staticFormula.ts | 5 -- .../types/src/documents/app/table/schema.ts | 57 ++++++++++++++++--- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/packages/pro b/packages/pro index 45f5b6fe9b..788173a024 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 45f5b6fe9bbdbdf502581740ab43b82e8153260f +Subproject commit 788173a024fd5ef98d3122b26dbc06d39fb51349 diff --git a/packages/server/src/api/controllers/row/staticFormula.ts b/packages/server/src/api/controllers/row/staticFormula.ts index afa3a1f239..e2743da366 100644 --- a/packages/server/src/api/controllers/row/staticFormula.ts +++ b/packages/server/src/api/controllers/row/staticFormula.ts @@ -163,11 +163,6 @@ export async function finaliseRow( contextRows: [enrichedRow], }) - const flag1 = await features.isEnabled(FeatureFlag.BUDIBASE_AI) - const flag2 = await pro.features.isBudibaseAIEnabled() - const flag3 = await features.isEnabled(FeatureFlag.AI_CUSTOM_CONFIGS) - const flag4 = await pro.features.isAICustomConfigsEnabled() - const aiEnabled = ((await features.isEnabled(FeatureFlag.BUDIBASE_AI)) && (await pro.features.isBudibaseAIEnabled())) || diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index f4a6d8481d..47a63e0dd9 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -118,16 +118,59 @@ export interface FormulaFieldMetadata extends BaseFieldSchema { responseType?: FormulaResponseType } -export interface AIFieldMetadata extends BaseFieldSchema { +interface AITranslateFieldMetadata extends BaseFieldSchema { type: FieldType.AI - operation: AIOperationEnum - columns?: string[] - column?: string - categories?: string - prompt?: string - language?: string + operation: AIOperationEnum.TRANSLATE + column: string + language: string } +interface AICleanDataFieldMetadata extends BaseFieldSchema { + type: FieldType.AI + operation: AIOperationEnum.CLEAN_DATA + column: string +} + +interface AICategoriseTextFieldMetadata extends BaseFieldSchema { + type: FieldType.AI + operation: AIOperationEnum.CATEGORISE_TEXT + columns: string[] + categories: string +} + +interface AISentimentAnalysisFieldMetadata extends BaseFieldSchema { + type: FieldType.AI + operation: AIOperationEnum.SENTIMENT_ANALYSIS + column: string +} + +interface AISearchWebFieldMetadata extends BaseFieldSchema { + type: FieldType.AI + operation: AIOperationEnum.SEARCH_WEB + columns: string[] +} + +interface AIPromptFieldMetadata extends BaseFieldSchema { + type: FieldType.AI + operation: AIOperationEnum.PROMPT + prompt: string +} + +interface AISummariseTextFieldMetadata extends BaseFieldSchema { + type: FieldType.AI + operation: AIOperationEnum.SUMMARISE_TEXT + columns: string[] +} + +export type AIFieldMetadata = + | AITranslateFieldMetadata + | AICleanDataFieldMetadata + | AICategoriseTextFieldMetadata + | AISentimentAnalysisFieldMetadata + | AIPromptFieldMetadata + | AISearchWebFieldMetadata + | AISummariseTextFieldMetadata + export interface BBReferenceFieldMetadata extends Omit { type: FieldType.BB_REFERENCE From eb6a2434b6bfe635a5afa2b4a08e146fd0e0ef75 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 8 Jan 2025 17:18:33 +0100 Subject: [PATCH 123/173] Simplify code --- packages/frontend-core/src/fetch/DataFetch.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 74450c6254..9312c57637 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -11,7 +11,6 @@ import { SortType, TableSchema, UISearchFilter, - ViewSchema, } from "@budibase/types" import { APIClient } from "../api/types" @@ -224,12 +223,12 @@ export default abstract class DataFetch< supportsPagination: paginate && !!features?.supportsPagination, } - if (!definition?.schema) { + // Fetch and enrich schema + let schema = this.getSchema(definition) + if (!schema) { return } - - // Fetch and enrich schema - const schema = this.enrichSchema(definition.schema) + schema = this.enrichSchema(schema) // If an invalid sort column is specified, delete it if (this.options.sortColumn && !schema[this.options.sortColumn]) { @@ -362,9 +361,7 @@ export default abstract class DataFetch< * @param definition the datasource definition * @return {object} the schema */ - getSchema( - definition: TDefinition | null - ): ViewSchema | Record | undefined { + getSchema(definition: TDefinition | null): Record | undefined { return definition?.schema ?? undefined } @@ -379,7 +376,7 @@ export default abstract class DataFetch< let jsonAdditions: Record = {} for (const fieldKey of Object.keys(schema)) { const fieldSchema = schema[fieldKey] - if (fieldSchema?.type === FieldType.JSON) { + if (fieldSchema.type === FieldType.JSON) { const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, { squashObjects: true, }) as Record | null // TODO: remove when convertJSONSchemaToTableSchema is typed From 41e3e2d77415d153c50679eb38e597fc09429ac5 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 8 Jan 2025 16:52:33 +0000 Subject: [PATCH 124/173] Improve handling of configs --- packages/builder/src/stores/portal/oidc.ts | 12 ++++-------- packages/frontend-core/src/api/configs.ts | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/builder/src/stores/portal/oidc.ts b/packages/builder/src/stores/portal/oidc.ts index a914645135..6c3609f9d5 100644 --- a/packages/builder/src/stores/portal/oidc.ts +++ b/packages/builder/src/stores/portal/oidc.ts @@ -11,14 +11,10 @@ class OIDCStore extends BudiStore { async init() { const tenantId = get(auth).tenantId - const config = await API.getOIDCConfig(tenantId) - if (Object.keys(config || {}).length) { - // Just use the first config for now. - // We will be support multiple logins buttons later on. - this.set(config[0]) - } else { - this.set({}) - } + const configs = await API.getOIDCConfigs(tenantId) + // Just use the first config for now. + // We will be support multiple logins buttons later on. + this.set(configs[0] || {}) } } diff --git a/packages/frontend-core/src/api/configs.ts b/packages/frontend-core/src/api/configs.ts index 82f08e58a7..408180a859 100644 --- a/packages/frontend-core/src/api/configs.ts +++ b/packages/frontend-core/src/api/configs.ts @@ -16,7 +16,7 @@ import { BaseAPIClient } from "./types" export interface ConfigEndpoints { getConfig: (type: ConfigType) => Promise getTenantConfig: (tentantId: string) => Promise - getOIDCConfig: (tenantId: string) => Promise + getOIDCConfigs: (tenantId: string) => Promise getOIDCLogos: () => Promise> saveConfig: (config: SaveConfigRequest) => Promise deleteConfig: (id: string, rev: string) => Promise @@ -73,7 +73,7 @@ export const buildConfigEndpoints = (API: BaseAPIClient): ConfigEndpoints => ({ * Gets the OIDC config for a certain tenant. * @param tenantId the tenant ID to get the config for */ - getOIDCConfig: async tenantId => { + getOIDCConfigs: async tenantId => { return await API.get({ url: `/api/global/configs/public/oidc?tenantId=${tenantId}`, }) From 68c2b29e6225225589c65c41a866a64670d17715 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Jan 2025 17:03:40 +0000 Subject: [PATCH 125/173] Admit defeat. --- packages/pro | 2 +- .../types/src/documents/app/table/schema.ts | 57 +++---------------- 2 files changed, 8 insertions(+), 51 deletions(-) diff --git a/packages/pro b/packages/pro index 788173a024..71922a7d97 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 788173a024fd5ef98d3122b26dbc06d39fb51349 +Subproject commit 71922a7d979ddca6f51d9e450abcd81ba9a5b6fa diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index 47a63e0dd9..f4a6d8481d 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -118,59 +118,16 @@ export interface FormulaFieldMetadata extends BaseFieldSchema { responseType?: FormulaResponseType } -interface AITranslateFieldMetadata extends BaseFieldSchema { +export interface AIFieldMetadata extends BaseFieldSchema { type: FieldType.AI - operation: AIOperationEnum.TRANSLATE - column: string - language: string + operation: AIOperationEnum + columns?: string[] + column?: string + categories?: string + prompt?: string + language?: string } -interface AICleanDataFieldMetadata extends BaseFieldSchema { - type: FieldType.AI - operation: AIOperationEnum.CLEAN_DATA - column: string -} - -interface AICategoriseTextFieldMetadata extends BaseFieldSchema { - type: FieldType.AI - operation: AIOperationEnum.CATEGORISE_TEXT - columns: string[] - categories: string -} - -interface AISentimentAnalysisFieldMetadata extends BaseFieldSchema { - type: FieldType.AI - operation: AIOperationEnum.SENTIMENT_ANALYSIS - column: string -} - -interface AISearchWebFieldMetadata extends BaseFieldSchema { - type: FieldType.AI - operation: AIOperationEnum.SEARCH_WEB - columns: string[] -} - -interface AIPromptFieldMetadata extends BaseFieldSchema { - type: FieldType.AI - operation: AIOperationEnum.PROMPT - prompt: string -} - -interface AISummariseTextFieldMetadata extends BaseFieldSchema { - type: FieldType.AI - operation: AIOperationEnum.SUMMARISE_TEXT - columns: string[] -} - -export type AIFieldMetadata = - | AITranslateFieldMetadata - | AICleanDataFieldMetadata - | AICategoriseTextFieldMetadata - | AISentimentAnalysisFieldMetadata - | AIPromptFieldMetadata - | AISearchWebFieldMetadata - | AISummariseTextFieldMetadata - export interface BBReferenceFieldMetadata extends Omit { type: FieldType.BB_REFERENCE From 352e16f347172ece0a69f73fcc97d8456ec6c848 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Jan 2025 17:09:02 +0000 Subject: [PATCH 126/173] Explain the weirdness with enriched view FieldType.AI columns in a comment for the next person to stumble on this. --- packages/server/src/sdk/app/views/index.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/server/src/sdk/app/views/index.ts b/packages/server/src/sdk/app/views/index.ts index 7fc78b9085..4f978253d6 100644 --- a/packages/server/src/sdk/app/views/index.ts +++ b/packages/server/src/sdk/app/views/index.ts @@ -432,6 +432,21 @@ export async function enrichSchema( ...tableSchema[key], ...ui, order: anyViewOrder ? ui?.order ?? undefined : tableSchema[key]?.order, + // When this was written, the only column types in FieldSchema to have columns + // field were the relationship columns. We blank this out here to make sure it's + // not set on non-relationship columns, then below we populate it by calling + // populateRelSchema. + // + // For Budibase 3.0 we introduced the FieldType.AI fields. Some of these fields + // have `columns: string[]` and it flew under the radar here because the + // AIFieldMetadata type isn't a union on its subtypes, it has a collection of + // optional fields. So columns is `columns?: string[]` which allows undefined, + // and doesn't fail this type check. + // + // What this means in practice is when FieldType.AI fields get enriched, we + // delete their `columns`. At the time of writing, I don't believe anything in + // the frontend depends on this, but it is odd and will probably bite us at + // some point. columns: undefined, } From a18256a9cfe018c993d4c53b3e68f1a6189a520b Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Jan 2025 17:10:02 +0000 Subject: [PATCH 127/173] Limit view AI column tests to internal tables. --- .../src/api/routes/tests/viewV2.spec.ts | 145 +++++++++--------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index 57efc868e9..9531737d30 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -936,93 +936,94 @@ if (descriptions.length) { ) }) - describe("AI fields", () => { - let envCleanup: () => void - beforeAll(() => { - mocks.licenses.useBudibaseAI() - mocks.licenses.useAICustomConfigs() - envCleanup = setEnv({ - OPENAI_API_KEY: "sk-abcdefghijklmnopqrstuvwxyz1234567890abcd", + isInternal && + describe("AI fields", () => { + let envCleanup: () => void + beforeAll(() => { + mocks.licenses.useBudibaseAI() + mocks.licenses.useAICustomConfigs() + envCleanup = setEnv({ + OPENAI_API_KEY: "sk-abcdefghijklmnopqrstuvwxyz1234567890abcd", + }) + + mockChatGPTResponse(prompt => { + if (prompt.includes("elephant")) { + return "big" + } + if (prompt.includes("mouse")) { + return "small" + } + if (prompt.includes("whale")) { + return "big" + } + return "unknown" + }) }) - mockChatGPTResponse(prompt => { - if (prompt.includes("elephant")) { - return "big" - } - if (prompt.includes("mouse")) { - return "small" - } - if (prompt.includes("whale")) { - return "big" - } - return "unknown" + afterAll(() => { + nock.cleanAll() + envCleanup() + mocks.licenses.useCloudFree() }) - }) - afterAll(() => { - nock.cleanAll() - envCleanup() - mocks.licenses.useCloudFree() - }) - - it("can use AI fields in view calculations", async () => { - const table = await config.api.table.save( - saveTableRequest({ - schema: { - animal: { - name: "animal", - type: FieldType.STRING, + it("can use AI fields in view calculations", async () => { + const table = await config.api.table.save( + saveTableRequest({ + schema: { + animal: { + name: "animal", + type: FieldType.STRING, + }, + bigOrSmall: { + name: "bigOrSmall", + type: FieldType.AI, + operation: AIOperationEnum.CATEGORISE_TEXT, + categories: "big,small", + columns: ["animal"], + }, }, + }) + ) + + const view = await config.api.viewV2.create({ + tableId: table._id!, + name: generator.guid(), + type: ViewV2Type.CALCULATION, + schema: { bigOrSmall: { - name: "bigOrSmall", - type: FieldType.AI, - operation: AIOperationEnum.CATEGORISE_TEXT, - categories: "big,small", - columns: ["animal"], + visible: true, + }, + count: { + visible: true, + calculationType: CalculationType.COUNT, + field: "animal", }, }, }) - ) - const view = await config.api.viewV2.create({ - tableId: table._id!, - name: generator.guid(), - type: ViewV2Type.CALCULATION, - schema: { - bigOrSmall: { - visible: true, - }, - count: { - visible: true, - calculationType: CalculationType.COUNT, - field: "animal", - }, - }, - }) + await config.api.row.save(table._id!, { + animal: "elephant", + }) - await config.api.row.save(table._id!, { - animal: "elephant", - }) + await config.api.row.save(table._id!, { + animal: "mouse", + }) - await config.api.row.save(table._id!, { - animal: "mouse", - }) + await config.api.row.save(table._id!, { + animal: "whale", + }) - await config.api.row.save(table._id!, { - animal: "whale", + const { rows } = await config.api.row.search(view.id, { + sort: "bigOrSmall", + sortOrder: SortOrder.ASCENDING, + }) + expect(rows).toHaveLength(2) + expect(rows[0].bigOrSmall).toEqual("big") + expect(rows[1].bigOrSmall).toEqual("small") + expect(rows[0].count).toEqual(2) + expect(rows[1].count).toEqual(1) }) - - const { rows } = await config.api.row.search(view.id, { - sort: "bigOrSmall", - sortOrder: SortOrder.ASCENDING, - }) - expect(rows).toHaveLength(2) - expect(rows[0].bigOrSmall).toEqual("big") - expect(rows[1].bigOrSmall).toEqual("small") - expect(rows[0].count).toEqual(2) - expect(rows[1].count).toEqual(1) }) - }) }) describe("update", () => { From 2a9e4c307825cf6e97265a8436cfc9a58832ff07 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Wed, 8 Jan 2025 17:34:08 +0000 Subject: [PATCH 128/173] Remove double processing of AI columns. --- packages/server/src/api/controllers/row/staticFormula.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/server/src/api/controllers/row/staticFormula.ts b/packages/server/src/api/controllers/row/staticFormula.ts index e2743da366..bd842ebfd0 100644 --- a/packages/server/src/api/controllers/row/staticFormula.ts +++ b/packages/server/src/api/controllers/row/staticFormula.ts @@ -185,11 +185,6 @@ export async function finaliseRow( enrichedRow = await processFormulas(table, enrichedRow, { dynamic: false, }) - if (aiEnabled) { - enrichedRow = await processAIColumns(table, enrichedRow, { - contextRows: [enrichedRow], - }) - } // this updates the related formulas in other rows based on the relations to this row if (updateFormula) { From 45ee1570370c9e41fe503a12401ac5664081a832 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 11:24:37 +0100 Subject: [PATCH 129/173] Rename file --- packages/client/src/stores/index.js | 2 +- packages/client/src/stores/{notification.js => notification.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/client/src/stores/{notification.js => notification.ts} (100%) diff --git a/packages/client/src/stores/index.js b/packages/client/src/stores/index.js index f2b80ed732..e099434b3d 100644 --- a/packages/client/src/stores/index.js +++ b/packages/client/src/stores/index.js @@ -1,6 +1,6 @@ export { authStore } from "./auth" export { appStore } from "./app" -export { notificationStore } from "./notification" +export { notificationStore } from "./notification.ts" export { routeStore } from "./routes" export { screenStore } from "./screens" export { builderStore } from "./builder" diff --git a/packages/client/src/stores/notification.js b/packages/client/src/stores/notification.ts similarity index 100% rename from packages/client/src/stores/notification.js rename to packages/client/src/stores/notification.ts From 96cee21792413d638191e4a6872bf5e388d1786a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 11:32:10 +0100 Subject: [PATCH 130/173] Type store --- packages/client/src/stores/notification.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/client/src/stores/notification.ts b/packages/client/src/stores/notification.ts index 054117aaba..6f5fcc9ef4 100644 --- a/packages/client/src/stores/notification.ts +++ b/packages/client/src/stores/notification.ts @@ -6,7 +6,7 @@ const DEFAULT_NOTIFICATION_TIMEOUT = 3000 const createNotificationStore = () => { let block = false - const store = writable([]) + const store = writable<{ id: string; message: string; count: number }[]>([]) const blockNotifications = (timeout = 1000) => { block = true @@ -14,17 +14,18 @@ const createNotificationStore = () => { } const send = ( - message, + message: string, type = "info", - icon, + icon: string, autoDismiss = true, - duration, + duration: number, count = 1 ) => { if (block) { return } + // @ts-expect-error if (get(routeStore).queryParams?.peek) { window.parent.postMessage({ type: "notification", @@ -66,7 +67,7 @@ const createNotificationStore = () => { } } - const dismiss = id => { + const dismiss = (id: string) => { store.update(state => { return state.filter(n => n.id !== id) }) @@ -76,13 +77,13 @@ const createNotificationStore = () => { subscribe: store.subscribe, actions: { send, - info: (msg, autoDismiss, duration) => + info: (msg: string, autoDismiss: boolean, duration: number) => send(msg, "info", "Info", autoDismiss ?? true, duration), - success: (msg, autoDismiss, duration) => + success: (msg: string, autoDismiss: boolean, duration: number) => send(msg, "success", "CheckmarkCircle", autoDismiss ?? true, duration), - warning: (msg, autoDismiss, duration) => + warning: (msg: string, autoDismiss: boolean, duration: number) => send(msg, "warning", "Alert", autoDismiss ?? true, duration), - error: (msg, autoDismiss, duration) => + error: (msg: string, autoDismiss: boolean, duration: number) => send(msg, "error", "Alert", autoDismiss ?? false, duration), blockNotifications, dismiss, From f938eb3297e5dd3de249d41c36ef7c0565f1996a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 11:34:15 +0100 Subject: [PATCH 131/173] api to ts --- packages/client/src/api/{api.js => api.ts} | 6 +++++- packages/client/src/api/index.js | 2 +- packages/client/src/stores/notification.ts | 10 +++++----- 3 files changed, 11 insertions(+), 7 deletions(-) rename packages/client/src/api/{api.js => api.ts} (96%) diff --git a/packages/client/src/api/api.js b/packages/client/src/api/api.ts similarity index 96% rename from packages/client/src/api/api.js rename to packages/client/src/api/api.ts index d4c8faa4d2..59430e4ebd 100644 --- a/packages/client/src/api/api.js +++ b/packages/client/src/api/api.ts @@ -1,6 +1,10 @@ import { createAPIClient } from "@budibase/frontend-core" import { authStore } from "../stores/auth.js" -import { notificationStore, devToolsEnabled, devToolsStore } from "../stores/" +import { + notificationStore, + devToolsEnabled, + devToolsStore, +} from "../stores/index.js" import { get } from "svelte/store" export const API = createAPIClient({ diff --git a/packages/client/src/api/index.js b/packages/client/src/api/index.js index 5eb6b2b6f4..a63e19bfbb 100644 --- a/packages/client/src/api/index.js +++ b/packages/client/src/api/index.js @@ -1,4 +1,4 @@ -import { API } from "./api.js" +import { API } from "./api.ts" import { patchAPI } from "./patches.js" // Certain endpoints which return rows need patched so that they transform diff --git a/packages/client/src/stores/notification.ts b/packages/client/src/stores/notification.ts index 6f5fcc9ef4..5e1a4774c1 100644 --- a/packages/client/src/stores/notification.ts +++ b/packages/client/src/stores/notification.ts @@ -18,7 +18,7 @@ const createNotificationStore = () => { type = "info", icon: string, autoDismiss = true, - duration: number, + duration?: number, count = 1 ) => { if (block) { @@ -77,13 +77,13 @@ const createNotificationStore = () => { subscribe: store.subscribe, actions: { send, - info: (msg: string, autoDismiss: boolean, duration: number) => + info: (msg: string, autoDismiss?: boolean, duration?: number) => send(msg, "info", "Info", autoDismiss ?? true, duration), - success: (msg: string, autoDismiss: boolean, duration: number) => + success: (msg: string, autoDismiss?: boolean, duration?: number) => send(msg, "success", "CheckmarkCircle", autoDismiss ?? true, duration), - warning: (msg: string, autoDismiss: boolean, duration: number) => + warning: (msg: string, autoDismiss?: boolean, duration?: number) => send(msg, "warning", "Alert", autoDismiss ?? true, duration), - error: (msg: string, autoDismiss: boolean, duration: number) => + error: (msg: string, autoDismiss?: boolean, duration?: number) => send(msg, "error", "Alert", autoDismiss ?? false, duration), blockNotifications, dismiss, From a0950f15d9bb4d77dbdcc98d8f96fa93b78ef085 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 11:38:16 +0100 Subject: [PATCH 132/173] Add window typings --- packages/client/src/index.d.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/client/src/index.d.ts diff --git a/packages/client/src/index.d.ts b/packages/client/src/index.d.ts new file mode 100644 index 0000000000..7e13670b33 --- /dev/null +++ b/packages/client/src/index.d.ts @@ -0,0 +1,5 @@ +interface Window { + "##BUDIBASE_APP_ID##": string + "##BUDIBASE_IN_BUILDER##": string + MIGRATING_APP: boolean +} From 60c23ae021614dee53eb62a08e0ae9c4da974ff9 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 11:42:35 +0100 Subject: [PATCH 133/173] Type auth store --- packages/client/src/stores/{auth.js => auth.ts} | 4 +++- packages/types/src/api/web/global/self.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) rename packages/client/src/stores/{auth.js => auth.ts} (94%) diff --git a/packages/client/src/stores/auth.js b/packages/client/src/stores/auth.ts similarity index 94% rename from packages/client/src/stores/auth.js rename to packages/client/src/stores/auth.ts index 214cc7bce2..15f44e7c32 100644 --- a/packages/client/src/stores/auth.js +++ b/packages/client/src/stores/auth.ts @@ -2,7 +2,9 @@ import { API } from "api" import { writable } from "svelte/store" const createAuthStore = () => { - const store = writable(null) + const store = writable<{ + csrfToken?: string + } | null>(null) // Fetches the user object if someone is logged in and has reloaded the page const fetchUser = async () => { diff --git a/packages/types/src/api/web/global/self.ts b/packages/types/src/api/web/global/self.ts index 517559d1ca..9d99a1f1a5 100644 --- a/packages/types/src/api/web/global/self.ts +++ b/packages/types/src/api/web/global/self.ts @@ -15,5 +15,5 @@ export interface GetGlobalSelfResponse extends User { license: License budibaseAccess: boolean accountPortalAccess: boolean - csrfToken: boolean + csrfToken: string } From 6e816fb6a2ae3aa8ec13f8d5fc887bc88b3c25fe Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 11:51:27 +0100 Subject: [PATCH 134/173] Fixes --- packages/client/src/api/api.ts | 2 +- packages/client/src/stores/derived/currentRole.js | 2 +- packages/client/src/stores/notification.ts | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/client/src/api/api.ts b/packages/client/src/api/api.ts index 59430e4ebd..93f59f6e9a 100644 --- a/packages/client/src/api/api.ts +++ b/packages/client/src/api/api.ts @@ -1,5 +1,5 @@ import { createAPIClient } from "@budibase/frontend-core" -import { authStore } from "../stores/auth.js" +import { authStore } from "../stores/auth" import { notificationStore, devToolsEnabled, diff --git a/packages/client/src/stores/derived/currentRole.js b/packages/client/src/stores/derived/currentRole.js index 8bb4c5a25d..056a05f8ab 100644 --- a/packages/client/src/stores/derived/currentRole.js +++ b/packages/client/src/stores/derived/currentRole.js @@ -1,7 +1,7 @@ import { derived } from "svelte/store" import { Constants } from "@budibase/frontend-core" import { devToolsStore } from "../devTools.js" -import { authStore } from "../auth.js" +import { authStore } from "../auth" import { devToolsEnabled } from "./devToolsEnabled.js" // Derive the current role of the logged-in user diff --git a/packages/client/src/stores/notification.ts b/packages/client/src/stores/notification.ts index 5e1a4774c1..fa28b9f40a 100644 --- a/packages/client/src/stores/notification.ts +++ b/packages/client/src/stores/notification.ts @@ -25,7 +25,6 @@ const createNotificationStore = () => { return } - // @ts-expect-error if (get(routeStore).queryParams?.peek) { window.parent.postMessage({ type: "notification", From 1b6dc51f018c80938c8f45aaf2852734f3981076 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 11:51:38 +0100 Subject: [PATCH 135/173] Type routes --- .../src/stores/{routes.js => routes.ts} | 30 ++++++++++++++----- packages/types/src/documents/app/screen.ts | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) rename packages/client/src/stores/{routes.js => routes.ts} (82%) diff --git a/packages/client/src/stores/routes.js b/packages/client/src/stores/routes.ts similarity index 82% rename from packages/client/src/stores/routes.js rename to packages/client/src/stores/routes.ts index 8e318af2e3..3f200a9c88 100644 --- a/packages/client/src/stores/routes.js +++ b/packages/client/src/stores/routes.ts @@ -4,8 +4,24 @@ import { API } from "api" import { peekStore } from "./peek" import { builderStore } from "./builder" +interface Route { + path: string + screenId: string +} + +interface StoreType { + routes: Route[] + routeParams: {} + activeRoute?: Route | null + routeSessionId: number + routerLoaded: boolean + queryParams?: { + peek?: boolean + } +} + const createRouteStore = () => { - const initialState = { + const initialState: StoreType = { routes: [], routeParams: {}, activeRoute: null, @@ -22,7 +38,7 @@ const createRouteStore = () => { } catch (error) { routeConfig = null } - let routes = [] + const routes: Route[] = [] Object.values(routeConfig?.routes || {}).forEach(route => { Object.entries(route.subpaths || {}).forEach(([path, config]) => { routes.push({ @@ -43,13 +59,13 @@ const createRouteStore = () => { return state }) } - const setRouteParams = routeParams => { + const setRouteParams = (routeParams: StoreType["routeParams"]) => { store.update(state => { state.routeParams = routeParams return state }) } - const setQueryParams = queryParams => { + const setQueryParams = (queryParams: { peek?: boolean }) => { store.update(state => { state.queryParams = { ...queryParams, @@ -60,13 +76,13 @@ const createRouteStore = () => { return state }) } - const setActiveRoute = route => { + const setActiveRoute = (route: string) => { store.update(state => { state.activeRoute = state.routes.find(x => x.path === route) return state }) } - const navigate = (url, peek, externalNewTab) => { + const navigate = (url: string, peek: boolean, externalNewTab: boolean) => { if (get(builderStore).inBuilder) { return } @@ -93,7 +109,7 @@ const createRouteStore = () => { const setRouterLoaded = () => { store.update(state => ({ ...state, routerLoaded: true })) } - const createFullURL = relativeURL => { + const createFullURL = (relativeURL: string) => { if (!relativeURL?.startsWith("/")) { return relativeURL } diff --git a/packages/types/src/documents/app/screen.ts b/packages/types/src/documents/app/screen.ts index b2cedf31a9..e85fd5953b 100644 --- a/packages/types/src/documents/app/screen.ts +++ b/packages/types/src/documents/app/screen.ts @@ -36,6 +36,7 @@ export type ScreenRoutingJson = Record< subpaths: Record< string, { + screenId: string screens: Record } > From 59bdd201585b90c1e87e6cfaa7b82becf2a3ef01 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 12:12:43 +0100 Subject: [PATCH 136/173] Type onError --- packages/frontend-core/src/api/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/api/types.ts b/packages/frontend-core/src/api/types.ts index 0db1049591..940927f499 100644 --- a/packages/frontend-core/src/api/types.ts +++ b/packages/frontend-core/src/api/types.ts @@ -46,7 +46,7 @@ export type Headers = Record export type APIClientConfig = { enableCaching?: boolean attachHeaders?: (headers: Headers) => void - onError?: (error: any) => void + onError?: (error: APIError) => void onMigrationDetected?: (migration: string) => void } From e6c45d934b70ae496a8827b5f17d75cc5c8af5b8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 12:39:44 +0100 Subject: [PATCH 137/173] Stringify api errors --- packages/frontend-core/src/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/api/index.ts b/packages/frontend-core/src/api/index.ts index f7b05c338a..44e85e5a68 100644 --- a/packages/frontend-core/src/api/index.ts +++ b/packages/frontend-core/src/api/index.ts @@ -74,7 +74,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => { if (json?.message) { message = json.message } else if (json?.error) { - message = json.error + message = JSON.stringify(json.error) } } catch (error) { // Do nothing From 2cbf7a47c16194741d49dc654d1d0ea059c3d54d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 12:40:23 +0100 Subject: [PATCH 138/173] Type --- packages/frontend-core/src/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/api/index.ts b/packages/frontend-core/src/api/index.ts index 44e85e5a68..b0e1970e6f 100644 --- a/packages/frontend-core/src/api/index.ts +++ b/packages/frontend-core/src/api/index.ts @@ -226,7 +226,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => { return await handler(callConfig) } catch (error) { if (config?.onError) { - config.onError(error) + config.onError(error as APIError) } throw error } From 9fade65b4a3895c7ab0609b0654d5ac3d44d455d Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 9 Jan 2025 11:46:45 +0000 Subject: [PATCH 139/173] Update pro reference. --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 71922a7d97..15b7f0907e 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 71922a7d979ddca6f51d9e450abcd81ba9a5b6fa +Subproject commit 15b7f0907e66e4144338404bb071bc1ccfc98137 From 2b90d972b21325608f0f1e4f51d0d1a850be2e26 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 12:50:19 +0100 Subject: [PATCH 140/173] Clean code --- packages/frontend-core/src/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/api/index.ts b/packages/frontend-core/src/api/index.ts index b0e1970e6f..92dc2d9ea3 100644 --- a/packages/frontend-core/src/api/index.ts +++ b/packages/frontend-core/src/api/index.ts @@ -68,7 +68,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => { ): Promise => { // Try to read a message from the error let message = response.statusText - let json: any = null + let json = null try { json = await response.json() if (json?.message) { From 71c6480c1b3ea08cd69bc8a0cfe015aadbaa773b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 13:00:02 +0100 Subject: [PATCH 141/173] Remove unused function --- packages/frontend-core/src/api/index.ts | 6 +----- packages/frontend-core/src/api/types.ts | 3 +-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/frontend-core/src/api/index.ts b/packages/frontend-core/src/api/index.ts index 92dc2d9ea3..6efc90023a 100644 --- a/packages/frontend-core/src/api/index.ts +++ b/packages/frontend-core/src/api/index.ts @@ -93,7 +93,7 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => { // Generates an error object from a string const makeError = ( message: string, - url?: string, + url: string, method?: HTTPMethod ): APIError => { return { @@ -239,13 +239,9 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => { patch: requestApiCall(HTTPMethod.PATCH), delete: requestApiCall(HTTPMethod.DELETE), put: requestApiCall(HTTPMethod.PUT), - error: (message: string) => { - throw makeError(message) - }, invalidateCache: () => { cache = {} }, - // Generic utility to extract the current app ID. Assumes that any client // that exists in an app context will be attaching our app ID header. getAppID: (): string => { diff --git a/packages/frontend-core/src/api/types.ts b/packages/frontend-core/src/api/types.ts index 940927f499..4819b4cd3b 100644 --- a/packages/frontend-core/src/api/types.ts +++ b/packages/frontend-core/src/api/types.ts @@ -86,14 +86,13 @@ export type BaseAPIClient = { patch: ( params: APICallParams ) => Promise - error: (message: string) => void invalidateCache: () => void getAppID: () => string } export type APIError = { message?: string - url?: string + url: string method?: HTTPMethod json: any status: number From ace5099a8cf25f6eb73878d295568cb4130ea344 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 9 Jan 2025 12:05:45 +0000 Subject: [PATCH 142/173] Update pro reference. --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 23fdd50b7e..193476cdfa 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 23fdd50b7ef28cf320716ed2c46e15d63185daa7 +Subproject commit 193476cdfade6d3c613e6972f16ee0c527e01ff6 From 70a8b9e4688249211f5e9d56463e3524a97b2539 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 13:55:00 +0100 Subject: [PATCH 143/173] Remove screen id --- packages/types/src/documents/app/screen.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/types/src/documents/app/screen.ts b/packages/types/src/documents/app/screen.ts index e85fd5953b..b2cedf31a9 100644 --- a/packages/types/src/documents/app/screen.ts +++ b/packages/types/src/documents/app/screen.ts @@ -36,7 +36,6 @@ export type ScreenRoutingJson = Record< subpaths: Record< string, { - screenId: string screens: Record } > From 88e245a5bb7a97eedfc07ea6104e44c5d2dfbd2a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 14:01:07 +0100 Subject: [PATCH 144/173] Fix typing --- packages/types/src/documents/app/screen.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/types/src/documents/app/screen.ts b/packages/types/src/documents/app/screen.ts index b2cedf31a9..a8c32118d3 100644 --- a/packages/types/src/documents/app/screen.ts +++ b/packages/types/src/documents/app/screen.ts @@ -33,11 +33,6 @@ export interface ScreenRoutesViewOutput extends Document { export type ScreenRoutingJson = Record< string, { - subpaths: Record< - string, - { - screens: Record - } - > + subpaths: Record } > From 02b20f1102ebc05f3c292eae68df8c8a9e2b7417 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 14:24:59 +0100 Subject: [PATCH 145/173] Fix getSchema from forms --- packages/client/src/utils/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index ffab142cf3..4a65d2d099 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -52,7 +52,7 @@ export const fetchDatasourceSchema = async ( // Get the normal schema as long as we aren't wanting a form schema let schema if (datasource?.type !== "query" || !options?.formSchema) { - schema = instance.getSchema(datasource, definition) + schema = instance.getSchema(definition) } else if (definition.parameters?.length) { schema = {} definition.parameters.forEach(param => { From ff0a25f0ffadf727418f757736fcc0b6091ff412 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 14:32:15 +0100 Subject: [PATCH 146/173] Pass datasource to instance --- packages/client/src/utils/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 4a65d2d099..60800afc53 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -31,7 +31,7 @@ const getDatasourceFetchInstance = datasource => { if (!handler) { return null } - return new handler({ API }) + return new handler({ API, datasource }) } /** From a5ec51028099325a288ab9fc4bca5e1978d634cb Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 15:58:59 +0100 Subject: [PATCH 147/173] Explicitly fetch the data from fetch --- packages/frontend-core/src/fetch/DataFetch.ts | 3 --- packages/frontend-core/src/fetch/index.ts | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 9312c57637..0079fec057 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -179,9 +179,6 @@ export default abstract class DataFetch< this.store.update($store => ({ ...$store, loaded: true })) return } - - // Initially fetch data but don't bother waiting for the result - this.getInitialData() } /** diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 4accb0b5ec..c1f35abef2 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -33,7 +33,12 @@ const DataFetchMap = { export const fetchData = ({ API, datasource, options }: any) => { const Fetch = DataFetchMap[datasource?.type as keyof typeof DataFetchMap] || TableFetch - return new Fetch({ API, datasource, ...options }) + const fetch = new Fetch({ API, datasource, ...options }) + + // Initially fetch data but don't bother waiting for the result + fetch.getInitialData() + + return fetch } // Creates an empty fetch instance with no datasource configured, so no data From 5c933c7f80ef4f0e631fafed7dc16d8691823079 Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Thu, 9 Jan 2025 16:27:59 +0000 Subject: [PATCH 148/173] Revert "Fix issue with forms after cleanup" --- packages/client/src/utils/schema.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 60800afc53..ffab142cf3 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -31,7 +31,7 @@ const getDatasourceFetchInstance = datasource => { if (!handler) { return null } - return new handler({ API, datasource }) + return new handler({ API }) } /** @@ -52,7 +52,7 @@ export const fetchDatasourceSchema = async ( // Get the normal schema as long as we aren't wanting a form schema let schema if (datasource?.type !== "query" || !options?.formSchema) { - schema = instance.getSchema(definition) + schema = instance.getSchema(datasource, definition) } else if (definition.parameters?.length) { schema = {} definition.parameters.forEach(param => { From 40192097d819564573343d47cd85a63b00d8be39 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 14:32:15 +0100 Subject: [PATCH 149/173] Pass datasource to instance --- packages/client/src/utils/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index ffab142cf3..988c2e3316 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -31,7 +31,7 @@ const getDatasourceFetchInstance = datasource => { if (!handler) { return null } - return new handler({ API }) + return new handler({ API, datasource }) } /** From cbad9303d962f3b118186099aaf5c50f092b9668 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 14:24:59 +0100 Subject: [PATCH 150/173] Fix getSchema from forms --- packages/client/src/utils/schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 988c2e3316..60800afc53 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -52,7 +52,7 @@ export const fetchDatasourceSchema = async ( // Get the normal schema as long as we aren't wanting a form schema let schema if (datasource?.type !== "query" || !options?.formSchema) { - schema = instance.getSchema(datasource, definition) + schema = instance.getSchema(definition) } else if (definition.parameters?.length) { schema = {} definition.parameters.forEach(param => { From aadc4da0b124cbdeaae04f85a008f41160dcb67e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 10:15:34 +0100 Subject: [PATCH 151/173] Remove duplicated utils --- .../src/components/grid/lib/utils.js | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 packages/frontend-core/src/components/grid/lib/utils.js diff --git a/packages/frontend-core/src/components/grid/lib/utils.js b/packages/frontend-core/src/components/grid/lib/utils.js deleted file mode 100644 index ee74a14bf0..0000000000 --- a/packages/frontend-core/src/components/grid/lib/utils.js +++ /dev/null @@ -1,32 +0,0 @@ -// TODO: remove when all stores are typed - -import { GeneratedIDPrefix, CellIDSeparator } from "./constants" -import { Helpers } from "@budibase/bbui" - -export const parseCellID = cellId => { - if (!cellId) { - return { rowId: undefined, field: undefined } - } - const parts = cellId.split(CellIDSeparator) - const field = parts.pop() - return { rowId: parts.join(CellIDSeparator), field } -} - -export const getCellID = (rowId, fieldName) => { - return `${rowId}${CellIDSeparator}${fieldName}` -} - -export const parseEventLocation = e => { - return { - x: e.clientX ?? e.touches?.[0]?.clientX, - y: e.clientY ?? e.touches?.[0]?.clientY, - } -} - -export const generateRowID = () => { - return `${GeneratedIDPrefix}${Helpers.uuid()}` -} - -export const isGeneratedRowID = id => { - return id?.startsWith(GeneratedIDPrefix) -} From 96052679cb5bbdda0b082ee6c471b6ce7cbaff06 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 10:26:24 +0100 Subject: [PATCH 152/173] Convert constants.js --- .../src/components/grid/lib/{constants.js => constants.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/frontend-core/src/components/grid/lib/{constants.js => constants.ts} (100%) diff --git a/packages/frontend-core/src/components/grid/lib/constants.js b/packages/frontend-core/src/components/grid/lib/constants.ts similarity index 100% rename from packages/frontend-core/src/components/grid/lib/constants.js rename to packages/frontend-core/src/components/grid/lib/constants.ts From bb1811558570b1f29d3bd064640c6249df818e81 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 10:26:56 +0100 Subject: [PATCH 153/173] Convert renderer --- .../grid/lib/{renderers.js => renderers.ts} | 18 ++++++++++++++---- packages/types/src/ui/stores/grid/columns.ts | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) rename packages/frontend-core/src/components/grid/lib/{renderers.js => renderers.ts} (82%) diff --git a/packages/frontend-core/src/components/grid/lib/renderers.js b/packages/frontend-core/src/components/grid/lib/renderers.ts similarity index 82% rename from packages/frontend-core/src/components/grid/lib/renderers.js rename to packages/frontend-core/src/components/grid/lib/renderers.ts index a860d01b53..b009806cc4 100644 --- a/packages/frontend-core/src/components/grid/lib/renderers.js +++ b/packages/frontend-core/src/components/grid/lib/renderers.ts @@ -1,4 +1,4 @@ -import { FieldType } from "@budibase/types" +import { FieldType, UIColumn } from "@budibase/types" import OptionsCell from "../cells/OptionsCell.svelte" import DateCell from "../cells/DateCell.svelte" @@ -40,13 +40,23 @@ const TypeComponentMap = { // Custom types for UI only role: RoleCell, } -export const getCellRenderer = column => { + +function getCellRendererByType(type: FieldType | "role" | undefined) { + if (!type) { + return + } + + return TypeComponentMap[type as keyof typeof TypeComponentMap] +} + +export const getCellRenderer = (column: UIColumn) => { if (column.calculationType) { return NumberCell } + return ( - TypeComponentMap[column?.schema?.cellRenderType] || - TypeComponentMap[column?.schema?.type] || + getCellRendererByType(column.schema?.cellRenderType) || + getCellRendererByType(column.schema?.type) || TextCell ) } diff --git a/packages/types/src/ui/stores/grid/columns.ts b/packages/types/src/ui/stores/grid/columns.ts index 7f20145246..2517d2a3e0 100644 --- a/packages/types/src/ui/stores/grid/columns.ts +++ b/packages/types/src/ui/stores/grid/columns.ts @@ -14,6 +14,7 @@ export type UIColumn = FieldSchema & { type: FieldType readonly: boolean autocolumn: boolean + cellRenderType?: FieldType | "role" } calculationType: CalculationType __idx: number From e23be5acb8ccb0d0425b39d14180817355bc7e6c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 10:30:19 +0100 Subject: [PATCH 154/173] Websocket to ts --- .../components/grid/lib/{websocket.js => websocket.ts} | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) rename packages/frontend-core/src/components/grid/lib/{websocket.js => websocket.ts} (89%) diff --git a/packages/frontend-core/src/components/grid/lib/websocket.js b/packages/frontend-core/src/components/grid/lib/websocket.ts similarity index 89% rename from packages/frontend-core/src/components/grid/lib/websocket.js rename to packages/frontend-core/src/components/grid/lib/websocket.ts index e7b89ff58a..437b93270d 100644 --- a/packages/frontend-core/src/components/grid/lib/websocket.js +++ b/packages/frontend-core/src/components/grid/lib/websocket.ts @@ -1,12 +1,14 @@ import { get } from "svelte/store" import { createWebsocket } from "../../../utils" import { SocketEvent, GridSocketEvent } from "@budibase/shared-core" +import { Store } from "../stores" +import { UIDatasource } from "@budibase/types" -export const createGridWebsocket = context => { +export const createGridWebsocket = (context: Store) => { const { rows, datasource, users, focusedCellId, definition, API } = context const socket = createWebsocket("/socket/grid") - const connectToDatasource = datasource => { + const connectToDatasource = (datasource: UIDatasource) => { if (!socket.connected) { return } @@ -65,7 +67,7 @@ export const createGridWebsocket = context => { GridSocketEvent.DatasourceChange, ({ datasource: newDatasource }) => { // Listen builder renames, as these aren't handled otherwise - if (newDatasource?.name !== get(definition).name) { + if (newDatasource?.name !== get(definition)?.name) { definition.set(newDatasource) } } From 535f2d68031efcb84f51493644e2d6c2fa8d7de7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 10:45:35 +0100 Subject: [PATCH 155/173] Type --- packages/frontend-core/src/components/grid/lib/websocket.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend-core/src/components/grid/lib/websocket.ts b/packages/frontend-core/src/components/grid/lib/websocket.ts index 437b93270d..bc41d594f4 100644 --- a/packages/frontend-core/src/components/grid/lib/websocket.ts +++ b/packages/frontend-core/src/components/grid/lib/websocket.ts @@ -2,7 +2,7 @@ import { get } from "svelte/store" import { createWebsocket } from "../../../utils" import { SocketEvent, GridSocketEvent } from "@budibase/shared-core" import { Store } from "../stores" -import { UIDatasource } from "@budibase/types" +import { UIDatasource, UIUser } from "@budibase/types" export const createGridWebsocket = (context: Store) => { const { rows, datasource, users, focusedCellId, definition, API } = context @@ -20,7 +20,7 @@ export const createGridWebsocket = (context: Store) => { datasource, appId, }, - ({ users: gridUsers }) => { + ({ users: gridUsers }: { users: UIUser[] }) => { users.set(gridUsers) } ) From 7d9debd3191668da83dac17c0f0b551a17cea0b5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 14:49:07 +0100 Subject: [PATCH 156/173] Export DataFetchMap --- packages/frontend-core/src/fetch/index.ts | 14 +++++++------- packages/frontend-core/src/index.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index c1f35abef2..e343b351bc 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -1,18 +1,18 @@ -import TableFetch from "./TableFetch.js" -import ViewFetch from "./ViewFetch.js" -import ViewV2Fetch from "./ViewV2Fetch.js" +import TableFetch from "./TableFetch" +import ViewFetch from "./ViewFetch" +import ViewV2Fetch from "./ViewV2Fetch" import QueryFetch from "./QueryFetch" import RelationshipFetch from "./RelationshipFetch" import NestedProviderFetch from "./NestedProviderFetch" import FieldFetch from "./FieldFetch" import JSONArrayFetch from "./JSONArrayFetch" -import UserFetch from "./UserFetch.js" +import UserFetch from "./UserFetch" import GroupUserFetch from "./GroupUserFetch" import CustomFetch from "./CustomFetch" -import QueryArrayFetch from "./QueryArrayFetch.js" -import { APIClient } from "../api/types.js" +import QueryArrayFetch from "./QueryArrayFetch" +import { APIClient } from "../api/types" -const DataFetchMap = { +export const DataFetchMap = { table: TableFetch, view: ViewFetch, viewV2: ViewV2Fetch, diff --git a/packages/frontend-core/src/index.ts b/packages/frontend-core/src/index.ts index 37951dc776..5b24a9ac50 100644 --- a/packages/frontend-core/src/index.ts +++ b/packages/frontend-core/src/index.ts @@ -1,5 +1,5 @@ export { createAPIClient } from "./api" -export { fetchData } from "./fetch" +export { fetchData, DataFetchMap } from "./fetch" export * as Constants from "./constants" export * from "./stores" export * from "./utils" From 7df69f154a594a5250b511ef62de29a2063870ad Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 14:50:21 +0100 Subject: [PATCH 157/173] Basic ts conversion --- packages/client/src/sdk.js | 2 +- .../client/src/utils/{schema.js => schema.ts} | 24 +++---------------- 2 files changed, 4 insertions(+), 22 deletions(-) rename packages/client/src/utils/{schema.js => schema.ts} (73%) diff --git a/packages/client/src/sdk.js b/packages/client/src/sdk.js index 40d066f2ee..40f35b2ba7 100644 --- a/packages/client/src/sdk.js +++ b/packages/client/src/sdk.js @@ -29,7 +29,7 @@ import { ActionTypes } from "./constants" import { fetchDatasourceSchema, fetchDatasourceDefinition, -} from "./utils/schema.js" +} from "./utils/schema.ts" import { getAPIKey } from "./utils/api.js" import { enrichButtonActions } from "./utils/buttonActions.js" import { processStringSync, makePropSafe } from "@budibase/string-templates" diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.ts similarity index 73% rename from packages/client/src/utils/schema.js rename to packages/client/src/utils/schema.ts index 60800afc53..53b31b5495 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.ts @@ -1,13 +1,5 @@ import { API } from "api" -import TableFetch from "@budibase/frontend-core/src/fetch/TableFetch" -import ViewFetch from "@budibase/frontend-core/src/fetch/ViewFetch" -import QueryFetch from "@budibase/frontend-core/src/fetch/QueryFetch" -import RelationshipFetch from "@budibase/frontend-core/src/fetch/RelationshipFetch" -import NestedProviderFetch from "@budibase/frontend-core/src/fetch/NestedProviderFetch" -import FieldFetch from "@budibase/frontend-core/src/fetch/FieldFetch" -import JSONArrayFetch from "@budibase/frontend-core/src/fetch/JSONArrayFetch" -import ViewV2Fetch from "@budibase/frontend-core/src/fetch/ViewV2Fetch" -import QueryArrayFetch from "@budibase/frontend-core/src/fetch/QueryArrayFetch" +import { DataFetchMap } from "@budibase/frontend-core" /** * Constructs a fetch instance for a given datasource. @@ -16,18 +8,8 @@ import QueryArrayFetch from "@budibase/frontend-core/src/fetch/QueryArrayFetch" * @param datasource the datasource * @returns */ -const getDatasourceFetchInstance = datasource => { - const handler = { - table: TableFetch, - view: ViewFetch, - viewV2: ViewV2Fetch, - query: QueryFetch, - link: RelationshipFetch, - provider: NestedProviderFetch, - field: FieldFetch, - jsonarray: JSONArrayFetch, - queryarray: QueryArrayFetch, - }[datasource?.type] +const getDatasourceFetchInstance = (datasource: { type: string }) => { + const handler = DataFetchMap[datasource?.type] if (!handler) { return null } From e25f26d28d9d41bb2e46f7e0823e87b19c3c3986 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 15:04:56 +0100 Subject: [PATCH 158/173] Reuse type --- packages/frontend-core/src/fetch/index.ts | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index e343b351bc..21832e3ede 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -12,6 +12,8 @@ import CustomFetch from "./CustomFetch" import QueryArrayFetch from "./QueryArrayFetch" import { APIClient } from "../api/types" +export type DataFetchType = keyof typeof DataFetchMap + export const DataFetchMap = { table: TableFetch, view: ViewFetch, @@ -31,8 +33,7 @@ export const DataFetchMap = { // Constructs a new fetch model for a certain datasource export const fetchData = ({ API, datasource, options }: any) => { - const Fetch = - DataFetchMap[datasource?.type as keyof typeof DataFetchMap] || TableFetch + const Fetch = DataFetchMap[datasource?.type as DataFetchType] || TableFetch const fetch = new Fetch({ API, datasource, ...options }) // Initially fetch data but don't bother waiting for the result @@ -43,18 +44,14 @@ export const fetchData = ({ API, datasource, options }: any) => { // Creates an empty fetch instance with no datasource configured, so no data // will initially be loaded -const createEmptyFetchInstance = < - TDatasource extends { - type: keyof typeof DataFetchMap - } ->({ +const createEmptyFetchInstance = ({ API, datasource, }: { API: APIClient datasource: TDatasource }) => { - const handler = DataFetchMap[datasource?.type as keyof typeof DataFetchMap] + const handler = DataFetchMap[datasource?.type as DataFetchType] if (!handler) { return null } @@ -63,9 +60,7 @@ const createEmptyFetchInstance = < // Fetches the definition of any type of datasource export const getDatasourceDefinition = async < - TDatasource extends { - type: keyof typeof DataFetchMap - } + TDatasource extends { type: DataFetchType } >({ API, datasource, @@ -79,9 +74,7 @@ export const getDatasourceDefinition = async < // Fetches the schema of any type of datasource export const getDatasourceSchema = < - TDatasource extends { - type: keyof typeof DataFetchMap - } + TDatasource extends { type: DataFetchType } >({ API, datasource, From 4f06592685522e7d1d58af1a43e7549b24e9002a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 15:23:20 +0100 Subject: [PATCH 159/173] Use trimmed and typed datasources --- packages/frontend-core/src/fetch/DataFetch.ts | 3 ++- packages/frontend-core/src/fetch/FieldFetch.ts | 9 ++++++--- packages/frontend-core/src/fetch/GroupUserFetch.ts | 2 ++ packages/frontend-core/src/fetch/JSONArrayFetch.ts | 2 +- .../frontend-core/src/fetch/NestedProviderFetch.ts | 1 + packages/frontend-core/src/fetch/QueryArrayFetch.ts | 2 +- packages/frontend-core/src/fetch/QueryFetch.ts | 1 + .../frontend-core/src/fetch/RelationshipFetch.ts | 1 + packages/frontend-core/src/fetch/TableFetch.ts | 9 +++++++-- packages/frontend-core/src/fetch/UserFetch.ts | 8 ++++++-- packages/frontend-core/src/fetch/ViewFetch.ts | 11 +++++++++-- packages/frontend-core/src/fetch/ViewV2Fetch.ts | 12 ++++++++++-- packages/frontend-core/src/fetch/index.ts | 8 ++++++-- packages/frontend-core/src/index.ts | 1 + 14 files changed, 54 insertions(+), 16 deletions(-) diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 0079fec057..8f475339b4 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -13,6 +13,7 @@ import { UISearchFilter, } from "@budibase/types" import { APIClient } from "../api/types" +import { DataFetchType } from "." const { buildQuery, limit: queryLimit, runQuery, sort } = QueryUtils @@ -59,7 +60,7 @@ export interface DataFetchParams< * For other types of datasource, this class is overridden and extended. */ export default abstract class DataFetch< - TDatasource extends {}, + TDatasource extends { type: DataFetchType }, TDefinition extends { schema?: Record | null primaryDisplay?: string diff --git a/packages/frontend-core/src/fetch/FieldFetch.ts b/packages/frontend-core/src/fetch/FieldFetch.ts index ac1e683c51..694443a5dc 100644 --- a/packages/frontend-core/src/fetch/FieldFetch.ts +++ b/packages/frontend-core/src/fetch/FieldFetch.ts @@ -1,7 +1,10 @@ import { Row } from "@budibase/types" import DataFetch from "./DataFetch" -export interface FieldDatasource { +type Types = "field" | "queryarray" | "jsonarray" + +export interface FieldDatasource { + type: TType tableId: string fieldType: "attachment" | "array" value: string[] | Row[] @@ -15,8 +18,8 @@ function isArrayOfStrings(value: string[] | Row[]): value is string[] { return Array.isArray(value) && !!value[0] && typeof value[0] !== "object" } -export default class FieldFetch extends DataFetch< - FieldDatasource, +export default class FieldFetch extends DataFetch< + FieldDatasource, FieldDefinition > { async getDefinition(): Promise { diff --git a/packages/frontend-core/src/fetch/GroupUserFetch.ts b/packages/frontend-core/src/fetch/GroupUserFetch.ts index a14623bfb0..e07e5331d4 100644 --- a/packages/frontend-core/src/fetch/GroupUserFetch.ts +++ b/packages/frontend-core/src/fetch/GroupUserFetch.ts @@ -8,6 +8,7 @@ interface GroupUserQuery { } interface GroupUserDatasource { + type: "groupUser" tableId: TableNames.USERS } @@ -20,6 +21,7 @@ export default class GroupUserFetch extends DataFetch< super({ ...opts, datasource: { + type: "groupUser", tableId: TableNames.USERS, }, }) diff --git a/packages/frontend-core/src/fetch/JSONArrayFetch.ts b/packages/frontend-core/src/fetch/JSONArrayFetch.ts index cae9a1e521..d746c923f8 100644 --- a/packages/frontend-core/src/fetch/JSONArrayFetch.ts +++ b/packages/frontend-core/src/fetch/JSONArrayFetch.ts @@ -1,7 +1,7 @@ import FieldFetch from "./FieldFetch" import { getJSONArrayDatasourceSchema } from "../utils/json" -export default class JSONArrayFetch extends FieldFetch { +export default class JSONArrayFetch extends FieldFetch<"jsonarray"> { async getDefinition() { const { datasource } = this.options diff --git a/packages/frontend-core/src/fetch/NestedProviderFetch.ts b/packages/frontend-core/src/fetch/NestedProviderFetch.ts index 666340610f..af121fcef8 100644 --- a/packages/frontend-core/src/fetch/NestedProviderFetch.ts +++ b/packages/frontend-core/src/fetch/NestedProviderFetch.ts @@ -2,6 +2,7 @@ import { Row, TableSchema } from "@budibase/types" import DataFetch from "./DataFetch" interface NestedProviderDatasource { + type: "provider" value?: { schema: TableSchema primaryDisplay: string diff --git a/packages/frontend-core/src/fetch/QueryArrayFetch.ts b/packages/frontend-core/src/fetch/QueryArrayFetch.ts index 9142000fe6..7f4d34aaa6 100644 --- a/packages/frontend-core/src/fetch/QueryArrayFetch.ts +++ b/packages/frontend-core/src/fetch/QueryArrayFetch.ts @@ -4,7 +4,7 @@ import { generateQueryArraySchemas, } from "../utils/json" -export default class QueryArrayFetch extends FieldFetch { +export default class QueryArrayFetch extends FieldFetch<"queryarray"> { async getDefinition() { const { datasource } = this.options diff --git a/packages/frontend-core/src/fetch/QueryFetch.ts b/packages/frontend-core/src/fetch/QueryFetch.ts index 0754edd267..09dde86cbd 100644 --- a/packages/frontend-core/src/fetch/QueryFetch.ts +++ b/packages/frontend-core/src/fetch/QueryFetch.ts @@ -4,6 +4,7 @@ import { ExecuteQueryRequest, Query } from "@budibase/types" import { get } from "svelte/store" interface QueryDatasource { + type: "query" _id: string fields: Record & { pagination?: { diff --git a/packages/frontend-core/src/fetch/RelationshipFetch.ts b/packages/frontend-core/src/fetch/RelationshipFetch.ts index f853a753cd..89a85ab0e4 100644 --- a/packages/frontend-core/src/fetch/RelationshipFetch.ts +++ b/packages/frontend-core/src/fetch/RelationshipFetch.ts @@ -2,6 +2,7 @@ import { Table } from "@budibase/types" import DataFetch from "./DataFetch" interface RelationshipDatasource { + type: "link" tableId: string rowId: string rowTableId: string diff --git a/packages/frontend-core/src/fetch/TableFetch.ts b/packages/frontend-core/src/fetch/TableFetch.ts index f5927262cb..67cac6b6a7 100644 --- a/packages/frontend-core/src/fetch/TableFetch.ts +++ b/packages/frontend-core/src/fetch/TableFetch.ts @@ -1,8 +1,13 @@ import { get } from "svelte/store" import DataFetch from "./DataFetch" -import { SortOrder, Table, UITable } from "@budibase/types" +import { SortOrder, Table } from "@budibase/types" -export default class TableFetch extends DataFetch { +interface TableDatasource { + type: "table" + tableId: string +} + +export default class TableFetch extends DataFetch { async determineFeatureFlags() { return { supportsSearch: true, diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 656cd840fe..54147fbccf 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -14,18 +14,22 @@ interface UserFetchQuery { } interface UserDatasource { - tableId: string + type: "user" + tableId: TableNames.USERS } +interface UserDefinition {} + export default class UserFetch extends DataFetch< UserDatasource, - {}, + UserDefinition, UserFetchQuery > { constructor(opts: DataFetchParams) { super({ ...opts, datasource: { + type: "user", tableId: TableNames.USERS, }, }) diff --git a/packages/frontend-core/src/fetch/ViewFetch.ts b/packages/frontend-core/src/fetch/ViewFetch.ts index b6830e7118..c075d80ce0 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.ts +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -1,7 +1,14 @@ -import { Table, View } from "@budibase/types" +import { Table } from "@budibase/types" import DataFetch from "./DataFetch" -type ViewV1 = View & { name: string } +type ViewV1 = { + type: "view" + name: string + tableId: string + calculation: string + field: string + groupBy: string +} export default class ViewFetch extends DataFetch { async getDefinition() { diff --git a/packages/frontend-core/src/fetch/ViewV2Fetch.ts b/packages/frontend-core/src/fetch/ViewV2Fetch.ts index cdd3bab6ed..aa5fbd60a2 100644 --- a/packages/frontend-core/src/fetch/ViewV2Fetch.ts +++ b/packages/frontend-core/src/fetch/ViewV2Fetch.ts @@ -1,9 +1,17 @@ -import { SortOrder, UIView, ViewV2, ViewV2Type } from "@budibase/types" +import { SortOrder, ViewV2Enriched, ViewV2Type } from "@budibase/types" import DataFetch from "./DataFetch" import { get } from "svelte/store" import { helpers } from "@budibase/shared-core" -export default class ViewV2Fetch extends DataFetch { +interface ViewDatasource { + type: "viewV2" + id: string +} + +export default class ViewV2Fetch extends DataFetch< + ViewDatasource, + ViewV2Enriched +> { async determineFeatureFlags() { return { supportsSearch: true, diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index 21832e3ede..d80aa10df6 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -26,7 +26,7 @@ export const DataFetchMap = { // Client specific datasource types provider: NestedProviderFetch, - field: FieldFetch, + field: FieldFetch<"field">, jsonarray: JSONArrayFetch, queryarray: QueryArrayFetch, } @@ -55,7 +55,11 @@ const createEmptyFetchInstance = ({ if (!handler) { return null } - return new handler({ API, datasource: null as any, query: null as any }) + return new handler({ + API, + datasource: null as never, + query: null as any, + }) } // Fetches the definition of any type of datasource diff --git a/packages/frontend-core/src/index.ts b/packages/frontend-core/src/index.ts index 5b24a9ac50..c0baa63ab6 100644 --- a/packages/frontend-core/src/index.ts +++ b/packages/frontend-core/src/index.ts @@ -1,5 +1,6 @@ export { createAPIClient } from "./api" export { fetchData, DataFetchMap } from "./fetch" +export type { DataFetchType } from "./fetch" export * as Constants from "./constants" export * from "./stores" export * from "./utils" From eb73370460f9b3fb98303f086bf21e29a1ae9bc7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 9 Jan 2025 15:35:16 +0100 Subject: [PATCH 160/173] Fix types --- packages/client/src/utils/schema.ts | 56 +++++++++++++------ packages/frontend-core/src/fetch/DataFetch.ts | 2 +- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/packages/client/src/utils/schema.ts b/packages/client/src/utils/schema.ts index 53b31b5495..5400d62087 100644 --- a/packages/client/src/utils/schema.ts +++ b/packages/client/src/utils/schema.ts @@ -1,5 +1,5 @@ import { API } from "api" -import { DataFetchMap } from "@budibase/frontend-core" +import { DataFetchMap, DataFetchType } from "@budibase/frontend-core" /** * Constructs a fetch instance for a given datasource. @@ -8,12 +8,20 @@ import { DataFetchMap } from "@budibase/frontend-core" * @param datasource the datasource * @returns */ -const getDatasourceFetchInstance = (datasource: { type: string }) => { +const getDatasourceFetchInstance = < + TDatasource extends { type: DataFetchType } +>( + datasource: TDatasource +) => { const handler = DataFetchMap[datasource?.type] if (!handler) { return null } - return new handler({ API, datasource }) + return new handler({ + API, + datasource: datasource as never, + query: null as any, + }) } /** @@ -21,21 +29,23 @@ const getDatasourceFetchInstance = (datasource: { type: string }) => { * @param datasource the datasource to fetch the schema for * @param options options for enriching the schema */ -export const fetchDatasourceSchema = async ( - datasource, +export const fetchDatasourceSchema = async < + TDatasource extends { type: DataFetchType } +>( + datasource: TDatasource, options = { enrichRelationships: false, formSchema: false } ) => { const instance = getDatasourceFetchInstance(datasource) - const definition = await instance?.getDefinition(datasource) - if (!definition) { + const definition = await instance?.getDefinition() + if (!instance || !definition) { return null } // Get the normal schema as long as we aren't wanting a form schema - let schema + let schema: any if (datasource?.type !== "query" || !options?.formSchema) { - schema = instance.getSchema(definition) - } else if (definition.parameters?.length) { + schema = instance.getSchema(definition as any) + } else if ("parameters" in definition && definition.parameters?.length) { schema = {} definition.parameters.forEach(param => { schema[param.name] = { ...param, type: "string" } @@ -55,7 +65,12 @@ export const fetchDatasourceSchema = async ( } // Enrich schema with relationships if required - if (definition?.sql && options?.enrichRelationships) { + if ( + definition && + "sql" in definition && + definition.sql && + options?.enrichRelationships + ) { const relationshipAdditions = await getRelationshipSchemaAdditions(schema) schema = { ...schema, @@ -71,20 +86,26 @@ export const fetchDatasourceSchema = async ( * Fetches the definition of any kind of datasource. * @param datasource the datasource to fetch the schema for */ -export const fetchDatasourceDefinition = async datasource => { +export const fetchDatasourceDefinition = async < + TDatasource extends { type: DataFetchType } +>( + datasource: TDatasource +) => { const instance = getDatasourceFetchInstance(datasource) - return await instance?.getDefinition(datasource) + return await instance?.getDefinition() } /** * Fetches the schema of relationship fields for a SQL table schema * @param schema the schema to enrich */ -export const getRelationshipSchemaAdditions = async schema => { +export const getRelationshipSchemaAdditions = async ( + schema: Record +) => { if (!schema) { return null } - let relationshipAdditions = {} + let relationshipAdditions: Record = {} for (let fieldKey of Object.keys(schema)) { const fieldSchema = schema[fieldKey] if (fieldSchema?.type === "link") { @@ -92,7 +113,10 @@ export const getRelationshipSchemaAdditions = async schema => { type: "table", tableId: fieldSchema?.tableId, }) - Object.keys(linkSchema || {}).forEach(linkKey => { + if (!linkSchema) { + continue + } + Object.keys(linkSchema).forEach(linkKey => { relationshipAdditions[`${fieldKey}.${linkKey}`] = { type: linkSchema[linkKey].type, externalType: linkSchema[linkKey].externalType, diff --git a/packages/frontend-core/src/fetch/DataFetch.ts b/packages/frontend-core/src/fetch/DataFetch.ts index 8f475339b4..b10a8b0a69 100644 --- a/packages/frontend-core/src/fetch/DataFetch.ts +++ b/packages/frontend-core/src/fetch/DataFetch.ts @@ -369,7 +369,7 @@ export default abstract class DataFetch< * @param schema the datasource schema * @return {object} the enriched datasource schema */ - private enrichSchema(schema: TableSchema): TableSchema { + enrichSchema(schema: TableSchema): TableSchema { // Check for any JSON fields so we can add any top level properties let jsonAdditions: Record = {} for (const fieldKey of Object.keys(schema)) { From be41a2ae6c2c087deea46c2d8b1861c7448afec2 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 10:07:45 +0100 Subject: [PATCH 161/173] Add type to customDatasource --- packages/frontend-core/src/fetch/CustomFetch.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend-core/src/fetch/CustomFetch.ts b/packages/frontend-core/src/fetch/CustomFetch.ts index afd3d18ba9..dfd29c4a02 100644 --- a/packages/frontend-core/src/fetch/CustomFetch.ts +++ b/packages/frontend-core/src/fetch/CustomFetch.ts @@ -1,6 +1,7 @@ import DataFetch from "./DataFetch" interface CustomDatasource { + type: "custom" data: any } From 8520ad2aeb9cc0424301950cebd0bc8a597bb2e4 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 10 Jan 2025 11:31:14 +0000 Subject: [PATCH 162/173] convert queries store to typescript --- .../builder/src/stores/builder/queries.js | 130 --------------- .../builder/src/stores/builder/queries.ts | 156 ++++++++++++++++++ 2 files changed, 156 insertions(+), 130 deletions(-) delete mode 100644 packages/builder/src/stores/builder/queries.js create mode 100644 packages/builder/src/stores/builder/queries.ts diff --git a/packages/builder/src/stores/builder/queries.js b/packages/builder/src/stores/builder/queries.js deleted file mode 100644 index 7aeb9ff8fd..0000000000 --- a/packages/builder/src/stores/builder/queries.js +++ /dev/null @@ -1,130 +0,0 @@ -import { writable, get, derived } from "svelte/store" -import { datasources } from "./datasources" -import { integrations } from "./integrations" -import { API } from "@/api" -import { duplicateName } from "@/helpers/duplicate" - -const sortQueries = queryList => { - queryList.sort((q1, q2) => { - return q1.name.localeCompare(q2.name) - }) -} - -export function createQueriesStore() { - const store = writable({ - list: [], - selectedQueryId: null, - }) - const derivedStore = derived(store, $store => ({ - ...$store, - selected: $store.list?.find(q => q._id === $store.selectedQueryId), - })) - - const fetch = async () => { - const queries = await API.getQueries() - sortQueries(queries) - store.update(state => ({ - ...state, - list: queries, - })) - } - - const save = async (datasourceId, query) => { - const _integrations = get(integrations) - const dataSource = get(datasources).list.filter( - ds => ds._id === datasourceId - ) - // Check if readable attribute is found - if (dataSource.length !== 0) { - const integration = _integrations[dataSource[0].source] - const readable = integration.query[query.queryVerb].readable - if (readable) { - query.readable = readable - } - } - query.datasourceId = datasourceId - const savedQuery = await API.saveQuery(query) - store.update(state => { - const idx = state.list.findIndex(query => query._id === savedQuery._id) - const queries = state.list - if (idx >= 0) { - queries.splice(idx, 1, savedQuery) - } else { - queries.push(savedQuery) - } - sortQueries(queries) - return { - list: queries, - selectedQueryId: savedQuery._id, - } - }) - return savedQuery - } - - const importQueries = async ({ data, datasourceId }) => { - return await API.importQueries(datasourceId, data) - } - - const select = id => { - store.update(state => ({ - ...state, - selectedQueryId: id, - })) - } - - const preview = async query => { - const result = await API.previewQuery(query) - // Assume all the fields are strings and create a basic schema from the - // unique fields returned by the server - const schema = {} - for (let [field, metadata] of Object.entries(result.schema)) { - schema[field] = metadata || { type: "string" } - } - return { ...result, schema, rows: result.rows || [] } - } - - const deleteQuery = async query => { - await API.deleteQuery(query._id, query._rev) - store.update(state => { - state.list = state.list.filter(existing => existing._id !== query._id) - return state - }) - } - - const duplicate = async query => { - let list = get(store).list - const newQuery = { ...query } - const datasourceId = query.datasourceId - - delete newQuery._id - delete newQuery._rev - newQuery.name = duplicateName( - query.name, - list.map(q => q.name) - ) - - return await save(datasourceId, newQuery) - } - - const removeDatasourceQueries = datasourceId => { - store.update(state => ({ - ...state, - list: state.list.filter(table => table.datasourceId !== datasourceId), - })) - } - - return { - subscribe: derivedStore.subscribe, - fetch, - init: fetch, - select, - save, - import: importQueries, - delete: deleteQuery, - preview, - duplicate, - removeDatasourceQueries, - } -} - -export const queries = createQueriesStore() diff --git a/packages/builder/src/stores/builder/queries.ts b/packages/builder/src/stores/builder/queries.ts new file mode 100644 index 0000000000..c6511dc346 --- /dev/null +++ b/packages/builder/src/stores/builder/queries.ts @@ -0,0 +1,156 @@ +import { derived, get, Writable } from "svelte/store" +import { datasources } from "./datasources" +import { integrations } from "./integrations" +import { API } from "@/api" +import { duplicateName } from "@/helpers/duplicate" +import { DerivedBudiStore } from "@/stores/BudiStore" +import { + Query, + QueryPreview, + PreviewQueryResponse, + SaveQueryRequest, + ImportRestQueryRequest, + QuerySchema, +} from "@budibase/types" + +const sortQueries = (queryList: Query[]) => { + queryList.sort((q1, q2) => { + return q1.name.localeCompare(q2.name) + }) +} + +interface BuilderQueryStore { + list: Query[] + selectedQueryId: string | null +} + +interface DerivedQueryStore extends BuilderQueryStore { + selected?: Query +} + +export class QueryStore extends DerivedBudiStore< + BuilderQueryStore, + DerivedQueryStore +> { + constructor() { + const makeDerivedStore = (store: Writable) => { + return derived(store, ($store): DerivedQueryStore => { + return { + list: $store.list, + selectedQueryId: $store.selectedQueryId, + selected: $store.list?.find(q => q._id === $store.selectedQueryId), + } + }) + } + + super( + { + list: [], + selectedQueryId: null, + }, + makeDerivedStore + ) + + this.select = this.select.bind(this) + } + + async fetch() { + const queries = await API.getQueries() + sortQueries(queries) + this.store.update(state => ({ + ...state, + list: queries, + })) + } + + async save(datasourceId: string, query: SaveQueryRequest) { + const _integrations = get(integrations) + const dataSource = get(datasources).list.filter( + ds => ds._id === datasourceId + ) + // Check if readable attribute is found + if (dataSource.length !== 0) { + const integration = _integrations[dataSource[0].source] + const readable = integration.query[query.queryVerb].readable + if (readable) { + query.readable = readable + } + } + query.datasourceId = datasourceId + const savedQuery = await API.saveQuery(query) + this.store.update(state => { + const idx = state.list.findIndex(query => query._id === savedQuery._id) + const queries = state.list + if (idx >= 0) { + queries.splice(idx, 1, savedQuery) + } else { + queries.push(savedQuery) + } + sortQueries(queries) + return { + list: queries, + selectedQueryId: savedQuery._id || null, + } + }) + return savedQuery + } + + async importQueries(data: ImportRestQueryRequest) { + return await API.importQueries(data) + } + + select(id: string | null) { + this.store.update(state => ({ + ...state, + selectedQueryId: id, + })) + } + + async preview(query: QueryPreview): Promise { + const result = await API.previewQuery(query) + // Assume all the fields are strings and create a basic schema from the + // unique fields returned by the server + const schema: Record = {} + for (let [field, metadata] of Object.entries(result.schema)) { + schema[field] = (metadata as QuerySchema) || { type: "string" } + } + return { ...result, schema, rows: result.rows || [] } + } + + async delete(query: Query) { + if (!query._id || !query._rev) { + throw new Error("Query ID or Revision is missing") + } + await API.deleteQuery(query._id, query._rev) + this.store.update(state => ({ + ...state, + list: state.list.filter(existing => existing._id !== query._id), + })) + } + + async duplicate(query: Query) { + let list = get(this.store).list + const newQuery = { ...query } + const datasourceId = query.datasourceId + + delete newQuery._id + delete newQuery._rev + newQuery.name = duplicateName( + query.name, + list.map(q => q.name) + ) + + return await this.save(datasourceId, newQuery) + } + + removeDatasourceQueries(datasourceId: string) { + this.store.update(state => ({ + ...state, + list: state.list.filter(table => table.datasourceId !== datasourceId), + })) + } + + init = this.fetch +} + +export const queries = new QueryStore() From 616e89716c8ea89bcd1b34b8e16a72463b089924 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 12:47:49 +0100 Subject: [PATCH 163/173] Remove unneeded extension --- packages/client/src/sdk.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/sdk.js b/packages/client/src/sdk.js index 40f35b2ba7..68d75d2806 100644 --- a/packages/client/src/sdk.js +++ b/packages/client/src/sdk.js @@ -29,7 +29,7 @@ import { ActionTypes } from "./constants" import { fetchDatasourceSchema, fetchDatasourceDefinition, -} from "./utils/schema.ts" +} from "./utils/schema" import { getAPIKey } from "./utils/api.js" import { enrichButtonActions } from "./utils/buttonActions.js" import { processStringSync, makePropSafe } from "@budibase/string-templates" From b54eb876d81007c37b918e33f61ded9db8c4ef1f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 12:50:08 +0100 Subject: [PATCH 164/173] Renames --- packages/frontend-core/src/fetch/ViewFetch.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend-core/src/fetch/ViewFetch.ts b/packages/frontend-core/src/fetch/ViewFetch.ts index c075d80ce0..df00b9bbfc 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.ts +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -1,7 +1,7 @@ import { Table } from "@budibase/types" import DataFetch from "./DataFetch" -type ViewV1 = { +type ViewV1Datasource = { type: "view" name: string tableId: string @@ -10,7 +10,7 @@ type ViewV1 = { groupBy: string } -export default class ViewFetch extends DataFetch { +export default class ViewFetch extends DataFetch { async getDefinition() { const { datasource } = this.options From ed6adbae08cb76f4278084b6d84fc9dcf0f65d45 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 10 Jan 2025 11:52:48 +0000 Subject: [PATCH 165/173] Bump version to 3.2.38 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 647c9f202d..ff69a18459 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.37", + "version": "3.2.38", "npmClient": "yarn", "concurrency": 20, "command": { From 6ecb01ae830d7ea94fe14b4e2696cfbb29f82cb1 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 14:47:09 +0100 Subject: [PATCH 166/173] Fix close modal on grid+modal generation --- packages/frontend-core/src/utils/utils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/frontend-core/src/utils/utils.js b/packages/frontend-core/src/utils/utils.js index c424aea5b2..55603b0129 100644 --- a/packages/frontend-core/src/utils/utils.js +++ b/packages/frontend-core/src/utils/utils.js @@ -209,6 +209,9 @@ export const buildFormBlockButtonConfig = props => { { "##eventHandlerType": "Close Side Panel", }, + { + "##eventHandlerType": "Close Modal", + }, ...(actionUrl ? [ From 23025f46396b828e27c356ae21c7bddb473c90c9 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 15:19:55 +0100 Subject: [PATCH 167/173] Clean --- packages/client/src/api/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/api/api.ts b/packages/client/src/api/api.ts index 93f59f6e9a..b944f7bd7c 100644 --- a/packages/client/src/api/api.ts +++ b/packages/client/src/api/api.ts @@ -4,7 +4,7 @@ import { notificationStore, devToolsEnabled, devToolsStore, -} from "../stores/index.js" +} from "../stores/index" import { get } from "svelte/store" export const API = createAPIClient({ From 9d0e3a17222f303e1f3a952e7c5e298d7187f070 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 15:22:34 +0100 Subject: [PATCH 168/173] Remove unnecessary extensions --- packages/client/src/api/index.js | 4 ++-- packages/client/src/stores/index.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/src/api/index.js b/packages/client/src/api/index.js index a63e19bfbb..3c53045cfd 100644 --- a/packages/client/src/api/index.js +++ b/packages/client/src/api/index.js @@ -1,5 +1,5 @@ -import { API } from "./api.ts" -import { patchAPI } from "./patches.js" +import { API } from "./api" +import { patchAPI } from "./patches" // Certain endpoints which return rows need patched so that they transform // and enrich the row docs, so that they can be correctly handled by the diff --git a/packages/client/src/stores/index.js b/packages/client/src/stores/index.js index e099434b3d..f2b80ed732 100644 --- a/packages/client/src/stores/index.js +++ b/packages/client/src/stores/index.js @@ -1,6 +1,6 @@ export { authStore } from "./auth" export { appStore } from "./app" -export { notificationStore } from "./notification.ts" +export { notificationStore } from "./notification" export { routeStore } from "./routes" export { screenStore } from "./screens" export { builderStore } from "./builder" From 9e2915ff0fc0a7279b95b1b05f9dd8e8baec1cbc Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 16:24:55 +0100 Subject: [PATCH 169/173] Fix wrong conversion --- packages/frontend-core/src/fetch/UserFetch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 656cd840fe..58aa4f5a96 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -52,7 +52,7 @@ export default class UserFetch extends DataFetch< const finalQuery: SearchFilters = utils.isSupportedUserSearch(rest) ? rest - : { [BasicOperator.EMPTY]: { email: null } } + : { [BasicOperator.STRING]: { email: null as any } } try { const opts: SearchUsersRequest = { From f54d917f3a1b375948491757298bc71fdb968192 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:27:50 +0000 Subject: [PATCH 170/173] account-portal login v2 feature flag (#15343) --- packages/types/src/sdk/featureFlag.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/types/src/sdk/featureFlag.ts b/packages/types/src/sdk/featureFlag.ts index 7b61b70772..996d3bba8d 100644 --- a/packages/types/src/sdk/featureFlag.ts +++ b/packages/types/src/sdk/featureFlag.ts @@ -1,9 +1,15 @@ export enum FeatureFlag { USE_ZOD_VALIDATOR = "USE_ZOD_VALIDATOR", + + // Account-portal + DIRECT_LOGIN_TO_ACCOUNT_PORTAL = "DIRECT_LOGIN_TO_ACCOUNT_PORTAL", } export const FeatureFlagDefaults = { [FeatureFlag.USE_ZOD_VALIDATOR]: false, + + // Account-portal + [FeatureFlag.DIRECT_LOGIN_TO_ACCOUNT_PORTAL]: false, } export type FeatureFlags = typeof FeatureFlagDefaults From e7400f982cc6bab2bada801e94a76b167332b84e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 16:29:42 +0100 Subject: [PATCH 171/173] Add comment --- packages/frontend-core/src/fetch/UserFetch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index e8e7dc8721..1fe9c0a383 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -56,7 +56,7 @@ export default class UserFetch extends DataFetch< const finalQuery: SearchFilters = utils.isSupportedUserSearch(rest) ? rest - : { [BasicOperator.STRING]: { email: null as any } } + : { [BasicOperator.STRING]: { email: null as any } } // TODO: chech. Left as any to not change the behaviour it had when it was js try { const opts: SearchUsersRequest = { From 337339d6e5366b36d437dc384f29963506cee6df Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 10 Jan 2025 16:39:55 +0100 Subject: [PATCH 172/173] Remove confusing empty filter --- packages/frontend-core/src/fetch/UserFetch.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/frontend-core/src/fetch/UserFetch.ts b/packages/frontend-core/src/fetch/UserFetch.ts index 1fe9c0a383..36aebac506 100644 --- a/packages/frontend-core/src/fetch/UserFetch.ts +++ b/packages/frontend-core/src/fetch/UserFetch.ts @@ -2,11 +2,7 @@ import { get } from "svelte/store" import DataFetch, { DataFetchParams } from "./DataFetch" import { TableNames } from "../constants" import { utils } from "@budibase/shared-core" -import { - BasicOperator, - SearchFilters, - SearchUsersRequest, -} from "@budibase/types" +import { SearchFilters, SearchUsersRequest } from "@budibase/types" interface UserFetchQuery { appId: string @@ -56,7 +52,7 @@ export default class UserFetch extends DataFetch< const finalQuery: SearchFilters = utils.isSupportedUserSearch(rest) ? rest - : { [BasicOperator.STRING]: { email: null as any } } // TODO: chech. Left as any to not change the behaviour it had when it was js + : {} try { const opts: SearchUsersRequest = { From 6ab389edde98138f90b85f216cea44b6af804875 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 10 Jan 2025 15:51:18 +0000 Subject: [PATCH 173/173] Bump version to 3.2.39 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index ff69a18459..0dc09b27be 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.38", + "version": "3.2.39", "npmClient": "yarn", "concurrency": 20, "command": {