@budibase/server 2.5.5 → 2.5.6-alpha.10

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.
Files changed (156) hide show
  1. package/builder/assets/index.5c1a6913.js +1776 -0
  2. package/builder/assets/index.c0265b74.css +6 -0
  3. package/builder/index.html +2 -2
  4. package/dist/api/controllers/automation.js +13 -7
  5. package/dist/api/controllers/ops.js +40 -0
  6. package/dist/api/controllers/plugin/index.js +6 -37
  7. package/dist/api/controllers/table/utils.js +2 -1
  8. package/dist/api/controllers/user.js +1 -83
  9. package/dist/api/routes/index.js +2 -0
  10. package/dist/api/routes/ops.js +52 -0
  11. package/dist/api/routes/user.js +0 -1
  12. package/dist/app.js +4 -13
  13. package/dist/automations/actions.js +32 -6
  14. package/dist/automations/index.js +3 -2
  15. package/dist/automations/steps/bash.js +6 -6
  16. package/dist/automations/steps/createRow.js +11 -11
  17. package/dist/automations/steps/delay.js +3 -3
  18. package/dist/automations/steps/deleteRow.js +8 -8
  19. package/dist/automations/steps/discord.js +8 -8
  20. package/dist/automations/steps/executeQuery.js +9 -9
  21. package/dist/automations/steps/executeScript.js +6 -6
  22. package/dist/automations/steps/filter.js +6 -6
  23. package/dist/automations/steps/integromat.js +10 -10
  24. package/dist/automations/steps/loop.js +9 -9
  25. package/dist/automations/steps/outgoingWebhook.js +10 -10
  26. package/dist/automations/steps/queryRows.js +14 -14
  27. package/dist/automations/steps/sendSmtpEmail.js +9 -9
  28. package/dist/automations/steps/serverLog.js +4 -4
  29. package/dist/automations/steps/slack.js +6 -6
  30. package/dist/automations/steps/updateRow.js +11 -11
  31. package/dist/automations/steps/zapier.js +9 -9
  32. package/dist/automations/triggerInfo/app.js +5 -5
  33. package/dist/automations/triggerInfo/cron.js +4 -4
  34. package/dist/automations/triggerInfo/rowDeleted.js +5 -5
  35. package/dist/automations/triggerInfo/rowSaved.js +7 -7
  36. package/dist/automations/triggerInfo/rowUpdated.js +7 -7
  37. package/dist/automations/triggerInfo/webhook.js +6 -6
  38. package/dist/environment.js +0 -1
  39. package/dist/events/docUpdates/index.js +17 -0
  40. package/dist/events/docUpdates/processors.js +18 -0
  41. package/dist/events/docUpdates/syncUsers.js +49 -0
  42. package/dist/events/index.js +3 -0
  43. package/dist/integrations/index.js +3 -3
  44. package/dist/integrations/microsoftSqlServer.js +5 -2
  45. package/dist/integrations/mysql.js +5 -3
  46. package/dist/integrations/postgres.js +7 -5
  47. package/dist/integrations/redis.js +7 -0
  48. package/dist/integrations/rest.js +4 -0
  49. package/dist/migrations/functions/usageQuotas/syncApps.js +1 -1
  50. package/dist/migrations/functions/usageQuotas/syncRows.js +1 -2
  51. package/dist/package.json +15 -15
  52. package/dist/sdk/app/applications/sync.js +117 -23
  53. package/dist/sdk/index.js +2 -0
  54. package/dist/sdk/plugins/index.js +27 -0
  55. package/dist/sdk/plugins/plugins.js +53 -0
  56. package/dist/sdk/users/utils.js +21 -4
  57. package/dist/startup.js +31 -28
  58. package/dist/threads/automation.js +16 -5
  59. package/dist/tsconfig.build.tsbuildinfo +1 -1
  60. package/dist/utilities/fileSystem/plugin.js +33 -23
  61. package/dist/utilities/global.js +17 -12
  62. package/dist/watch.js +2 -2
  63. package/dist/websockets/client.js +14 -0
  64. package/dist/websockets/grid.js +60 -0
  65. package/dist/websockets/index.js +17 -0
  66. package/dist/websockets/websocket.js +78 -0
  67. package/jest.config.ts +3 -3
  68. package/nodemon.json +7 -3
  69. package/package.json +16 -16
  70. package/scripts/dev/manage.js +2 -0
  71. package/scripts/integrations/mssql/data/entrypoint.sh +1 -0
  72. package/scripts/integrations/mssql/data/setup.sql +17 -17
  73. package/scripts/integrations/mysql/init.sql +1 -1
  74. package/scripts/integrations/postgres/init.sql +1 -0
  75. package/src/api/controllers/automation.ts +12 -6
  76. package/src/api/controllers/ops.ts +32 -0
  77. package/src/api/controllers/plugin/index.ts +8 -45
  78. package/src/api/controllers/row/internal.ts +9 -10
  79. package/src/api/controllers/row/utils.ts +2 -2
  80. package/src/api/controllers/table/utils.ts +2 -1
  81. package/src/api/controllers/user.ts +10 -96
  82. package/src/api/routes/index.ts +2 -0
  83. package/src/api/routes/ops.ts +30 -0
  84. package/src/api/routes/tests/automation.spec.js +7 -4
  85. package/src/api/routes/tests/user.spec.js +48 -37
  86. package/src/api/routes/user.ts +0 -5
  87. package/src/app.ts +4 -15
  88. package/src/automations/actions.ts +56 -24
  89. package/src/automations/index.ts +1 -1
  90. package/src/automations/steps/bash.ts +10 -7
  91. package/src/automations/steps/createRow.ts +15 -12
  92. package/src/automations/steps/delay.ts +6 -4
  93. package/src/automations/steps/deleteRow.ts +12 -9
  94. package/src/automations/steps/discord.ts +10 -8
  95. package/src/automations/steps/executeQuery.ts +13 -10
  96. package/src/automations/steps/executeScript.ts +10 -7
  97. package/src/automations/steps/filter.ts +8 -6
  98. package/src/automations/steps/integromat.ts +12 -10
  99. package/src/automations/steps/loop.ts +16 -10
  100. package/src/automations/steps/outgoingWebhook.ts +14 -11
  101. package/src/automations/steps/queryRows.ts +18 -15
  102. package/src/automations/steps/sendSmtpEmail.ts +11 -9
  103. package/src/automations/steps/serverLog.ts +6 -4
  104. package/src/automations/steps/slack.ts +8 -6
  105. package/src/automations/steps/updateRow.ts +15 -12
  106. package/src/automations/steps/zapier.ts +11 -9
  107. package/src/automations/tests/utilities/index.ts +2 -2
  108. package/src/automations/triggerInfo/app.ts +8 -5
  109. package/src/automations/triggerInfo/cron.ts +7 -4
  110. package/src/automations/triggerInfo/rowDeleted.ts +8 -5
  111. package/src/automations/triggerInfo/rowSaved.ts +10 -7
  112. package/src/automations/triggerInfo/rowUpdated.ts +10 -7
  113. package/src/automations/triggerInfo/webhook.ts +9 -6
  114. package/src/environment.ts +0 -1
  115. package/src/events/docUpdates/index.ts +1 -0
  116. package/src/events/docUpdates/processors.ts +14 -0
  117. package/src/events/docUpdates/syncUsers.ts +35 -0
  118. package/src/events/index.ts +1 -0
  119. package/src/integrations/index.ts +3 -3
  120. package/src/integrations/microsoftSqlServer.ts +5 -2
  121. package/src/integrations/mysql.ts +5 -3
  122. package/src/integrations/postgres.ts +7 -5
  123. package/src/integrations/redis.ts +8 -0
  124. package/src/integrations/rest.ts +3 -0
  125. package/src/migrations/functions/usageQuotas/syncApps.ts +1 -1
  126. package/src/migrations/functions/usageQuotas/syncRows.ts +2 -3
  127. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +2 -2
  128. package/src/sdk/app/applications/sync.ts +129 -22
  129. package/src/sdk/app/applications/tests/sync.spec.ts +137 -0
  130. package/src/sdk/index.ts +2 -0
  131. package/src/sdk/plugins/index.ts +5 -0
  132. package/src/sdk/plugins/plugins.ts +41 -0
  133. package/src/sdk/users/tests/utils.spec.ts +1 -32
  134. package/src/sdk/users/utils.ts +23 -5
  135. package/src/startup.ts +36 -34
  136. package/src/tests/jestEnv.ts +0 -1
  137. package/src/tests/jestSetup.ts +0 -1
  138. package/src/tests/utilities/TestConfiguration.ts +28 -0
  139. package/src/tests/utilities/structures.ts +25 -17
  140. package/src/threads/automation.ts +18 -6
  141. package/src/utilities/fileSystem/plugin.ts +13 -4
  142. package/src/utilities/global.ts +21 -16
  143. package/src/watch.ts +2 -2
  144. package/src/websockets/client.ts +11 -0
  145. package/src/websockets/grid.ts +55 -0
  146. package/src/websockets/index.ts +14 -0
  147. package/src/websockets/websocket.ts +83 -0
  148. package/tsconfig.json +1 -7
  149. package/builder/assets/index.7f9a008b.css +0 -6
  150. package/builder/assets/index.f493a2b3.js +0 -1817
  151. package/dist/elasticApm.js +0 -14
  152. package/dist/websocket.js +0 -22
  153. package/scripts/likeCypress.ts +0 -35
  154. package/src/elasticApm.ts +0 -10
  155. package/src/tests/logging.ts +0 -34
  156. package/src/websocket.ts +0 -26
@@ -12,10 +12,108 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.syncApp = void 0;
15
+ exports.syncApp = exports.syncUsersToAllApps = void 0;
16
16
  const environment_1 = __importDefault(require("../../../environment"));
17
17
  const backend_core_1 = require("@budibase/backend-core");
18
+ const pro_1 = require("@budibase/pro");
18
19
  const __1 = __importDefault(require("../../"));
20
+ const global_1 = require("../../../utilities/global");
21
+ const utils_1 = require("../../../db/utils");
22
+ function syncUsersToApp(appId, users, groups) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ if (!(yield backend_core_1.db.dbExists(appId))) {
25
+ return;
26
+ }
27
+ yield backend_core_1.context.doInAppContext(appId, () => __awaiter(this, void 0, void 0, function* () {
28
+ const db = backend_core_1.context.getAppDB();
29
+ for (let user of users) {
30
+ let ctxUser = user;
31
+ let deletedUser = false;
32
+ const metadataId = (0, utils_1.generateUserMetadataID)(user._id);
33
+ if (user.deleted) {
34
+ deletedUser = true;
35
+ }
36
+ // make sure role is correct
37
+ if (!deletedUser) {
38
+ ctxUser = yield (0, global_1.processUser)(ctxUser, { appId, groups });
39
+ }
40
+ let roleId = ctxUser.roleId;
41
+ if (roleId === backend_core_1.roles.BUILTIN_ROLE_IDS.PUBLIC) {
42
+ roleId = undefined;
43
+ }
44
+ let metadata;
45
+ try {
46
+ metadata = yield db.get(metadataId);
47
+ }
48
+ catch (err) {
49
+ if (err.status !== 404) {
50
+ throw err;
51
+ }
52
+ // no metadata and user is to be deleted, can skip
53
+ // no role - user isn't in app anyway
54
+ if (!roleId) {
55
+ continue;
56
+ }
57
+ else if (!deletedUser) {
58
+ // doesn't exist yet, creating it
59
+ metadata = {
60
+ tableId: utils_1.InternalTables.USER_METADATA,
61
+ };
62
+ }
63
+ }
64
+ // the user doesn't exist, or doesn't have a role anymore
65
+ // get rid of their metadata
66
+ if (deletedUser || !roleId) {
67
+ yield db.remove(metadata);
68
+ continue;
69
+ }
70
+ // assign the roleId for the metadata doc
71
+ if (roleId) {
72
+ metadata.roleId = roleId;
73
+ }
74
+ let combined = __1.default.users.combineMetadataAndUser(ctxUser, metadata);
75
+ // if no combined returned, there are no updates to make
76
+ if (combined) {
77
+ yield db.put(combined);
78
+ }
79
+ }
80
+ }));
81
+ });
82
+ }
83
+ function syncUsersToAllApps(userIds) {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ // list of users, if one has been deleted it will be undefined in array
86
+ const users = (yield (0, global_1.getGlobalUsers)(userIds, {
87
+ noProcessing: true,
88
+ }));
89
+ const groups = yield pro_1.sdk.groups.fetch();
90
+ const finalUsers = [];
91
+ for (let userId of userIds) {
92
+ const user = users.find(user => user._id === userId);
93
+ if (!user) {
94
+ finalUsers.push({ _id: userId, deleted: true });
95
+ }
96
+ else {
97
+ finalUsers.push(user);
98
+ }
99
+ }
100
+ const devAppIds = yield backend_core_1.db.getDevAppIDs();
101
+ let promises = [];
102
+ for (let devAppId of devAppIds) {
103
+ const prodAppId = backend_core_1.db.getProdAppID(devAppId);
104
+ for (let appId of [prodAppId, devAppId]) {
105
+ promises.push(syncUsersToApp(appId, finalUsers, groups));
106
+ }
107
+ }
108
+ const resp = yield Promise.allSettled(promises);
109
+ const failed = resp.filter(promise => promise.status === "rejected");
110
+ if (failed.length > 0) {
111
+ const reasons = failed.map(fail => fail.reason);
112
+ backend_core_1.logging.logAlert("Failed to sync users to apps", reasons);
113
+ }
114
+ });
115
+ }
116
+ exports.syncUsersToAllApps = syncUsersToAllApps;
19
117
  function syncApp(appId, opts) {
20
118
  return __awaiter(this, void 0, void 0, function* () {
21
119
  if (environment_1.default.DISABLE_AUTO_PROD_APP_SYNC) {
@@ -31,31 +129,27 @@ function syncApp(appId, opts) {
31
129
  // specific case, want to make sure setup is skipped
32
130
  const prodDb = backend_core_1.context.getProdAppDB({ skip_setup: true });
33
131
  const exists = yield prodDb.exists();
34
- if (!exists) {
35
- // the database doesn't exist. Don't replicate
36
- return {
37
- message: "App sync not required, app not deployed.",
38
- };
39
- }
40
- const replication = new backend_core_1.db.Replication({
41
- source: prodAppId,
42
- target: appId,
43
- });
44
132
  let error;
45
- try {
46
- const replOpts = replication.appReplicateOpts();
47
- if (opts === null || opts === void 0 ? void 0 : opts.automationOnly) {
48
- replOpts.filter = (doc) => doc._id.startsWith(backend_core_1.db.DocumentType.AUTOMATION);
133
+ if (exists) {
134
+ const replication = new backend_core_1.db.Replication({
135
+ source: prodAppId,
136
+ target: appId,
137
+ });
138
+ try {
139
+ const replOpts = replication.appReplicateOpts();
140
+ if (opts === null || opts === void 0 ? void 0 : opts.automationOnly) {
141
+ replOpts.filter = (doc) => doc._id.startsWith(backend_core_1.db.DocumentType.AUTOMATION);
142
+ }
143
+ yield replication.replicate(replOpts);
144
+ }
145
+ catch (err) {
146
+ error = err;
147
+ }
148
+ finally {
149
+ yield replication.close();
49
150
  }
50
- yield replication.replicate(replOpts);
51
- }
52
- catch (err) {
53
- error = err;
54
- }
55
- finally {
56
- yield replication.close();
57
151
  }
58
- // sync the users
152
+ // sync the users - kept for safe keeping
59
153
  yield __1.default.users.syncGlobalUsers();
60
154
  if (error) {
61
155
  throw error;
package/dist/sdk/index.js CHANGED
@@ -11,6 +11,7 @@ const datasources_1 = __importDefault(require("./app/datasources"));
11
11
  const queries_1 = __importDefault(require("./app/queries"));
12
12
  const rows_1 = __importDefault(require("./app/rows"));
13
13
  const users_1 = __importDefault(require("./users"));
14
+ const plugins_1 = __importDefault(require("./plugins"));
14
15
  const sdk = {
15
16
  backups: backups_1.default,
16
17
  tables: tables_1.default,
@@ -20,6 +21,7 @@ const sdk = {
20
21
  users: users_1.default,
21
22
  datasources: datasources_1.default,
22
23
  queries: queries_1.default,
24
+ plugins: plugins_1.default,
23
25
  };
24
26
  // default export for TS
25
27
  exports.default = sdk;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const plugins = __importStar(require("./plugins"));
27
+ exports.default = Object.assign({}, plugins);
@@ -0,0 +1,53 @@
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
+ exports.processUploaded = exports.fetch = void 0;
16
+ const types_1 = require("@budibase/types");
17
+ const backend_core_1 = require("@budibase/backend-core");
18
+ const file_1 = require("../../api/controllers/plugin/file");
19
+ const environment_1 = __importDefault(require("../../environment"));
20
+ const websockets_1 = require("../../websockets");
21
+ const pro_1 = require("@budibase/pro");
22
+ function fetch(type) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ const db = backend_core_1.tenancy.getGlobalDB();
25
+ const response = yield db.allDocs(backend_core_1.db.getPluginParams(null, {
26
+ include_docs: true,
27
+ }));
28
+ let plugins = response.rows.map((row) => row.doc);
29
+ plugins = backend_core_1.objectStore.enrichPluginURLs(plugins);
30
+ if (type) {
31
+ return plugins.filter((plugin) => { var _a; return ((_a = plugin.schema) === null || _a === void 0 ? void 0 : _a.type) === type; });
32
+ }
33
+ else {
34
+ return plugins;
35
+ }
36
+ });
37
+ }
38
+ exports.fetch = fetch;
39
+ function processUploaded(plugin, source) {
40
+ var _a;
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ const { metadata, directory } = yield (0, file_1.fileUpload)(plugin);
43
+ backend_core_1.plugins.validate(metadata === null || metadata === void 0 ? void 0 : metadata.schema);
44
+ // Only allow components in cloud
45
+ if (!environment_1.default.SELF_HOSTED && ((_a = metadata === null || metadata === void 0 ? void 0 : metadata.schema) === null || _a === void 0 ? void 0 : _a.type) !== types_1.PluginType.COMPONENT) {
46
+ throw new Error("Only component plugins are supported outside of self-host");
47
+ }
48
+ const doc = yield pro_1.sdk.plugins.storePlugin(metadata, directory, source);
49
+ websockets_1.clientAppSocket.emit("plugin-update", { name: doc.name, hash: doc.hash });
50
+ return doc;
51
+ });
52
+ }
53
+ exports.processUploaded = processUploaded;
@@ -34,6 +34,10 @@ function combineMetadataAndUser(user, metadata) {
34
34
  if (found) {
35
35
  newDoc._rev = found._rev;
36
36
  }
37
+ // clear fields that shouldn't be in metadata
38
+ delete newDoc.password;
39
+ delete newDoc.forceResetPassword;
40
+ delete newDoc.roles;
37
41
  if (found == null || !(0, lodash_1.isEqual)(newDoc, found)) {
38
42
  return Object.assign(Object.assign({}, found), newDoc);
39
43
  }
@@ -53,10 +57,9 @@ function syncGlobalUsers() {
53
57
  return __awaiter(this, void 0, void 0, function* () {
54
58
  // sync user metadata
55
59
  const db = backend_core_1.context.getAppDB();
56
- const [users, metadata] = yield Promise.all([
57
- (0, global_1.getGlobalUsers)(),
58
- rawUserMetadata(),
59
- ]);
60
+ const resp = yield Promise.all([(0, global_1.getGlobalUsers)(), rawUserMetadata()]);
61
+ const users = resp[0];
62
+ const metadata = resp[1];
60
63
  const toWrite = [];
61
64
  for (let user of users) {
62
65
  const combined = combineMetadataAndUser(user, metadata);
@@ -64,6 +67,20 @@ function syncGlobalUsers() {
64
67
  toWrite.push(combined);
65
68
  }
66
69
  }
70
+ let foundEmails = [];
71
+ for (let data of metadata) {
72
+ if (!data._id) {
73
+ continue;
74
+ }
75
+ const alreadyExisting = data.email && foundEmails.indexOf(data.email) !== -1;
76
+ const globalId = (0, utils_1.getGlobalIDFromUserMetadataID)(data._id);
77
+ if (!users.find(user => user._id === globalId) || alreadyExisting) {
78
+ toWrite.push(Object.assign(Object.assign({}, data), { _deleted: true }));
79
+ }
80
+ if (data.email) {
81
+ foundEmails.push(data.email);
82
+ }
83
+ }
67
84
  yield db.bulkDocs(toWrite);
68
85
  });
69
86
  }
package/dist/startup.js CHANGED
@@ -44,17 +44,15 @@ const fs_1 = __importDefault(require("fs"));
44
44
  const watch_1 = require("./watch");
45
45
  const automations = __importStar(require("./automations"));
46
46
  const fileSystem = __importStar(require("./utilities/fileSystem"));
47
- const events_1 = __importDefault(require("./events"));
47
+ const events_1 = __importStar(require("./events"));
48
48
  const migrations = __importStar(require("./migrations"));
49
49
  const bullboard = __importStar(require("./automations/bullboard"));
50
50
  const pro = __importStar(require("@budibase/pro"));
51
51
  const api = __importStar(require("./api"));
52
52
  const sdk_1 = __importDefault(require("./sdk"));
53
- const pino = require("koa-pino-logger");
54
53
  let STARTUP_RAN = false;
55
54
  function initRoutes(app) {
56
55
  return __awaiter(this, void 0, void 0, function* () {
57
- app.use(pino(backend_core_1.logging.pinoSettings()));
58
56
  if (!environment_1.default.isTest()) {
59
57
  const plugin = yield bullboard.init();
60
58
  app.use(plugin);
@@ -79,8 +77,10 @@ function initPro() {
79
77
  });
80
78
  }
81
79
  function shutdown(server) {
82
- server.close();
83
- server.destroy();
80
+ if (server) {
81
+ server.close();
82
+ server.destroy();
83
+ }
84
84
  }
85
85
  function startup(app, server) {
86
86
  var _a;
@@ -96,6 +96,7 @@ function startup(app, server) {
96
96
  events_1.default.emitPort(environment_1.default.PORT);
97
97
  fileSystem.init();
98
98
  yield redis.init();
99
+ (0, events_1.init)();
99
100
  // run migrations on startup if not done via http
100
101
  // not recommended in a clustered environment
101
102
  if (!environment_1.default.HTTP_MIGRATIONS && !environment_1.default.isTest()) {
@@ -104,29 +105,7 @@ function startup(app, server) {
104
105
  }
105
106
  catch (e) {
106
107
  backend_core_1.logging.logAlert("Error performing migrations. Exiting.", e);
107
- shutdown();
108
- }
109
- }
110
- // check and create admin user if required
111
- if (environment_1.default.SELF_HOSTED &&
112
- !environment_1.default.MULTI_TENANCY &&
113
- environment_1.default.BB_ADMIN_USER_EMAIL &&
114
- environment_1.default.BB_ADMIN_USER_PASSWORD) {
115
- const checklist = yield (0, workerRequests_1.getChecklist)();
116
- if (!((_a = checklist === null || checklist === void 0 ? void 0 : checklist.adminUser) === null || _a === void 0 ? void 0 : _a.checked)) {
117
- try {
118
- const tenantId = backend_core_1.tenancy.getTenantId();
119
- const user = yield (0, workerRequests_1.createAdminUser)(environment_1.default.BB_ADMIN_USER_EMAIL, environment_1.default.BB_ADMIN_USER_PASSWORD, tenantId);
120
- // Need to set up an API key for automated integration tests
121
- if (environment_1.default.isTest()) {
122
- yield (0, workerRequests_1.generateApiKey)(user._id);
123
- }
124
- console.log("Admin account automatically created for", environment_1.default.BB_ADMIN_USER_EMAIL);
125
- }
126
- catch (e) {
127
- backend_core_1.logging.logAlert("Error creating initial admin user. Exiting.", e);
128
- shutdown();
129
- }
108
+ shutdown(server);
130
109
  }
131
110
  }
132
111
  // monitor plugin directory if required
@@ -150,6 +129,30 @@ function startup(app, server) {
150
129
  // bring routes online as final step once everything ready
151
130
  yield initRoutes(app);
152
131
  }
132
+ // check and create admin user if required
133
+ // this must be run after the api has been initialised due to
134
+ // the app user sync
135
+ if (environment_1.default.SELF_HOSTED &&
136
+ !environment_1.default.MULTI_TENANCY &&
137
+ environment_1.default.BB_ADMIN_USER_EMAIL &&
138
+ environment_1.default.BB_ADMIN_USER_PASSWORD) {
139
+ const checklist = yield (0, workerRequests_1.getChecklist)();
140
+ if (!((_a = checklist === null || checklist === void 0 ? void 0 : checklist.adminUser) === null || _a === void 0 ? void 0 : _a.checked)) {
141
+ try {
142
+ const tenantId = backend_core_1.tenancy.getTenantId();
143
+ const user = yield (0, workerRequests_1.createAdminUser)(environment_1.default.BB_ADMIN_USER_EMAIL, environment_1.default.BB_ADMIN_USER_PASSWORD, tenantId);
144
+ // Need to set up an API key for automated integration tests
145
+ if (environment_1.default.isTest()) {
146
+ yield (0, workerRequests_1.generateApiKey)(user._id);
147
+ }
148
+ console.log("Admin account automatically created for", environment_1.default.BB_ADMIN_USER_EMAIL);
149
+ }
150
+ catch (e) {
151
+ backend_core_1.logging.logAlert("Error creating initial admin user. Exiting.", e);
152
+ shutdown(server);
153
+ }
154
+ }
155
+ }
153
156
  });
154
157
  }
155
158
  exports.startup = startup;
@@ -52,14 +52,14 @@ const string_templates_1 = require("@budibase/string-templates");
52
52
  const fp_1 = require("lodash/fp");
53
53
  const sdkUtils = __importStar(require("../sdk/utils"));
54
54
  const environment_1 = __importDefault(require("../environment"));
55
- const FILTER_STEP_ID = actions.ACTION_DEFINITIONS.FILTER.stepId;
56
- const LOOP_STEP_ID = actions.ACTION_DEFINITIONS.LOOP.stepId;
55
+ const FILTER_STEP_ID = actions.BUILTIN_ACTION_DEFINITIONS.FILTER.stepId;
56
+ const LOOP_STEP_ID = actions.BUILTIN_ACTION_DEFINITIONS.LOOP.stepId;
57
57
  const CRON_STEP_ID = triggerInfo_1.definitions.CRON.stepId;
58
58
  const STOPPED_STATUS = { success: true, status: types_1.AutomationStatus.STOPPED };
59
59
  function getLoopIterations(loopStep, input) {
60
60
  const binding = automationUtils.typecastForLooping(loopStep, input);
61
- if (!loopStep || !binding) {
62
- return 1;
61
+ if (!binding) {
62
+ return 0;
63
63
  }
64
64
  if (Array.isArray(binding)) {
65
65
  return binding.length;
@@ -67,7 +67,7 @@ function getLoopIterations(loopStep, input) {
67
67
  if (typeof binding === "string") {
68
68
  return automationUtils.stringSplit(binding).length;
69
69
  }
70
- return 1;
70
+ return 0;
71
71
  }
72
72
  /**
73
73
  * The automation orchestrator is a class responsible for executing automations.
@@ -372,6 +372,17 @@ class Orchestrator {
372
372
  }
373
373
  }
374
374
  }
375
+ if (loopStep && iterations === 0) {
376
+ loopStep = undefined;
377
+ this.executionOutput.steps.splice(loopStepNumber + 1, 0, {
378
+ id: step.id,
379
+ stepId: step.stepId,
380
+ outputs: { status: types_1.AutomationStatus.NO_ITERATIONS, success: true },
381
+ inputs: {},
382
+ });
383
+ this._context.steps.splice(loopStepNumber, 1);
384
+ iterations = 1;
385
+ }
375
386
  // Delete the step after the loop step as it's irrelevant, since information is included
376
387
  // in the loop step
377
388
  if (wasLoopStep && !loopStep) {