@budibase/server 2.5.6-alpha.6 → 2.5.6-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const websocket_1 = __importDefault(require("./websocket"));
7
+ const authorized_1 = __importDefault(require("../middleware/authorized"));
8
+ const backend_core_1 = require("@budibase/backend-core");
9
+ class ClientAppWebsocket extends websocket_1.default {
10
+ constructor(app, server) {
11
+ super(app, server, "/socket/client", [(0, authorized_1.default)(backend_core_1.permissions.BUILDER)]);
12
+ }
13
+ }
14
+ exports.default = ClientAppWebsocket;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const authorized_1 = __importDefault(require("../middleware/authorized"));
16
+ const websocket_1 = __importDefault(require("./websocket"));
17
+ const backend_core_1 = require("@budibase/backend-core");
18
+ class GridSocket extends websocket_1.default {
19
+ constructor(app, server) {
20
+ super(app, server, "/socket/grid", [(0, authorized_1.default)(backend_core_1.permissions.BUILDER)]);
21
+ this.io.on("connection", socket => {
22
+ const user = socket.data.user;
23
+ console.log(`Spreadsheet user connected: ${user === null || user === void 0 ? void 0 : user.id}`);
24
+ // Socket state
25
+ let currentRoom;
26
+ // Initial identification of connected spreadsheet
27
+ socket.on("select-table", (tableId, callback) => __awaiter(this, void 0, void 0, function* () {
28
+ // Leave current room
29
+ if (currentRoom) {
30
+ socket.to(currentRoom).emit("user-disconnect", socket.data.user);
31
+ socket.leave(currentRoom);
32
+ }
33
+ // Join new room
34
+ currentRoom = tableId;
35
+ socket.join(currentRoom);
36
+ socket.to(currentRoom).emit("user-update", socket.data.user);
37
+ // Reply with all users in current room
38
+ const sockets = yield this.io.in(currentRoom).fetchSockets();
39
+ callback({
40
+ users: sockets.map(socket => socket.data.user),
41
+ id: user.id,
42
+ });
43
+ }));
44
+ // Handle users selecting a new cell
45
+ socket.on("select-cell", cellId => {
46
+ socket.data.user.selectedCellId = cellId;
47
+ if (currentRoom) {
48
+ socket.to(currentRoom).emit("user-update", socket.data.user);
49
+ }
50
+ });
51
+ // Disconnection cleanup
52
+ socket.on("disconnect", () => {
53
+ if (currentRoom) {
54
+ socket.to(currentRoom).emit("user-disconnect", socket.data.user);
55
+ }
56
+ });
57
+ });
58
+ }
59
+ }
60
+ exports.default = GridSocket;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.gridSocket = exports.clientAppSocket = exports.initialise = void 0;
7
+ const grid_1 = __importDefault(require("./grid"));
8
+ const client_1 = __importDefault(require("./client"));
9
+ let clientAppSocket;
10
+ exports.clientAppSocket = clientAppSocket;
11
+ let gridSocket;
12
+ exports.gridSocket = gridSocket;
13
+ const initialise = (app, server) => {
14
+ exports.clientAppSocket = clientAppSocket = new client_1.default(app, server);
15
+ exports.gridSocket = gridSocket = new grid_1.default(app, server);
16
+ };
17
+ exports.initialise = initialise;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const socket_io_1 = require("socket.io");
16
+ const http_1 = __importDefault(require("http"));
17
+ const cookies_1 = __importDefault(require("cookies"));
18
+ const koa_useragent_1 = require("koa-useragent");
19
+ const backend_core_1 = require("@budibase/backend-core");
20
+ const currentapp_1 = __importDefault(require("../middleware/currentapp"));
21
+ class Socket {
22
+ constructor(app, server, path, additionalMiddlewares) {
23
+ this.io = new socket_io_1.Server(server, {
24
+ path,
25
+ });
26
+ // Attach default middlewares
27
+ const authenticate = backend_core_1.auth.buildAuthMiddleware([], {
28
+ publicAllowed: true,
29
+ });
30
+ const middlewares = [
31
+ koa_useragent_1.userAgent,
32
+ authenticate,
33
+ currentapp_1.default,
34
+ ...(additionalMiddlewares || []),
35
+ ];
36
+ // Apply middlewares
37
+ this.io.use((socket, next) => __awaiter(this, void 0, void 0, function* () {
38
+ // Build fake koa context
39
+ const res = new http_1.default.ServerResponse(socket.request);
40
+ const ctx = Object.assign(Object.assign({}, app.createContext(socket.request, res)), {
41
+ // Additional overrides needed to make our middlewares work with this
42
+ // fake koa context
43
+ cookies: new cookies_1.default(socket.request, res), get: (field) => socket.request.headers[field], throw: (code, message) => {
44
+ throw new Error(message);
45
+ },
46
+ // Needed for koa-useragent middleware
47
+ headers: socket.request.headers, header: socket.request.headers,
48
+ // We don't really care about the path since it will never contain
49
+ // an app ID
50
+ path: "/socket" });
51
+ // Run all koa middlewares
52
+ try {
53
+ for (let [idx, middleware] of middlewares.entries()) {
54
+ yield middleware(ctx, () => {
55
+ if (idx === middlewares.length - 1) {
56
+ // Middlewares are finished.
57
+ // Extract some data from our enriched koa context to persist
58
+ // as metadata for the socket
59
+ socket.data.user = {
60
+ id: ctx.user._id,
61
+ email: ctx.user.email,
62
+ };
63
+ next();
64
+ }
65
+ });
66
+ }
67
+ }
68
+ catch (error) {
69
+ next(error);
70
+ }
71
+ }));
72
+ }
73
+ // Emit an event to all sockets
74
+ emit(event, payload) {
75
+ this.io.sockets.emit(event, payload);
76
+ }
77
+ }
78
+ exports.default = Socket;
package/jest.config.ts CHANGED
@@ -20,9 +20,9 @@ const baseConfig: Config.InitialProjectOptions = {
20
20
  }
21
21
 
22
22
  // add pro sources if they exist
23
- if (fs.existsSync("../../../budibase-pro")) {
24
- baseConfig.moduleNameMapper["@budibase/pro"] =
25
- "<rootDir>/../../../budibase-pro/packages/pro/src"
23
+ if (fs.existsSync("../pro/packages")) {
24
+ baseConfig.moduleNameMapper!["@budibase/pro"] =
25
+ "<rootDir>/../pro/packages/pro/src"
26
26
  }
27
27
 
28
28
  const config: Config.InitialOptions = {
package/nodemon.json CHANGED
@@ -1,6 +1,10 @@
1
1
  {
2
- "watch": ["src", "../backend-core", "../../../budibase-pro/packages/pro"],
2
+ "watch": ["src", "../backend-core", "../pro/packages/pro"],
3
3
  "ext": "js,ts,json",
4
- "ignore": ["src/**/*.spec.ts", "src/**/*.spec.js", "../backend-core/dist/**/*"],
4
+ "ignore": [
5
+ "src/**/*.spec.ts",
6
+ "src/**/*.spec.js",
7
+ "../backend-core/dist/**/*"
8
+ ],
5
9
  "exec": "ts-node src/index.ts"
6
- }
10
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "2.5.6-alpha.6",
4
+ "version": "2.5.6-alpha.8",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -45,12 +45,12 @@
45
45
  "license": "GPL-3.0",
46
46
  "dependencies": {
47
47
  "@apidevtools/swagger-parser": "10.0.3",
48
- "@budibase/backend-core": "2.5.6-alpha.6",
49
- "@budibase/client": "2.5.6-alpha.6",
50
- "@budibase/pro": "2.5.6-alpha.5",
51
- "@budibase/shared-core": "2.5.6-alpha.6",
52
- "@budibase/string-templates": "2.5.6-alpha.6",
53
- "@budibase/types": "2.5.6-alpha.6",
48
+ "@budibase/backend-core": "2.5.6-alpha.8",
49
+ "@budibase/client": "2.5.6-alpha.8",
50
+ "@budibase/pro": "2.5.6-alpha.6",
51
+ "@budibase/shared-core": "2.5.6-alpha.8",
52
+ "@budibase/string-templates": "2.5.6-alpha.8",
53
+ "@budibase/types": "2.5.6-alpha.8",
54
54
  "@bull-board/api": "3.7.0",
55
55
  "@bull-board/koa": "3.9.4",
56
56
  "@elastic/elasticsearch": "7.10.0",
@@ -65,6 +65,7 @@
65
65
  "bull": "4.10.1",
66
66
  "chmodr": "1.2.0",
67
67
  "chokidar": "3.5.3",
68
+ "cookies": "0.8.0",
68
69
  "csvtojson": "2.0.10",
69
70
  "curlconverter": "3.21.0",
70
71
  "dd-trace": "3.13.2",
@@ -108,7 +109,7 @@
108
109
  "redis": "4",
109
110
  "server-destroy": "1.0.1",
110
111
  "snowflake-promise": "^4.5.0",
111
- "socket.io": "^4.5.1",
112
+ "socket.io": "4.6.1",
112
113
  "svelte": "3.49.0",
113
114
  "swagger-parser": "10.0.3",
114
115
  "tar": "6.1.11",
@@ -175,5 +176,5 @@
175
176
  "optionalDependencies": {
176
177
  "oracledb": "5.3.0"
177
178
  },
178
- "gitHead": "38e1d3a3a0a70b4a55b3a1a790d46151057af3c2"
179
+ "gitHead": "e87d1692c387c3a26ecf37b07e69dc39c403e224"
179
180
  }
@@ -2,7 +2,7 @@ import { npmUpload, urlUpload, githubUpload } from "./uploaders"
2
2
  import { plugins as pluginCore } from "@budibase/backend-core"
3
3
  import { PluginType, FileType, PluginSource } from "@budibase/types"
4
4
  import env from "../../../environment"
5
- import { ClientAppSocket } from "../../../websocket"
5
+ import { clientAppSocket } from "../../../websockets"
6
6
  import sdk from "../../../sdk"
7
7
  import { sdk as pro } from "@budibase/pro"
8
8
 
@@ -71,7 +71,7 @@ export async function create(ctx: any) {
71
71
 
72
72
  const doc = await pro.plugins.storePlugin(metadata, directory, source)
73
73
 
74
- ClientAppSocket.emit("plugins-update", { name, hash: doc.hash })
74
+ clientAppSocket.emit("plugins-update", { name, hash: doc.hash })
75
75
  ctx.body = {
76
76
  message: "Plugin uploaded successfully",
77
77
  plugins: [doc],
@@ -124,7 +124,8 @@ export function importToRows(
124
124
  for (const [fieldName, schema] of Object.entries(table.schema)) {
125
125
  // check whether the options need to be updated for inclusion as part of the data import
126
126
  if (
127
- schema.type === FieldTypes.OPTIONS &&
127
+ (schema.type === FieldTypes.OPTIONS ||
128
+ schema.type === FieldTypes.ARRAY) &&
128
129
  row[fieldName] &&
129
130
  (!schema.constraints!.inclusion ||
130
131
  schema.constraints!.inclusion.indexOf(row[fieldName]) === -1)
package/src/app.ts CHANGED
@@ -15,8 +15,8 @@ import * as api from "./api"
15
15
  import * as automations from "./automations"
16
16
  import { Thread } from "./threads"
17
17
  import * as redis from "./utilities/redis"
18
+ import { initialise as initialiseWebsockets } from "./websockets"
18
19
  import { events, logging, middleware, timers } from "@budibase/backend-core"
19
- import { initialise as initialiseWebsockets } from "./websocket"
20
20
  import { startup } from "./startup"
21
21
  const Sentry = require("@sentry/node")
22
22
  const destroyable = require("server-destroy")
@@ -61,7 +61,7 @@ if (env.isProd()) {
61
61
 
62
62
  const server = http.createServer(app.callback())
63
63
  destroyable(server)
64
- initialiseWebsockets(server)
64
+ initialiseWebsockets(app, server)
65
65
 
66
66
  let shuttingDown = false,
67
67
  errCode = 0
@@ -7,7 +7,7 @@ import {
7
7
  } from "@budibase/backend-core"
8
8
  import { fileUpload } from "../../api/controllers/plugin/file"
9
9
  import env from "../../environment"
10
- import { ClientAppSocket } from "../../websocket"
10
+ import { clientAppSocket } from "../../websockets"
11
11
  import { sdk as pro } from "@budibase/pro"
12
12
 
13
13
  export async function fetch(type?: PluginType) {
@@ -36,6 +36,6 @@ export async function processUploaded(plugin: FileType, source?: PluginSource) {
36
36
  }
37
37
 
38
38
  const doc = await pro.plugins.storePlugin(metadata, directory, source)
39
- ClientAppSocket.emit("plugin-update", { name: doc.name, hash: doc.hash })
39
+ clientAppSocket.emit("plugin-update", { name: doc.name, hash: doc.hash })
40
40
  return doc
41
41
  }
@@ -0,0 +1,11 @@
1
+ import Socket from "./websocket"
2
+ import authorized from "../middleware/authorized"
3
+ import http from "http"
4
+ import Koa from "koa"
5
+ import { permissions } from "@budibase/backend-core"
6
+
7
+ export default class ClientAppWebsocket extends Socket {
8
+ constructor(app: Koa, server: http.Server) {
9
+ super(app, server, "/socket/client", [authorized(permissions.BUILDER)])
10
+ }
11
+ }
@@ -0,0 +1,55 @@
1
+ import authorized from "../middleware/authorized"
2
+ import Socket from "./websocket"
3
+ import { permissions } from "@budibase/backend-core"
4
+ import http from "http"
5
+ import Koa from "koa"
6
+
7
+ export default class GridSocket extends Socket {
8
+ constructor(app: Koa, server: http.Server) {
9
+ super(app, server, "/socket/grid", [authorized(permissions.BUILDER)])
10
+
11
+ this.io.on("connection", socket => {
12
+ const user = socket.data.user
13
+ console.log(`Spreadsheet user connected: ${user?.id}`)
14
+
15
+ // Socket state
16
+ let currentRoom: string
17
+
18
+ // Initial identification of connected spreadsheet
19
+ socket.on("select-table", async (tableId, callback) => {
20
+ // Leave current room
21
+ if (currentRoom) {
22
+ socket.to(currentRoom).emit("user-disconnect", socket.data.user)
23
+ socket.leave(currentRoom)
24
+ }
25
+
26
+ // Join new room
27
+ currentRoom = tableId
28
+ socket.join(currentRoom)
29
+ socket.to(currentRoom).emit("user-update", socket.data.user)
30
+
31
+ // Reply with all users in current room
32
+ const sockets = await this.io.in(currentRoom).fetchSockets()
33
+ callback({
34
+ users: sockets.map(socket => socket.data.user),
35
+ id: user.id,
36
+ })
37
+ })
38
+
39
+ // Handle users selecting a new cell
40
+ socket.on("select-cell", cellId => {
41
+ socket.data.user.selectedCellId = cellId
42
+ if (currentRoom) {
43
+ socket.to(currentRoom).emit("user-update", socket.data.user)
44
+ }
45
+ })
46
+
47
+ // Disconnection cleanup
48
+ socket.on("disconnect", () => {
49
+ if (currentRoom) {
50
+ socket.to(currentRoom).emit("user-disconnect", socket.data.user)
51
+ }
52
+ })
53
+ })
54
+ }
55
+ }
@@ -0,0 +1,14 @@
1
+ import http from "http"
2
+ import Koa from "koa"
3
+ import GridSocket from "./grid"
4
+ import ClientAppSocket from "./client"
5
+
6
+ let clientAppSocket: ClientAppSocket
7
+ let gridSocket: GridSocket
8
+
9
+ export const initialise = (app: Koa, server: http.Server) => {
10
+ clientAppSocket = new ClientAppSocket(app, server)
11
+ gridSocket = new GridSocket(app, server)
12
+ }
13
+
14
+ export { clientAppSocket, gridSocket }
@@ -0,0 +1,83 @@
1
+ import { Server } from "socket.io"
2
+ import http from "http"
3
+ import Koa from "koa"
4
+ import Cookies from "cookies"
5
+ import { userAgent } from "koa-useragent"
6
+ import { auth } from "@budibase/backend-core"
7
+ import currentApp from "../middleware/currentapp"
8
+
9
+ export default class Socket {
10
+ io: Server
11
+
12
+ constructor(
13
+ app: Koa,
14
+ server: http.Server,
15
+ path: string,
16
+ additionalMiddlewares?: any[]
17
+ ) {
18
+ this.io = new Server(server, {
19
+ path,
20
+ })
21
+
22
+ // Attach default middlewares
23
+ const authenticate = auth.buildAuthMiddleware([], {
24
+ publicAllowed: true,
25
+ })
26
+ const middlewares = [
27
+ userAgent,
28
+ authenticate,
29
+ currentApp,
30
+ ...(additionalMiddlewares || []),
31
+ ]
32
+
33
+ // Apply middlewares
34
+ this.io.use(async (socket, next) => {
35
+ // Build fake koa context
36
+ const res = new http.ServerResponse(socket.request)
37
+ const ctx: any = {
38
+ ...app.createContext(socket.request, res),
39
+
40
+ // Additional overrides needed to make our middlewares work with this
41
+ // fake koa context
42
+ cookies: new Cookies(socket.request, res),
43
+ get: (field: string) => socket.request.headers[field],
44
+ throw: (code: number, message: string) => {
45
+ throw new Error(message)
46
+ },
47
+
48
+ // Needed for koa-useragent middleware
49
+ headers: socket.request.headers,
50
+ header: socket.request.headers,
51
+
52
+ // We don't really care about the path since it will never contain
53
+ // an app ID
54
+ path: "/socket",
55
+ }
56
+
57
+ // Run all koa middlewares
58
+ try {
59
+ for (let [idx, middleware] of middlewares.entries()) {
60
+ await middleware(ctx, () => {
61
+ if (idx === middlewares.length - 1) {
62
+ // Middlewares are finished.
63
+ // Extract some data from our enriched koa context to persist
64
+ // as metadata for the socket
65
+ socket.data.user = {
66
+ id: ctx.user._id,
67
+ email: ctx.user.email,
68
+ }
69
+ next()
70
+ }
71
+ })
72
+ }
73
+ } catch (error: any) {
74
+ next(error)
75
+ }
76
+ })
77
+ }
78
+
79
+ // Emit an event to all sockets
80
+ emit(event: string, payload: any) {
81
+ this.io.sockets.emit(event, payload)
82
+ }
83
+ }
package/tsconfig.json CHANGED
@@ -10,19 +10,13 @@
10
10
  "@budibase/backend-core": ["../backend-core/src"],
11
11
  "@budibase/backend-core/*": ["../backend-core/*"],
12
12
  "@budibase/shared-core": ["../shared-core/src"],
13
- "@budibase/pro": ["../../../budibase-pro/packages/pro/src"]
13
+ "@budibase/pro": ["../pro/packages/pro/src"]
14
14
  }
15
15
  },
16
16
  "ts-node": {
17
17
  "require": ["tsconfig-paths/register"],
18
18
  "swc": true
19
19
  },
20
- "references": [
21
- { "path": "../types" },
22
- { "path": "../backend-core" },
23
- { "path": "../shared-core" },
24
- { "path": "../../../budibase-pro/packages/pro" }
25
- ],
26
20
  "include": ["src/**/*", "specs", "package.json"],
27
21
  "exclude": ["node_modules", "dist"]
28
22
  }