notherbase-fs 4.0.21 → 4.0.23

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 (54) hide show
  1. package/README.md +6 -6
  2. package/controllers/creation.js +147 -147
  3. package/controllers/spirit-world.js +174 -174
  4. package/controllers/user.js +240 -240
  5. package/controllers/util.js +64 -64
  6. package/models/index.js +33 -33
  7. package/models/send-mail.js +58 -58
  8. package/models/spirit.js +234 -234
  9. package/notherbase-fs.js +112 -111
  10. package/package.json +40 -40
  11. package/public/js/base.js +222 -227
  12. package/public/js/chat-box.js +120 -120
  13. package/test/coast/tall-beach/nono-cove/index.css +17 -17
  14. package/test/coast/tall-beach/nono-cove/index.ejs +29 -29
  15. package/test/coast/tall-beach/nono-cove/nono-og/add-gold.js +15 -15
  16. package/test/coast/tall-beach/nono-cove/nono-og/index.ejs +46 -46
  17. package/test/coast/tall-beach/nono-cove/nono-og/nono.css +88 -88
  18. package/test/coast/tall-beach/nono-cove/nono-og/nono.js +207 -207
  19. package/test/pages/test-page/emailTime.js +8 -8
  20. package/test/pages/test-page/index.ejs +104 -104
  21. package/test/pages/void/index.ejs +35 -35
  22. package/test/pages/void/void.css +2 -2
  23. package/test/public/styles/main.css +792 -792
  24. package/test/the-front/add-gold.js +13 -13
  25. package/test/the-front/check/check.css +2 -2
  26. package/test/the-front/check/emailTime.js +9 -9
  27. package/test/the-front/check/flip.js +9 -9
  28. package/test/the-front/check/index.ejs +54 -54
  29. package/test/the-front/check/save-input.js +7 -7
  30. package/test/the-front/index.ejs +116 -99
  31. package/test/the-front/keeper/clipboards.js +133 -133
  32. package/test/the-front/keeper/index.ejs +80 -80
  33. package/test/the-front/keeper/keeper.css +157 -157
  34. package/test/the-front/keeper/keeper.js +140 -140
  35. package/test-index.js +19 -19
  36. package/test2/pages/test-page/emailTime.js +8 -8
  37. package/test2/pages/test-page/index.ejs +104 -104
  38. package/test2/pages/void/index.ejs +35 -35
  39. package/test2/pages/void/void.css +2 -2
  40. package/test2/public/styles/main.css +792 -792
  41. package/test2/the-front/add-gold.js +13 -13
  42. package/test2/the-front/check/check.css +2 -2
  43. package/test2/the-front/check/emailTime.js +9 -9
  44. package/test2/the-front/check/flip.js +9 -9
  45. package/test2/the-front/check/index.ejs +54 -54
  46. package/test2/the-front/check/save-input.js +7 -7
  47. package/test2/the-front/index.ejs +99 -99
  48. package/test2/the-front/keeper/clipboards.js +133 -133
  49. package/test2/the-front/keeper/index.ejs +80 -80
  50. package/test2/the-front/keeper/keeper.css +157 -157
  51. package/test2/the-front/keeper/keeper.js +140 -140
  52. package/views/explorer.ejs +82 -82
  53. package/views/footer.ejs +9 -9
  54. package/views/head.ejs +17 -17
package/models/index.js CHANGED
@@ -1,34 +1,34 @@
1
- import mongoose from "mongoose";
2
- import dotenv from "dotenv";
3
- dotenv.config();
4
- import Spirit from "./spirit.js";
5
- import SendMail from "./send-mail.js";
6
-
7
- mongoose.set('strictQuery', true);
8
-
9
- mongoose.connection.on('connected', (err) => {
10
- console.log(`Mongoose connected to db`);
11
- });
12
-
13
- mongoose.connection.on('error', (err) => {
14
- console.log(`Mongoose ${err}`);
15
- });
16
-
17
- mongoose.connection.on('disconnected', () => {
18
- console.log('Mongoose disconnected');
19
- });
20
-
21
- try {
22
- mongoose.connect(process.env.MONGODB_URI, {
23
- useNewUrlParser: true,
24
- useUnifiedTopology: true
25
- });
26
- }
27
- catch (err) {
28
- console.log(`Mongoose on connect: ${err}`);
29
- }
30
-
31
- export default {
32
- SendMail: SendMail,
33
- Spirit: Spirit
1
+ import mongoose from "mongoose";
2
+ import dotenv from "dotenv";
3
+ dotenv.config();
4
+ import Spirit from "./spirit.js";
5
+ import SendMail from "./send-mail.js";
6
+
7
+ mongoose.set('strictQuery', true);
8
+
9
+ mongoose.connection.on('connected', (err) => {
10
+ console.log(`Mongoose connected to db`);
11
+ });
12
+
13
+ mongoose.connection.on('error', (err) => {
14
+ console.log(`Mongoose ${err}`);
15
+ });
16
+
17
+ mongoose.connection.on('disconnected', () => {
18
+ console.log('Mongoose disconnected');
19
+ });
20
+
21
+ try {
22
+ mongoose.connect(process.env.MONGODB_URI, {
23
+ useNewUrlParser: true,
24
+ useUnifiedTopology: true
25
+ });
26
+ }
27
+ catch (err) {
28
+ console.log(`Mongoose on connect: ${err}`);
29
+ }
30
+
31
+ export default {
32
+ SendMail: SendMail,
33
+ Spirit: Spirit
34
34
  }
@@ -1,59 +1,59 @@
1
- import dotenv from "dotenv";
2
- dotenv.config();
3
- import nodemailer from "nodemailer";
4
- import { google } from "googleapis";
5
-
6
- const OAuth2 = google.auth.OAuth2;
7
- const OAuth2Client = new OAuth2(process.env.CLIENTID, process.env.CLIENTSECRET);
8
- OAuth2Client.setCredentials({ refresh_token: process.env.CLIENTREFRESH });
9
-
10
-
11
- /**
12
- * Sends an email with a password reset code. WIP
13
- * @param {String} toEmail Email address to send to.
14
- * @param {Number} resetToken Token to reset by.
15
- */
16
- const passwordReset = async (toEmail, resetToken) => {
17
- return await send(toEmail, 'Password Reset for NotherBase',
18
- `<h1>Your One-Time Password Reset Code:<h1>
19
- <h2>${resetToken}<h2>
20
- <p>Visit <a href="https://www.notherbase.com/the-front/keeper">notherbase.com/the-front/keeper</a> to finish changing your password.</p>`);
21
- };
22
-
23
- /**
24
- * Sends an email. WIP
25
- * @param {String} toEmail Email Address to send to.
26
- * @param {String} subject Subject of the email.
27
- * @param {String} html Body of the email.
28
- * @returns
29
- */
30
- const send = async (toEmail, subject, html, name = "NotherBase") => {
31
- let accessToken = OAuth2Client.getAccessToken();
32
-
33
- let transporter = nodemailer.createTransport({
34
- service: 'gmail',
35
- auth: {
36
- type: 'OAuth2',
37
- user: process.env.NOREPLY,
38
- clientId: process.env.CLIENTID,
39
- clientSecret: process.env.CLIENTSECRET,
40
- refreshToken: process.env.CLIENTREFRESH,
41
- accessToken: accessToken
42
- }
43
- });
44
-
45
- let mailOptions = {
46
- from: name + " <" + process.env.NOREPLY +">",
47
- to: toEmail,
48
- subject: subject,
49
- html: html
50
- };
51
-
52
- let sent = await transporter.sendMail(mailOptions, function(error, info){
53
- if (error) console.log(error);
54
- });
55
-
56
- return sent;
57
- }
58
-
1
+ import dotenv from "dotenv";
2
+ dotenv.config();
3
+ import nodemailer from "nodemailer";
4
+ import { google } from "googleapis";
5
+
6
+ const OAuth2 = google.auth.OAuth2;
7
+ const OAuth2Client = new OAuth2(process.env.CLIENTID, process.env.CLIENTSECRET);
8
+ OAuth2Client.setCredentials({ refresh_token: process.env.CLIENTREFRESH });
9
+
10
+
11
+ /**
12
+ * Sends an email with a password reset code. WIP
13
+ * @param {String} toEmail Email address to send to.
14
+ * @param {Number} resetToken Token to reset by.
15
+ */
16
+ const passwordReset = async (toEmail, resetToken) => {
17
+ return await send(toEmail, 'Password Reset for NotherBase',
18
+ `<h1>Your One-Time Password Reset Code:<h1>
19
+ <h2>${resetToken}<h2>
20
+ <p>Visit <a href="https://www.notherbase.com/the-front/keeper">notherbase.com/the-front/keeper</a> to finish changing your password.</p>`);
21
+ };
22
+
23
+ /**
24
+ * Sends an email. WIP
25
+ * @param {String} toEmail Email Address to send to.
26
+ * @param {String} subject Subject of the email.
27
+ * @param {String} html Body of the email.
28
+ * @returns
29
+ */
30
+ const send = async (toEmail, subject, html, name = "NotherBase") => {
31
+ let accessToken = OAuth2Client.getAccessToken();
32
+
33
+ let transporter = nodemailer.createTransport({
34
+ service: 'gmail',
35
+ auth: {
36
+ type: 'OAuth2',
37
+ user: process.env.NOREPLY,
38
+ clientId: process.env.CLIENTID,
39
+ clientSecret: process.env.CLIENTSECRET,
40
+ refreshToken: process.env.CLIENTREFRESH,
41
+ accessToken: accessToken
42
+ }
43
+ });
44
+
45
+ let mailOptions = {
46
+ from: name + " <" + process.env.NOREPLY +">",
47
+ to: toEmail,
48
+ subject: subject,
49
+ html: html
50
+ };
51
+
52
+ let sent = await transporter.sendMail(mailOptions, function(error, info){
53
+ if (error) console.log(error);
54
+ });
55
+
56
+ return sent;
57
+ }
58
+
59
59
  export default { passwordReset, send };
package/models/spirit.js CHANGED
@@ -1,235 +1,235 @@
1
- import mongoose from "mongoose";
2
-
3
- /**
4
- * Curated Mongoose.js documents for use in bases.
5
- */
6
- export default class Spirit {
7
- // The actual Mongoose.js model for accessing the database.
8
- static db = mongoose.model('spirits', new mongoose.Schema({
9
- _lastUpdate: Number,
10
- service: String,
11
- parent: {
12
- type: mongoose.Schema.Types.ObjectId,
13
- ref: "spirits",
14
- required: false
15
- },
16
- data: {},
17
- backups: []
18
- }));
19
-
20
- /**
21
- * Builds query objects for Mongoose.js searches.
22
- * @param {String} service The name of the spirit.
23
- * @param {Object} data An object with data to query the spirit by.
24
- * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
25
- * @param {ObjectID} id The exact id of the MongoDB document.
26
- * @returns A query object.
27
- */
28
- static buildQuery = (service, data = null, parent = null, id = null) => {
29
- let query = {
30
- parent: parent
31
- };
32
-
33
- if (service) query.service = service;
34
- if (id) query._id = id;
35
- else if (data){
36
- let keys = Object.keys(data);
37
- for (let i = 0; i < keys.length; i++) {
38
- query[`data.${keys[i]}`] = data[keys[i]];
39
- }
40
- }
41
-
42
- return query;
43
- }
44
-
45
- // static buildBackupQuery = (service, data = null, parent = null, id = null) => {
46
- // let query = {
47
- // service: service,
48
- // parent: parent
49
- // };
50
-
51
- // if (id) query._id = id;
52
- // else if (data){
53
- // let keys = Object.keys(data);
54
- // for (let i = 0; i < keys.length; i++) {
55
-
56
- // query[`data.backups.0.data.${keys[i]}`] = data[keys[i]];
57
- // }
58
- // }
59
-
60
- // return query;
61
- // }
62
-
63
- /**
64
- * Creates a spirit in the database.
65
- * @param {String} service The name of the spirit.
66
- * @param {Object} data An object with data to create the spirit with.
67
- * @param {ObjectID} parent The MongoDB id of the parent of the spirit to be created.
68
- * @returns A new spirit.
69
- */
70
- static create = async (service, data = {}, parent = null) => {
71
- let spirit = new Spirit();
72
-
73
- spirit.memory = await Spirit.db.create({
74
- service,
75
- parent,
76
- _lastUpdate: Date.now(),
77
- data: data,
78
- backups: []
79
- });
80
-
81
- return spirit;
82
- }
83
-
84
- /**
85
- * Recalls all spirits in the database with a given name.
86
- * @param {String} service The name of the spirit.
87
- * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
88
- * @param {Object} data An object with data to query the spirit by.
89
- * @param {ObjectID} id The exact id of the MongoDB document.
90
- * @returns All spirits found.
91
- */
92
- static recallAll = async (service, parent = null, data = {}, id = null) => {
93
- let spirits = [];
94
-
95
- let query = Spirit.buildQuery(service, data, parent, id);
96
-
97
- let found = await Spirit.db.find(query);
98
-
99
- if (found) {
100
- for (let i = 0; i < found.length; i++) {
101
- let spirit = new Spirit(found[i]);
102
- spirits.push(spirit);
103
- // convert old backups to new format
104
- if (spirit.memory.data?._backupsEnabled) {
105
- spirit.memory.backups = spirit.memory.data.backups;
106
- spirit.memory.data = spirit.memory.backups[0].data;
107
- spirit.memory.markModified("backups");
108
- await spirit.commit();
109
- }
110
- }
111
-
112
- return spirits;
113
- }
114
- else return null;
115
- }
116
-
117
- /**
118
- * Recalls one spirit from the database or creates a new one.
119
- * @param {String} service The name of the spirit.
120
- * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
121
- * @param {Object} data An object with data to query the spirit by.
122
- * @param {ObjectID} id The exact id of the MongoDB document.
123
- * @returns The spirit found or a new one created in the database.
124
- */
125
- static recallOne = async (service, parent = null, data = {}, id = null) => {
126
- let spirit = null;
127
-
128
- let query = Spirit.buildQuery(service, data, parent, id);
129
-
130
- let found = await Spirit.db.findOne(query);
131
-
132
- if (found) {
133
- spirit = new Spirit(found);
134
-
135
- // convert old backups to new format
136
- if (spirit.memory.data?._backupsEnabled) {
137
- spirit.memory.backups = spirit.memory.data.backups;
138
- spirit.memory.data = spirit.memory.backups[0].data;
139
- spirit.memory.markModified("backups");
140
- await spirit.commit();
141
- }
142
-
143
- return spirit;
144
- }
145
- else return null;
146
- }
147
-
148
- /**
149
- * Recalls or creates a spirit in the database.
150
- * @param {String} service The name of the spirit.
151
- * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
152
- * @param {Object} data An object with data to query the spirit by.
153
- * @param {ObjectID} id The exact id of the MongoDB document.
154
- * @returns The spirit found or a new one created in the database.
155
- */
156
- static recallOrCreateOne = async (service, parent = null, data = {}, id = null) => {
157
- let spirit = null;
158
-
159
- let query = Spirit.buildQuery(service, data, parent, id);
160
-
161
- let found = await Spirit.db.findOne(query);
162
-
163
- if (found) spirit = new Spirit(found);
164
- else spirit = await Spirit.create(service, data, parent);
165
-
166
- // convert old backups to new format
167
- if (spirit.memory.data?._backupsEnabled) {
168
- spirit.memory.backups = spirit.memory.data.backups;
169
- spirit.memory.data = spirit.memory.backups[0].data;
170
- spirit.memory.markModified("backups");
171
- await spirit.commit();
172
- }
173
-
174
- return spirit;
175
- }
176
-
177
- /**
178
- * Deletes all of the specified spirit.
179
- * @param {String} service The name of the spirit.
180
- * @param {ObjectID} parent The MongoDB id of the parent spirit to search with.
181
- * @param {Object} data An object with data to query the spirit by.
182
- * @param {ObjectID} id The exact id of the MongoDB document.
183
- * @returns The number of documents deleted.
184
- */
185
- static delete = async (service, parent = null, data = {}, id = null) => {
186
- let found = await Spirit.db.deleteMany(Spirit.buildQuery(service, data, parent, id));
187
-
188
- return found.deletedCount;
189
- }
190
-
191
- constructor(memory = {}) {
192
- this.memory = memory;
193
- }
194
-
195
- /**
196
- * Commits new data to a spirit.
197
- * @param {Object} data Data to save.
198
- * @returns Updated
199
- */
200
- commit = async (data = this.memory.data) => {
201
- this.memory._lastUpdate = Date.now();
202
-
203
- this.memory.data = data;
204
- this.memory.markModified("data");
205
- await this.memory.save();
206
-
207
- return "Updated";
208
- }
209
-
210
- /**
211
- * Normalizes the data property to an array.
212
- */
213
- normalizeDataToArray = () => {
214
- if (!Array.isArray(this.memory.data)) this.memory.data = [];
215
- }
216
-
217
- /**
218
- * Adds a new backup to the spirit's data.
219
- * @param {Object} data Data to add to the backup.
220
- */
221
- addBackup = (data, max = 5) => {
222
- this.memory.backups.unshift({
223
- _lastUpdate: Date.now(),
224
- data: this.memory.data
225
- });
226
-
227
- this.memory.data = data;
228
-
229
- if (max > 1) {
230
- while (this.memory.backups.length > max) this.memory.backups.pop();
231
- }
232
-
233
- this.memory.markModified("backups");
234
- }
1
+ import mongoose from "mongoose";
2
+
3
+ /**
4
+ * Curated Mongoose.js documents for use in bases.
5
+ */
6
+ export default class Spirit {
7
+ // The actual Mongoose.js model for accessing the database.
8
+ static db = mongoose.model('spirits', new mongoose.Schema({
9
+ _lastUpdate: Number,
10
+ service: String,
11
+ parent: {
12
+ type: mongoose.Schema.Types.ObjectId,
13
+ ref: "spirits",
14
+ required: false
15
+ },
16
+ data: {},
17
+ backups: []
18
+ }));
19
+
20
+ /**
21
+ * Builds query objects for Mongoose.js searches.
22
+ * @param {String} service The name of the spirit.
23
+ * @param {Object} data An object with data to query the spirit by.
24
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
25
+ * @param {ObjectID} id The exact id of the MongoDB document.
26
+ * @returns A query object.
27
+ */
28
+ static buildQuery = (service, data = null, parent = null, id = null) => {
29
+ let query = {
30
+ parent: parent
31
+ };
32
+
33
+ if (service) query.service = service;
34
+ if (id) query._id = id;
35
+ else if (data){
36
+ let keys = Object.keys(data);
37
+ for (let i = 0; i < keys.length; i++) {
38
+ query[`data.${keys[i]}`] = data[keys[i]];
39
+ }
40
+ }
41
+
42
+ return query;
43
+ }
44
+
45
+ // static buildBackupQuery = (service, data = null, parent = null, id = null) => {
46
+ // let query = {
47
+ // service: service,
48
+ // parent: parent
49
+ // };
50
+
51
+ // if (id) query._id = id;
52
+ // else if (data){
53
+ // let keys = Object.keys(data);
54
+ // for (let i = 0; i < keys.length; i++) {
55
+
56
+ // query[`data.backups.0.data.${keys[i]}`] = data[keys[i]];
57
+ // }
58
+ // }
59
+
60
+ // return query;
61
+ // }
62
+
63
+ /**
64
+ * Creates a spirit in the database.
65
+ * @param {String} service The name of the spirit.
66
+ * @param {Object} data An object with data to create the spirit with.
67
+ * @param {ObjectID} parent The MongoDB id of the parent of the spirit to be created.
68
+ * @returns A new spirit.
69
+ */
70
+ static create = async (service, data = {}, parent = null) => {
71
+ let spirit = new Spirit();
72
+
73
+ spirit.memory = await Spirit.db.create({
74
+ service,
75
+ parent,
76
+ _lastUpdate: Date.now(),
77
+ data: data,
78
+ backups: []
79
+ });
80
+
81
+ return spirit;
82
+ }
83
+
84
+ /**
85
+ * Recalls all spirits in the database with a given name.
86
+ * @param {String} service The name of the spirit.
87
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
88
+ * @param {Object} data An object with data to query the spirit by.
89
+ * @param {ObjectID} id The exact id of the MongoDB document.
90
+ * @returns All spirits found.
91
+ */
92
+ static recallAll = async (service, parent = null, data = {}, id = null) => {
93
+ let spirits = [];
94
+
95
+ let query = Spirit.buildQuery(service, data, parent, id);
96
+
97
+ let found = await Spirit.db.find(query);
98
+
99
+ if (found) {
100
+ for (let i = 0; i < found.length; i++) {
101
+ let spirit = new Spirit(found[i]);
102
+ spirits.push(spirit);
103
+ // convert old backups to new format
104
+ if (spirit.memory.data?._backupsEnabled) {
105
+ spirit.memory.backups = spirit.memory.data.backups;
106
+ spirit.memory.data = spirit.memory.backups[0].data;
107
+ spirit.memory.markModified("backups");
108
+ await spirit.commit();
109
+ }
110
+ }
111
+
112
+ return spirits;
113
+ }
114
+ else return null;
115
+ }
116
+
117
+ /**
118
+ * Recalls one spirit from the database or creates a new one.
119
+ * @param {String} service The name of the spirit.
120
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
121
+ * @param {Object} data An object with data to query the spirit by.
122
+ * @param {ObjectID} id The exact id of the MongoDB document.
123
+ * @returns The spirit found or a new one created in the database.
124
+ */
125
+ static recallOne = async (service, parent = null, data = {}, id = null) => {
126
+ let spirit = null;
127
+
128
+ let query = Spirit.buildQuery(service, data, parent, id);
129
+
130
+ let found = await Spirit.db.findOne(query);
131
+
132
+ if (found) {
133
+ spirit = new Spirit(found);
134
+
135
+ // convert old backups to new format
136
+ if (spirit.memory.data?._backupsEnabled) {
137
+ spirit.memory.backups = spirit.memory.data.backups;
138
+ spirit.memory.data = spirit.memory.backups[0].data;
139
+ spirit.memory.markModified("backups");
140
+ await spirit.commit();
141
+ }
142
+
143
+ return spirit;
144
+ }
145
+ else return null;
146
+ }
147
+
148
+ /**
149
+ * Recalls or creates a spirit in the database.
150
+ * @param {String} service The name of the spirit.
151
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search by.
152
+ * @param {Object} data An object with data to query the spirit by.
153
+ * @param {ObjectID} id The exact id of the MongoDB document.
154
+ * @returns The spirit found or a new one created in the database.
155
+ */
156
+ static recallOrCreateOne = async (service, parent = null, data = {}, id = null) => {
157
+ let spirit = null;
158
+
159
+ let query = Spirit.buildQuery(service, data, parent, id);
160
+
161
+ let found = await Spirit.db.findOne(query);
162
+
163
+ if (found) spirit = new Spirit(found);
164
+ else spirit = await Spirit.create(service, data, parent);
165
+
166
+ // convert old backups to new format
167
+ if (spirit.memory.data?._backupsEnabled) {
168
+ spirit.memory.backups = spirit.memory.data.backups;
169
+ spirit.memory.data = spirit.memory.backups[0].data;
170
+ spirit.memory.markModified("backups");
171
+ await spirit.commit();
172
+ }
173
+
174
+ return spirit;
175
+ }
176
+
177
+ /**
178
+ * Deletes all of the specified spirit.
179
+ * @param {String} service The name of the spirit.
180
+ * @param {ObjectID} parent The MongoDB id of the parent spirit to search with.
181
+ * @param {Object} data An object with data to query the spirit by.
182
+ * @param {ObjectID} id The exact id of the MongoDB document.
183
+ * @returns The number of documents deleted.
184
+ */
185
+ static delete = async (service, parent = null, data = {}, id = null) => {
186
+ let found = await Spirit.db.deleteMany(Spirit.buildQuery(service, data, parent, id));
187
+
188
+ return found.deletedCount;
189
+ }
190
+
191
+ constructor(memory = {}) {
192
+ this.memory = memory;
193
+ }
194
+
195
+ /**
196
+ * Commits new data to a spirit.
197
+ * @param {Object} data Data to save.
198
+ * @returns Updated
199
+ */
200
+ commit = async (data = this.memory.data) => {
201
+ this.memory._lastUpdate = Date.now();
202
+
203
+ this.memory.data = data;
204
+ this.memory.markModified("data");
205
+ await this.memory.save();
206
+
207
+ return "Updated";
208
+ }
209
+
210
+ /**
211
+ * Normalizes the data property to an array.
212
+ */
213
+ normalizeDataToArray = () => {
214
+ if (!Array.isArray(this.memory.data)) this.memory.data = [];
215
+ }
216
+
217
+ /**
218
+ * Adds a new backup to the spirit's data.
219
+ * @param {Object} data Data to add to the backup.
220
+ */
221
+ addBackup = (data, max = 5) => {
222
+ this.memory.backups.unshift({
223
+ _lastUpdate: Date.now(),
224
+ data: this.memory.data
225
+ });
226
+
227
+ this.memory.data = data;
228
+
229
+ if (max > 1) {
230
+ while (this.memory.backups.length > max) this.memory.backups.pop();
231
+ }
232
+
233
+ this.memory.markModified("backups");
234
+ }
235
235
  };