notu 0.6.2 → 0.7.0

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.
package/dist/notu.mjs CHANGED
@@ -40,7 +40,6 @@ class Attr extends ModelWithState {
40
40
  __publicField(this, "_name", "");
41
41
  __publicField(this, "_description", "");
42
42
  __publicField(this, "_type", "TEXT");
43
- __publicField(this, "_spaceId", 0);
44
43
  __publicField(this, "_space", null);
45
44
  name && (this.name = name), description && (this.description = description);
46
45
  }
@@ -88,29 +87,26 @@ class Attr extends ModelWithState {
88
87
  asDate() {
89
88
  return this.type = "DATE", this;
90
89
  }
91
- get spaceId() {
92
- return this._spaceId;
93
- }
94
- set spaceId(value) {
95
- var _a;
96
- value !== this._spaceId && (this._spaceId = value, value !== ((_a = this.space) == null ? void 0 : _a.id) && (this._space = null), this.isClean && this.dirty());
97
- }
98
90
  get space() {
99
91
  return this._space;
100
92
  }
101
93
  set space(value) {
102
- this._space = value, this.spaceId = (value == null ? void 0 : value.id) ?? 0;
94
+ var _a;
95
+ if (value !== this._space) {
96
+ const idChanged = (value == null ? void 0 : value.id) != ((_a = this._space) == null ? void 0 : _a.id);
97
+ this._space = value, this.isClean && idChanged && this.dirty();
98
+ }
103
99
  }
104
100
  in(space) {
105
- return typeof space == "number" ? this.spaceId = space : this.space = space, this;
101
+ return this.space = space, this;
106
102
  }
107
103
  duplicate() {
108
104
  const output = new Attr();
109
- return output.id = this.id, output.name = this.name, output.description = this.description, output.type = this.type, this.space ? output.space = this.space : output.spaceId = this.spaceId, output.state = this.state, output;
105
+ return output.id = this.id, output.name = this.name, output.description = this.description, output.type = this.type, output.space = this.space, output.state = this.state, output;
110
106
  }
111
107
  validate(throwError = !1) {
112
108
  let output = null;
113
- if (this.spaceId <= 0 ? output = "Note spaceId must be greater than zero." : !this.isNew && this.id <= 0 && (output = "Attr id must be greater than zero if in non-new state."), throwError && output != null)
109
+ if (this.space ? !this.isNew && this.id <= 0 && (output = "Attr id must be greater than zero if in non-new state.") : output = "Attr must belong to a space.", throwError && output != null)
114
110
  throw Error(output);
115
111
  return output == null;
116
112
  }
@@ -127,158 +123,99 @@ class Attr extends ModelWithState {
127
123
  }
128
124
  }
129
125
  toJSON() {
126
+ var _a;
130
127
  return {
131
128
  state: this.state,
132
129
  id: this.id,
133
130
  name: this.name,
134
131
  description: this.description,
135
132
  type: this.type,
136
- spaceId: this.spaceId
133
+ spaceId: (_a = this.space) == null ? void 0 : _a.id
137
134
  };
138
135
  }
139
- static fromJSON(json) {
140
- const output = new Attr(json.name, json.description);
141
- return output.type = json.type, output.spaceId = json.spaceId, output.id = json.id, output.state = json.state, output;
142
- }
143
136
  }
144
- class CachedClient {
145
- constructor(internalClient) {
146
- __publicField(this, "_internalClient");
147
- //Caches
148
- __publicField(this, "_spaces", null);
149
- __publicField(this, "_attrs", null);
150
- __publicField(this, "_tags", null);
151
- this._internalClient = internalClient;
137
+ class Notu {
138
+ constructor(client, cache) {
139
+ __publicField(this, "_client");
140
+ __publicField(this, "_cache");
141
+ this._client = client, this._cache = cache;
152
142
  }
153
- _linkTagsToSpaces() {
154
- for (const tag of this._tags.values()) {
155
- const space = this._spaces.get(tag.spaceId);
156
- space && (tag.space = space);
157
- }
143
+ get client() {
144
+ return this._client;
158
145
  }
159
- _linkAttrsToSpaces() {
160
- for (const attr of this._attrs.values()) {
161
- const space = this._spaces.get(attr.spaceId);
162
- space && (attr.space = space);
163
- }
146
+ get cache() {
147
+ return this._cache;
164
148
  }
165
- /////////////////////////////////////
166
- // NotuClient implementation start //
167
- /////////////////////////////////////
168
149
  async login(username, password) {
169
- return await this._internalClient.login(username, password);
170
- }
171
- async getSpaces() {
172
- if (this._spaces == null) {
173
- const spaces = await this._internalClient.getSpaces();
174
- this._spaces = /* @__PURE__ */ new Map();
175
- for (const space of spaces)
176
- this._spaces.set(space.id, space);
177
- this._tags != null && this._linkTagsToSpaces(), this._attrs != null && this._linkAttrsToSpaces();
178
- }
179
- return [...this._spaces.values()];
150
+ return await this.client.login(username, password);
151
+ }
152
+ getSpaces() {
153
+ return this.cache.getSpaces();
154
+ }
155
+ getSpace(id) {
156
+ return this.cache.getSpace(id);
157
+ }
158
+ getSpaceByName(name) {
159
+ return this.cache.getSpaceByName(name);
180
160
  }
181
161
  async saveSpace(space) {
182
- const saveResult = await this._internalClient.saveSpace(space);
183
- return this._spaces != null && this._spaces.set(saveResult.id, saveResult), saveResult;
184
- }
185
- async getAttrs(spaceId) {
186
- if (this._attrs == null) {
187
- const attrs = await this._internalClient.getAttrs(spaceId);
188
- this._attrs = /* @__PURE__ */ new Map();
189
- for (const attr of attrs)
190
- this._attrs.set(attr.id, attr);
191
- this._spaces != null && this._linkAttrsToSpaces();
192
- }
193
- return [...this._attrs.values()];
162
+ const spaceData = await this.client.saveSpace(space);
163
+ return this.cache.spaceSaved(spaceData);
164
+ }
165
+ getAttrs(space) {
166
+ return this.cache.getAttrs(space);
167
+ }
168
+ getAttr(id) {
169
+ return this.cache.getAttr(id);
170
+ }
171
+ getAttrByName(name, space) {
172
+ return this.cache.getAttrByName(name, space);
194
173
  }
195
174
  async saveAttr(attr) {
196
- const saveResult = await this._internalClient.saveAttr(attr);
197
- return this._attrs != null && this._attrs.set(saveResult.id, saveResult), saveResult;
198
- }
199
- async getTags() {
200
- if (this._tags == null) {
201
- const tags = await this._internalClient.getTags();
202
- this._tags = /* @__PURE__ */ new Map();
203
- for (const tag of tags)
204
- this._tags.set(tag.id, tag);
205
- this._spaces != null && this._linkTagsToSpaces();
206
- }
207
- return [...this._tags.values()];
175
+ const attrData = await this.client.saveAttr(attr);
176
+ return this.cache.attrSaved(attrData);
177
+ }
178
+ getTags(space = null, includeOtherSpacePublics = !1) {
179
+ return this.cache.getTags(space, includeOtherSpacePublics);
180
+ }
181
+ getTag(id) {
182
+ return this.cache.getTag(id);
183
+ }
184
+ getTagByName(name, space) {
185
+ return this.cache.getTagByName(name, space);
208
186
  }
209
187
  async getNotes(query, spaceId) {
210
- const results = await this._internalClient.getNotes(query, spaceId);
211
- if (this._spaces != null)
212
- for (const note of results) {
213
- const space = this._spaces.get(note.spaceId);
214
- space && (note.space = space);
215
- }
216
- if (this._attrs != null)
217
- for (const note of results)
218
- for (const na of note.allAttrs) {
219
- const attr = this._attrs.get(na.attrId);
220
- attr && (na.attr = attr, attr.isDate && !(na.value instanceof Date) && (na.value = new Date(na.value)), na.clean());
221
- }
222
- if (this._tags != null)
223
- for (const note of results) {
224
- {
225
- const tag = this._tags.get(note.id);
226
- tag && (note.setOwnTag(tag), note.clean(), note.ownTag.clean());
227
- }
228
- for (const nt of note.tags) {
229
- const tag = this._tags.get(nt.tagId);
230
- tag && (nt.tag = tag, nt.clean());
231
- }
232
- for (const na of note.allAttrs.filter((x) => x.tagId != null)) {
233
- const tag = this._tags.get(na.tagId);
234
- tag && (na.tag = tag, na.clean());
235
- }
236
- }
237
- return results;
188
+ return (await this.client.getNotes(query, spaceId)).map((n) => this.cache.noteFromJSON(n));
238
189
  }
239
190
  async getNoteCount(query, spaceId) {
240
- return await this._internalClient.getNoteCount(query, spaceId);
191
+ return await this.client.getNoteCount(query, spaceId);
241
192
  }
242
193
  async saveNotes(notes) {
243
- const saveResults = await this._internalClient.saveNotes(notes);
244
- if (this._tags != null)
245
- for (const note of saveResults.filter((x) => !!x.ownTag))
246
- this._tags.set(note.ownTag.id, note.ownTag);
247
- return saveResults;
194
+ const notesData = await this.client.saveNotes(notes);
195
+ for (const noteData of notesData.filter((x) => !!x.ownTag))
196
+ this.cache.tagSaved(noteData.ownTag);
197
+ return notes = notesData.map((n) => this.cache.noteFromJSON(n)), notes;
248
198
  }
249
199
  async customJob(name, data) {
250
- return await this._internalClient.customJob(name, data);
251
- }
252
- ///////////////////////////////////
253
- // NotuClient implementation end //
254
- ///////////////////////////////////
255
- //Synchronous cache methods
256
- //These are introduced to make it far easier to lookup the cached values
257
- //Especially in React where async is kind of a pain
258
- //Make sure this method has been called before any of the other methods in this section
259
- async cacheAll(spaceId = 0) {
260
- await this.getSpaces();
261
- const tagsPromise = this.getTags(), attrsPromise = this.getAttrs(spaceId);
262
- await Promise.all([tagsPromise, attrsPromise]);
263
- }
264
- get spaces() {
265
- return [...this._spaces.values()];
266
- }
267
- get tags() {
268
- return [...this._tags.values()];
269
- }
270
- get attrs() {
271
- return [...this._attrs.values()];
200
+ return await this.client.customJob(name, data);
272
201
  }
273
202
  }
274
203
  class Space extends ModelWithState {
275
204
  constructor(name = "") {
276
205
  super();
277
- __publicField(this, "id", 0);
206
+ __publicField(this, "_id", 0);
278
207
  __publicField(this, "_name", "");
279
208
  __publicField(this, "_version", "0.0.1");
280
209
  this._name = name;
281
210
  }
211
+ get id() {
212
+ return this._id;
213
+ }
214
+ set id(value) {
215
+ if (!this.isNew)
216
+ throw Error("Cannot change the id of a Space once it has already been created.");
217
+ this._id = value;
218
+ }
282
219
  get name() {
283
220
  return this._name;
284
221
  }
@@ -296,7 +233,7 @@ class Space extends ModelWithState {
296
233
  }
297
234
  duplicate() {
298
235
  const output = new Space();
299
- return output.id = this.id, output.name = this.name, output.state = this.state, output.version = this.version, output;
236
+ return output.id = this.id, output.name = this.name, output.version = this.version, output.state = this.state, output;
300
237
  }
301
238
  validate(throwError = !1) {
302
239
  let output = null;
@@ -312,12 +249,8 @@ class Space extends ModelWithState {
312
249
  version: this.version
313
250
  };
314
251
  }
315
- static fromJSON(json) {
316
- const output = new Space(json.name);
317
- return output.id = json.id, output.state = json.state, output.version = json.version, output;
318
- }
319
252
  }
320
- class HttpClient {
253
+ class NotuHttpClient {
321
254
  constructor(url, fetchMethod = null) {
322
255
  __publicField(this, "_url", null);
323
256
  __publicField(this, "_token", null);
@@ -337,81 +270,60 @@ class HttpClient {
337
270
  this._token = value;
338
271
  }
339
272
  async login(username, password) {
340
- const result = await this._fetch(
273
+ const response = await this._fetch(
341
274
  this.url + "/login",
342
275
  {
343
276
  method: "POST",
344
277
  body: JSON.stringify({ username, password })
345
278
  }
346
279
  );
347
- if (result.body != null) {
348
- const token = (await result.json()).token;
349
- if (token)
350
- return this._token = token, { success: !0, error: null, token: this._token };
280
+ if (response.body != null) {
281
+ const result = await response.json();
282
+ return result.token && (this._token = result.token), result;
351
283
  }
352
- return { success: !1, error: "Invalid username & password.", token: null };
284
+ return { token: null, error: "Unknown error occurred on the server" };
353
285
  }
354
- async getSpaces() {
355
- return (await (await this._fetch(
356
- this.url + "/spaces",
286
+ async setup() {
287
+ await (await this._fetch(
288
+ this.url + "/setup",
357
289
  {
358
- method: "GET",
290
+ method: "POST",
359
291
  headers: { Authorization: "Bearer " + this.token }
360
292
  }
361
- )).json()).map((x) => Space.fromJSON(x));
293
+ )).json();
362
294
  }
363
295
  async saveSpace(space) {
364
- const result = await this._fetch(
296
+ return await (await this._fetch(
365
297
  this.url + "/spaces",
366
298
  {
367
299
  method: "POST",
368
300
  body: JSON.stringify(space),
369
301
  headers: { Authorization: "Bearer " + this.token }
370
302
  }
371
- );
372
- return Space.fromJSON(await result.json());
373
- }
374
- async getAttrs(spaceId = 0) {
375
- return (await (await this._fetch(
376
- this.url + `/attrs?space=${spaceId}`,
377
- {
378
- method: "GET",
379
- headers: { Authorization: "Bearer " + this.token }
380
- }
381
- )).json()).map((x) => Attr.fromJSON(x));
303
+ )).json();
382
304
  }
383
305
  async saveAttr(attr) {
384
- const result = await this._fetch(
306
+ return await (await this._fetch(
385
307
  this.url + "/attrs",
386
308
  {
387
309
  method: "POST",
388
310
  body: JSON.stringify(attr),
389
311
  headers: { Authorization: "Bearer " + this.token }
390
312
  }
391
- );
392
- return Attr.fromJSON(await result.json());
393
- }
394
- async getTags() {
395
- return (await (await this._fetch(
396
- this.url + "/tags",
397
- {
398
- method: "GET",
399
- headers: { Authorization: "Bearer " + this.token }
400
- }
401
- )).json()).map((x) => Tag.fromJSON(x));
313
+ )).json();
402
314
  }
403
- async getNotes(query, spaceId) {
404
- return (await (await this._fetch(
405
- this.url + `/notes?space=${spaceId}&query=${encodeURIComponent(query)}`,
315
+ async getNotes(query, space) {
316
+ return space instanceof Space && (space = space.id), await (await this._fetch(
317
+ this.url + `/notes?space=${space}&query=${encodeURIComponent(query)}`,
406
318
  {
407
319
  method: "GET",
408
320
  headers: { Authorization: "Bearer " + this.token }
409
321
  }
410
- )).json()).map((x) => Note.fromJSON(x));
322
+ )).json();
411
323
  }
412
- async getNoteCount(query, spaceId) {
413
- return (await (await this._fetch(
414
- this.url + `/notes?count=true&space=${spaceId}&query=${encodeURIComponent(query)}`,
324
+ async getNoteCount(query, space) {
325
+ return space instanceof Space && (space = space.id), (await (await this._fetch(
326
+ this.url + `/notes?count=true&space=${space}&query=${encodeURIComponent(query)}`,
415
327
  {
416
328
  method: "GET",
417
329
  headers: { Authorization: "Bearer " + this.token }
@@ -419,14 +331,14 @@ class HttpClient {
419
331
  )).json()).count;
420
332
  }
421
333
  async saveNotes(notes) {
422
- return (await (await this._fetch(
334
+ return await (await this._fetch(
423
335
  this.url + "/notes",
424
336
  {
425
337
  method: "POST",
426
338
  body: JSON.stringify(notes),
427
339
  headers: { Authorization: "Bearer " + this.token }
428
340
  }
429
- )).json()).map((x) => Note.fromJSON(x));
341
+ )).json();
430
342
  }
431
343
  async customJob(name, data) {
432
344
  return await (await this._fetch(
@@ -440,164 +352,129 @@ class HttpClient {
440
352
  }
441
353
  }
442
354
  class NoteAttr extends ModelWithState {
443
- constructor(note, attr, value) {
355
+ constructor(attr, tag, value) {
444
356
  super();
445
- __publicField(this, "_noteId", 0);
446
- __publicField(this, "_note", null);
447
- __publicField(this, "_attrId", 0);
357
+ __publicField(this, "_tag", null);
448
358
  __publicField(this, "_attr", null);
449
359
  __publicField(this, "_value", null);
450
- __publicField(this, "_tagId", null);
451
- __publicField(this, "_tag", null);
452
- note != null && note != null && (typeof note == "number" ? this.noteId = note : this.note = note), attr != null && attr != null && (typeof attr == "number" ? this.attrId = attr : this.attr = attr), value != null && value != null && (this.value = value);
453
- }
454
- get noteId() {
455
- return this._noteId;
456
- }
457
- set noteId(value) {
458
- var _a;
459
- value !== this._noteId && (this._noteId = value, value !== ((_a = this.note) == null ? void 0 : _a.id) && (this._note = null), this.isClean && this.dirty());
460
- }
461
- get note() {
462
- return this._note;
463
- }
464
- set note(value) {
465
- this._note = value, this.noteId = (value == null ? void 0 : value.id) ?? 0;
466
- }
467
- get attrId() {
468
- return this._attrId;
360
+ if (!attr)
361
+ throw Error("Cannot instanciate new NoteAttr without a passed in attr.");
362
+ if (attr.isNew)
363
+ throw Error("Cannot create a NoteAttr object for an attr that hasn't been saved yet.");
364
+ if (attr.isDeleted)
365
+ throw Error("Cannot create a NoteAttr object for an attr marked as deleted.");
366
+ if (this._attr = attr, tag) {
367
+ if (tag.isNew)
368
+ throw Error("Cannot create a NoteAttr object linked to a tag that hasn't been saved yet.");
369
+ if (tag.isDeleted)
370
+ throw Error("Cannot create a NoteAttr object linked to a tag marked as deleted.");
371
+ this._tag = tag;
372
+ }
373
+ value != null && value != null ? this.value = value : this.value = attr.defaultValue;
469
374
  }
470
- set attrId(value) {
471
- var _a;
472
- value !== this._attrId && (this._attrId = value, value !== ((_a = this.attr) == null ? void 0 : _a.id) && (this._attr = null), this.isClean && this.dirty());
375
+ get tag() {
376
+ return this._tag;
473
377
  }
474
378
  get attr() {
475
379
  return this._attr;
476
380
  }
477
- set attr(newAttr) {
478
- const oldAttr = this._attr;
479
- this._attr = newAttr, newAttr ? newAttr.id != this.attrId && (!oldAttr || newAttr.type != oldAttr.type) && (this.value = newAttr.defaultValue) : this.value = null, this.attrId = (newAttr == null ? void 0 : newAttr.id) ?? 0;
480
- }
481
381
  get value() {
482
382
  return this._value;
483
383
  }
484
384
  set value(newVal) {
485
- newVal != this._value && (this._value = newVal, this.isClean && this.dirty());
385
+ this.attr.isDate && !(newVal instanceof Date) && (newVal = new Date(newVal)), newVal != this._value && (this._value = newVal, this.isClean && this.dirty());
486
386
  }
487
387
  withValue(value) {
488
388
  return this.value = value, this;
489
389
  }
490
- get tagId() {
491
- return this._tagId;
492
- }
493
- set tagId(value) {
494
- var _a;
495
- value !== this._tagId && (this._tagId = value, value !== ((_a = this.tag) == null ? void 0 : _a.id) && (this._tag = null), this.isClean && this.dirty());
496
- }
497
- get tag() {
498
- return this._tag;
499
- }
500
- set tag(value) {
501
- this._tag = value, this.tagId = (value == null ? void 0 : value.id) ?? null;
502
- }
503
- onTag(tag) {
504
- return typeof tag == "number" ? this.tagId = tag : this.tag = tag, this;
505
- }
506
390
  duplicate() {
507
- const output = new NoteAttr();
508
- return output.noteId = this.noteId, this.attr ? output.attr = this.attr : output.attrId = this.attrId, this.tag ? output.tag = this.tag : output.tagId = this.tagId, output.value = this.value, output.state = this.state, output;
391
+ return new NoteAttr(this.attr, this.tag, this.value);
509
392
  }
510
393
  validate(throwError = !1) {
511
394
  let output = null;
512
- if (this.noteId <= 0 && !this.isNew ? output = "NoteAttr noteId must be greater than zero" : this.attrId <= 0 && (output = "NoteAttr attrId must be greater than zero"), throwError && output != null)
395
+ if (throwError && output != null)
513
396
  throw Error(output);
514
397
  return output == null;
515
398
  }
516
399
  toJSON() {
517
400
  return {
518
401
  state: this.state,
519
- noteId: this.noteId,
520
- attrId: this.attrId,
521
- tagId: this.tagId,
402
+ attrId: this.attr.id,
403
+ tagId: this.tag.id,
522
404
  value: this.value
523
405
  };
524
406
  }
525
- static fromJSON(json) {
526
- const output = new NoteAttr(json.noteId, json.attrId, json.value);
527
- return output.tagId = json.tagId, output.state = json.state, output;
528
- }
529
407
  }
530
408
  class NoteTag extends ModelWithState {
531
- constructor(note, tag) {
409
+ constructor(tag) {
532
410
  super();
533
- __publicField(this, "_noteId", 0);
534
- __publicField(this, "_note", null);
535
- __publicField(this, "_tagId", 0);
536
- __publicField(this, "_tag", null);
537
- note != null && note != null && (typeof note == "number" ? this.noteId = note : this.note = note), tag != null && tag != null && (typeof tag == "number" ? this.tagId = tag : this.tag = tag);
538
- }
539
- get noteId() {
540
- return this._noteId;
541
- }
542
- set noteId(value) {
543
- var _a;
544
- value !== this._noteId && (this._noteId = value, value !== ((_a = this.note) == null ? void 0 : _a.id) && (this._note = null), this.isClean && this.dirty());
545
- }
546
- get note() {
547
- return this._note;
411
+ __publicField(this, "_tag");
412
+ __publicField(this, "_attrs", []);
413
+ if (!tag)
414
+ throw Error("Cannot instanciate new NoteTag without a passed in tag.");
415
+ if (tag.isNew)
416
+ throw Error("Cannot create a NoteTag object for a tag that hasn't been saved yet.");
417
+ if (tag.isDeleted)
418
+ throw Error("Cannot create a NoteTag object for a tag marked as deleted.");
419
+ this._tag = tag;
548
420
  }
549
- set note(value) {
550
- this._note = value, this.noteId = (value == null ? void 0 : value.id) ?? 0;
421
+ get tag() {
422
+ return this._tag;
551
423
  }
552
- get tagId() {
553
- return this._tagId;
424
+ get attrs() {
425
+ return this._attrs.filter((x) => !x.isDeleted);
554
426
  }
555
- set tagId(value) {
556
- var _a;
557
- value !== this._tagId && (this._tagId = value, value !== ((_a = this.tag) == null ? void 0 : _a.id) && (this._tag = null), this.isClean && this.dirty());
427
+ get attrsPendingDeletion() {
428
+ return this._attrs.filter((x) => x.isDeleted);
558
429
  }
559
- get tag() {
560
- return this._tag;
430
+ addAttr(attr, value) {
431
+ if (attr.isDeleted)
432
+ throw Error("Cannot add an attribute marked as deleted.");
433
+ if (attr.isNew)
434
+ throw Error("Cannot add an attribute that hasn't yet been saved.");
435
+ const na = new NoteAttr(attr, this.tag, value);
436
+ return this._attrs.push(na), this;
561
437
  }
562
- set tag(value) {
563
- this._tag = value, this.tagId = (value == null ? void 0 : value.id) ?? 0;
438
+ removeAttr(attr) {
439
+ const na = this._attrs.find((x) => x.attr.id == attr.id);
440
+ return na ? (na.isNew ? this._attrs = this._attrs.filter((x) => x !== na) : na.delete(), this) : this;
564
441
  }
565
- get attrs() {
566
- return this.note ? this.note.allAttrs.filter((x) => x.tagId == this.tagId) : [];
442
+ getAttr(attr) {
443
+ return attr instanceof Attr && (attr = attr.name), this.attrs.find((x) => x.attr.name == attr);
567
444
  }
568
- addAttr(attr) {
569
- if (!this.note)
570
- throw new Error("Cannot call addAttr on NoteTag where note property has not been set");
571
- const na = this.note.addAttr(attr);
572
- return na.tag = this.tag, na;
445
+ getValue(attr) {
446
+ var _a;
447
+ return (_a = this.getAttr(attr)) == null ? void 0 : _a.value;
573
448
  }
574
449
  duplicate() {
575
- const output = new NoteTag();
576
- return output.noteId = this.noteId, this.tag ? output.tag = this.tag : output.tagId = this.tagId, output;
450
+ const output = new NoteTag(this.tag);
451
+ return output._attrs = this.attrs.map((x) => x.duplicate()), output;
577
452
  }
578
453
  validate(throwError = !1) {
579
- let output = null;
580
- if (this.noteId <= 0 && !this.isNew ? output = "NoteTag noteId must be greater than zero" : this.tagId <= 0 ? output = "NoteTag tagId must be greater than zero" : this.noteId == this.tagId && (output = "NoteTag cannot link a note to its own tag"), throwError && output != null)
581
- throw Error(output);
582
- return output == null;
454
+ function exit(message) {
455
+ if (throwError && message != null)
456
+ throw Error(message);
457
+ return message == null;
458
+ }
459
+ if (!this.tag)
460
+ return exit("NoteTag must have a tag set.");
461
+ for (const na of this._attrs)
462
+ if (!na.validate(throwError))
463
+ return !1;
464
+ return !0;
583
465
  }
584
466
  toJSON() {
585
467
  return {
586
468
  state: this.state,
587
- noteId: this.noteId,
588
- tagId: this.tagId
469
+ tagId: this.tag.id,
470
+ attrs: this._attrs
589
471
  };
590
472
  }
591
- static fromJSON(json) {
592
- const output = new NoteTag(json.noteId, json.tagId);
593
- return output.state = json.state, output;
594
- }
595
473
  }
596
474
  class Tag extends ModelWithState {
597
475
  constructor(name = "") {
598
476
  super();
599
477
  __publicField(this, "_id", 0);
600
- __publicField(this, "_spaceId", 0);
601
478
  __publicField(this, "_space", null);
602
479
  __publicField(this, "_name", "");
603
480
  __publicField(this, "_color", null);
@@ -608,23 +485,22 @@ class Tag extends ModelWithState {
608
485
  return this._id;
609
486
  }
610
487
  set id(value) {
611
- value !== this._id && (this._id = value, this.isClean && this.dirty());
612
- }
613
- get spaceId() {
614
- return this._spaceId;
615
- }
616
- set spaceId(value) {
617
- var _a;
618
- value !== this._spaceId && (this._spaceId = value, value !== ((_a = this.space) == null ? void 0 : _a.id) && (this._space = null), this.isClean && this.dirty());
488
+ if (!this.isNew)
489
+ throw Error("Cannot change the id of a Tag once it has already been created.");
490
+ this._id = value;
619
491
  }
620
492
  get space() {
621
493
  return this._space;
622
494
  }
623
495
  set space(value) {
624
- this._space = value, this.spaceId = (value == null ? void 0 : value.id) ?? 0;
496
+ var _a;
497
+ if (value !== this._space) {
498
+ const idChanged = (value == null ? void 0 : value.id) != ((_a = this._space) == null ? void 0 : _a.id);
499
+ this._space = value, this.isClean && idChanged && this.dirty();
500
+ }
625
501
  }
626
502
  in(space) {
627
- return typeof space == "number" ? this.spaceId = space : this.space = space, this;
503
+ return this.space = space, this;
628
504
  }
629
505
  get name() {
630
506
  return this._name;
@@ -633,7 +509,8 @@ class Tag extends ModelWithState {
633
509
  value !== this._name && (this._name = value, this.isClean && this.dirty());
634
510
  }
635
511
  getQualifiedName(contextSpaceId) {
636
- return contextSpaceId == this.spaceId ? this.name : `${this.space.name}.${this.name}`;
512
+ var _a;
513
+ return contextSpaceId == ((_a = this.space) == null ? void 0 : _a.id) ? this.name : `${this.space.name}.${this.name}`;
637
514
  }
638
515
  get color() {
639
516
  return this._color;
@@ -668,38 +545,36 @@ class Tag extends ModelWithState {
668
545
  return hex ? (hex.startsWith("#") && (hex = hex.substring(1)), parseInt(hex, 16)) : null;
669
546
  }
670
547
  toJSON() {
548
+ var _a;
671
549
  return {
672
550
  state: this.state,
673
551
  id: this.id,
674
552
  name: this.name,
675
- spaceId: this.spaceId,
553
+ spaceId: (_a = this.space) == null ? void 0 : _a.id,
676
554
  color: this.color,
677
555
  isPublic: this.isPublic
678
556
  };
679
557
  }
680
- static fromJSON(json) {
681
- const output = new Tag(json.name);
682
- return output.id = json.id, output.spaceId = json.spaceId, output.color = json.color, output.isPublic = json.isPublic, output.state = json.state, output;
683
- }
684
558
  }
685
559
  class Note extends ModelWithState {
686
- constructor(text) {
560
+ constructor(text, ownTag) {
687
561
  super();
688
562
  __publicField(this, "_id", 0);
689
563
  __publicField(this, "_date", /* @__PURE__ */ new Date());
690
564
  __publicField(this, "_text", "");
691
- __publicField(this, "_spaceId", 0);
692
565
  __publicField(this, "_space", null);
693
566
  __publicField(this, "_ownTag", null);
694
567
  __publicField(this, "_tags", []);
695
568
  __publicField(this, "_attrs", []);
696
- text && (this.text = text);
569
+ text && (this.text = text), this._ownTag = ownTag;
697
570
  }
698
571
  get id() {
699
572
  return this._id;
700
573
  }
701
574
  set id(value) {
702
- this._id = value, this.ownTag && (this.ownTag.id = value);
575
+ if (!this.isNew)
576
+ throw Error("Cannot change the id of a Note once it has already been created.");
577
+ this._id = value, this.ownTag && this.ownTag.id != value && (this.ownTag.id = value);
703
578
  }
704
579
  get date() {
705
580
  return this._date;
@@ -716,42 +591,30 @@ class Note extends ModelWithState {
716
591
  set text(value) {
717
592
  value !== this._text && (this._text = value, this.isClean && this.dirty());
718
593
  }
719
- get spaceId() {
720
- return this._spaceId;
721
- }
722
- set spaceId(value) {
723
- var _a;
724
- value !== this._spaceId && (this._spaceId = value, value !== ((_a = this.space) == null ? void 0 : _a.id) && (this._space = null), this.isClean && this.dirty(), this._setOwnTagSpace());
725
- }
726
594
  get space() {
727
595
  return this._space;
728
596
  }
729
597
  set space(value) {
730
- this._space = value, this.spaceId = (value == null ? void 0 : value.id) ?? 0;
598
+ var _a;
599
+ if (value !== this._space) {
600
+ const idChanged = (value == null ? void 0 : value.id) != ((_a = this._space) == null ? void 0 : _a.id);
601
+ this._space = value, this.isClean && idChanged && this.dirty(), this._setOwnTagSpace();
602
+ }
731
603
  }
732
604
  in(space) {
733
- return typeof space == "number" ? this.spaceId = space : this.space = space, this;
605
+ return this.space = space, this;
734
606
  }
735
607
  get ownTag() {
736
608
  return this._ownTag;
737
609
  }
738
- setOwnTag(tag) {
739
- if (typeof tag == "string")
740
- this.ownTag == null && (this._ownTag = new Tag()), this.ownTag.name = tag, this.ownTag.id = this.id, this._setOwnTagSpace();
741
- else {
742
- if (this.ownTag)
743
- throw new Error("Note has already had its tag set. If you would like to change the tag name, call setTag with just a string specifying the new tag name.");
744
- if (tag.id != 0 && tag.id != this.id)
745
- throw new Error("Attempted to set tag to note with non-matching ID. Added tag id must either match the note id, which indicates that the tag has already been added to the note. Otherwise the tag id must be zero, indicating that the tag still needs to be added.");
746
- this._ownTag = tag;
747
- }
748
- return this;
610
+ setOwnTag(tagName) {
611
+ return this.ownTag == null ? (this._ownTag = new Tag(tagName), this.ownTag.id = this.id) : this.ownTag.isDeleted && this.ownTag.dirty(), this.ownTag.name = tagName, this._setOwnTagSpace(), this;
749
612
  }
750
613
  removeOwnTag() {
751
614
  return this.ownTag ? (this.ownTag.isNew ? this._ownTag = null : this.ownTag.delete(), this) : this;
752
615
  }
753
616
  _setOwnTagSpace() {
754
- this.ownTag && (this.space ? this.ownTag.space = this.space : this.ownTag.spaceId = this.spaceId);
617
+ this.ownTag && this.space && (this.ownTag.space = this.space);
755
618
  }
756
619
  get tags() {
757
620
  return this._tags.filter((x) => !x.isDeleted);
@@ -766,63 +629,47 @@ class Note extends ModelWithState {
766
629
  throw Error("Cannot add a tag that hasn't yet been saved to a note");
767
630
  if (tag.id == this.id)
768
631
  throw Error("Note cannot add its own tag as a linked tag");
769
- if (!tag.isPublic && tag.spaceId != this.spaceId)
632
+ if (!tag.isPublic && tag.space.id != this.space.id)
770
633
  throw Error("Cannot add a private tag from another space");
771
- let nt = this._tags.find((x) => x.tagId == tag.id);
772
- return nt ? (nt.isDeleted && nt.dirty(), nt) : (nt = new NoteTag(), nt.note = this, nt.tag = tag, this._tags.push(nt), nt);
634
+ let nt = this._tags.find((x) => x.tag.id == tag.id);
635
+ return nt ? (nt.isDeleted && nt.dirty(), nt) : (nt = new NoteTag(tag), this._tags.push(nt), nt);
773
636
  }
774
637
  removeTag(tag) {
775
- const nt = this._tags.find((x) => x.tagId == tag.id);
776
- if (!nt)
777
- return this;
778
- nt.isNew ? this._tags = this._tags.filter((x) => x !== nt) : nt.delete();
779
- for (const na of this._attrs.filter((x) => !x.isDeleted && x.tagId == tag.id))
780
- this.removeAttr(na.attr, na.tag);
781
- return this;
638
+ const nt = this._tags.find((x) => x.tag.id == tag.id);
639
+ return nt ? (nt.isNew ? this._tags = this._tags.filter((x) => x !== nt) : nt.delete(), this) : this;
782
640
  }
783
641
  getTag(tag, space = null) {
784
- return tag instanceof Tag && (tag = tag.name), space && space instanceof Space && (space = space.id), space != null ? this.tags.find((x) => x.tag.name == tag && x.tag.spaceId == space) : this.tags.find((x) => x.tag.name == tag && x.tag.spaceId == this.spaceId);
642
+ return tag instanceof Tag && (tag = tag.name), space && space instanceof Space && (space = space.id), space != null ? this.tags.find((x) => x.tag.name == tag && x.tag.space.id == space) : this.tags.find((x) => x.tag.name == tag && x.tag.space.id == this.space.id);
785
643
  }
786
- /** This contains all attrs that have been added either directly to the note, or to a tag on the note and are not due to be deleted. */
787
- get allAttrs() {
644
+ get attrs() {
788
645
  return this._attrs.filter((x) => !x.isDeleted);
789
646
  }
790
- /** This contains all attrs that have been added directly to the note and are not due to be deleted. */
791
- get noteAttrs() {
792
- return this._attrs.filter((x) => !x.isDeleted && !x.tag);
793
- }
794
- /** This contains all attrs that have been added either directly to the note, or to a tag on the note and are due to be deleted. */
795
- get allAttrsPendingDeletion() {
647
+ get attrsPendingDeletion() {
796
648
  return this._attrs.filter((x) => x.isDeleted);
797
649
  }
798
- addAttr(attr) {
650
+ addAttr(attr, value) {
799
651
  if (attr.isDeleted)
800
652
  throw Error("Cannot add an attribute marked as deleted to a note");
801
653
  if (attr.isNew)
802
654
  throw Error("Cannot add an attribute that hasn't yet been saved to a note");
803
- const na = new NoteAttr(this, attr);
804
- return this._attrs.push(na), na;
655
+ const na = new NoteAttr(attr, null, value);
656
+ return this._attrs.push(na), this;
805
657
  }
806
- removeAttr(attr, tag = null) {
807
- const na = this._attrs.find((x) => x.attrId == attr.id && x.tagId == (tag == null ? void 0 : tag.id));
658
+ removeAttr(attr) {
659
+ const na = this._attrs.find((x) => x.attr.id == attr.id);
808
660
  return na ? (na.isNew ? this._attrs = this._attrs.filter((x) => x !== na) : na.delete(), this) : this;
809
661
  }
662
+ getAttr(attr) {
663
+ return attr instanceof Attr && (attr = attr.name), this.attrs.find((x) => x.attr.name == attr);
664
+ }
810
665
  getValue(attr) {
811
666
  var _a;
812
- return attr instanceof Attr && (attr = attr.name), (_a = this.noteAttrs.find((x) => x.attr.name == attr)) == null ? void 0 : _a.value;
813
- }
814
- getAttr(attr) {
815
- return attr instanceof Attr && (attr = attr.name), this.noteAttrs.find((x) => x.attr.name == attr);
667
+ return (_a = this.getAttr(attr)) == null ? void 0 : _a.value;
816
668
  }
817
669
  duplicate() {
818
- const output = new Note();
819
- return output.id = this.id, output.date = this.date, output.text = this.text, this.space ? output.space = this.space : output.spaceId = this.spaceId, output._tags = this.tags.map((x) => {
820
- const ntCopy = x.duplicate();
821
- return ntCopy.note = output, ntCopy;
822
- }), output._attrs = this.allAttrs.map((x) => {
823
- const naCopy = x.duplicate();
824
- return naCopy.note = output, naCopy;
825
- }), this.ownTag && !this.ownTag.isDeleted && output.setOwnTag(this.ownTag.duplicate()), output.state = this.state, output;
670
+ var _a;
671
+ const output = new Note(this.text, (_a = this.ownTag) == null ? void 0 : _a.duplicate()).at(this.date).in(this.space);
672
+ return output._attrs = this.attrs.map((x) => x.duplicate()), output._tags = this.tags.map((x) => x.duplicate()), output;
826
673
  }
827
674
  toJSON() {
828
675
  return {
@@ -830,39 +677,34 @@ class Note extends ModelWithState {
830
677
  id: this.id,
831
678
  date: this.date,
832
679
  text: this.text,
833
- spaceId: this.spaceId,
680
+ spaceId: this.space.id,
834
681
  ownTag: this.ownTag,
835
- tags: this.tags,
682
+ tags: this._tags,
836
683
  attrs: this._attrs
837
684
  };
838
685
  }
839
- static fromJSON(json) {
840
- const output = new Note(json.text);
841
- if (output.id = json.id, output.date = new Date(json.date), output.spaceId = json.spaceId, json.ownTag && output.setOwnTag(Tag.fromJSON(json.ownTag)), json.tags) {
842
- output._tags = json.tags.map((x) => NoteTag.fromJSON(x));
843
- for (const nt of output._tags)
844
- nt.note = output;
845
- }
846
- if (json.attrs) {
847
- output._attrs = json.attrs.map((x) => NoteAttr.fromJSON(x));
848
- for (const na of output._attrs)
849
- na.note = output;
850
- }
851
- return output.state = json.state, output;
852
- }
853
686
  validate(throwError = !1) {
854
- let output = null;
855
- this.spaceId <= 0 ? output = "Note spaceId must be greater than zero." : !this.isNew && this.id <= 0 ? output = "Note id must be greater than zero if in non-new state." : this.ownTag && this.ownTag.spaceId != this.spaceId && (output = "Note cannot belong to a different space than its own tag");
856
- const survivingAttrs = this._attrs.filter((x) => !x.isDeleted);
687
+ function exit(message) {
688
+ if (throwError && message != null)
689
+ throw Error(message);
690
+ return message == null;
691
+ }
692
+ if (this.space) {
693
+ if (!this.isNew && this.id <= 0)
694
+ return exit("Note id must be greater than zero if in non-new state.");
695
+ if (this.ownTag && this.ownTag.space.id != this.space.id)
696
+ return exit("Note cannot belong to a different space than its own tag");
697
+ } else
698
+ return exit("Note must belong to a space.");
699
+ const survivingAttrs = this.attrs;
857
700
  for (let i = 0; i < survivingAttrs.length; i++) {
858
701
  const na = survivingAttrs[i];
859
702
  for (let j = i + 1; j < survivingAttrs.length; j++) {
860
703
  const na2 = survivingAttrs[j];
861
- na.attrId == na2.attrId && na.tagId == na2.tagId && (output = `Attr '${na.attr.name}' is duplicated.`);
704
+ if (na.attr.id == na2.attr.id)
705
+ return exit(`Attr '${na.attr.name}' is duplicated.`);
862
706
  }
863
707
  }
864
- if (throwError && output != null)
865
- throw Error(output);
866
708
  if (this.ownTag && !this.ownTag.validate(throwError))
867
709
  return !1;
868
710
  for (const nt of this._tags)
@@ -871,7 +713,160 @@ class Note extends ModelWithState {
871
713
  for (const na of this._attrs)
872
714
  if (!na.validate(throwError))
873
715
  return !1;
874
- return output == null;
716
+ return !0;
717
+ }
718
+ }
719
+ class NotuCache {
720
+ constructor(fetcher) {
721
+ __publicField(this, "_fetcher");
722
+ __publicField(this, "_spaces", null);
723
+ __publicField(this, "_tags", null);
724
+ __publicField(this, "_attrs", null);
725
+ if (!fetcher)
726
+ throw Error("NotuCache constructor must have a fetcher argument supplied.");
727
+ this._fetcher = fetcher;
728
+ }
729
+ async populate() {
730
+ await this._populateSpaces();
731
+ const tagsPromise = this._populateTags(), attrsPromise = this._populateAttrs();
732
+ await Promise.all([tagsPromise, attrsPromise]);
733
+ }
734
+ async _populateSpaces() {
735
+ const spacesData = await this._fetcher.getSpacesData();
736
+ this._spaces = /* @__PURE__ */ new Map();
737
+ for (const spaceData of spacesData) {
738
+ const space = this._spaceFromJSON(spaceData);
739
+ this._spaces.set(space.id, space);
740
+ }
741
+ }
742
+ _spaceFromJSON(spaceData) {
743
+ const space = new Space(spaceData.name);
744
+ return space.id = spaceData.id, space.version = spaceData.version, space.state = spaceData.state, space;
745
+ }
746
+ async _populateTags() {
747
+ const tagsData = await this._fetcher.getTagsData();
748
+ this._tags = /* @__PURE__ */ new Map();
749
+ for (const tagData of tagsData) {
750
+ const tag = this._tagFromJSON(tagData);
751
+ this._tags.set(tag.id, tag);
752
+ }
753
+ }
754
+ _tagFromJSON(tagData) {
755
+ const tag = new Tag(tagData.name);
756
+ return tag.id = tagData.id, tag.space = this._spaces.get(tagData.spaceId), tag.color = tagData.color, tag.isPublic = tagData.isPublic, tag.state = tagData.state, tag;
757
+ }
758
+ async _populateAttrs() {
759
+ const attrsData = await this._fetcher.getAttrsData();
760
+ this._attrs = /* @__PURE__ */ new Map();
761
+ for (const attrData of attrsData) {
762
+ const attr = this._attrFromJSON(attrData);
763
+ this._attrs.set(attr.id, attr);
764
+ }
765
+ }
766
+ _attrFromJSON(attrData) {
767
+ const attr = new Attr(attrData.name, attrData.description);
768
+ return attr.id = attrData.id, attr.type = attrData.type, attr.space = this._spaces.get(attrData.spaceId), attr.state = attrData.state, attr;
769
+ }
770
+ noteFromJSON(noteData) {
771
+ const note = new Note(noteData.text, this.getTag(noteData.id)).at(new Date(noteData.date)).in(this.getSpace(noteData.spaceId));
772
+ note.id = noteData.id, note.state = noteData.state;
773
+ for (const naData of noteData.attrs) {
774
+ const attr = this.getAttr(naData.attrId);
775
+ note.addAttr(attr, naData.value), note.getAttr(attr).state = naData.state;
776
+ }
777
+ for (const ntData of noteData.tags) {
778
+ const nt = note.addTag(this.getTag(ntData.tagId));
779
+ nt.state = ntData.state;
780
+ for (const ntaData of ntData.attrs) {
781
+ const attr = this.getAttr(ntaData.attrId);
782
+ nt.addAttr(attr, ntaData.value), nt.getAttr(attr).state = ntaData.state;
783
+ }
784
+ }
785
+ return note;
786
+ }
787
+ getSpaces() {
788
+ return Array.from(this._spaces.values());
789
+ }
790
+ getSpace(id) {
791
+ return this._spaces.get(id);
792
+ }
793
+ getSpaceByName(name) {
794
+ for (const space of this._spaces.values())
795
+ if (space.name == name)
796
+ return space;
797
+ }
798
+ spaceSaved(spaceData) {
799
+ const space = this._spaceFromJSON(spaceData);
800
+ return space.state == "DELETED" ? this._spaces.delete(space.id) : this._spaces.set(space.id, space), space;
801
+ }
802
+ getTags(space = null, includeOtherSpacePublics = !1) {
803
+ return space == null ? Array.from(this._tags.values()) : (space instanceof Space && (space = space.id), Array.from(this._tags.values()).filter((x) => x.isPublic && includeOtherSpacePublics || x.space.id == space));
804
+ }
805
+ getTag(id) {
806
+ return this._tags.get(id);
807
+ }
808
+ getTagByName(name, space) {
809
+ space instanceof Space && (space = space.id);
810
+ for (const tag of this._tags.values())
811
+ if (tag.name == name && tag.space.id == space)
812
+ return tag;
813
+ }
814
+ tagSaved(tagData) {
815
+ const tag = this._tagFromJSON(tagData);
816
+ return tag.state == "DELETED" ? this._tags.delete(tag.id) : this._tags.set(tag.id, tag), tag;
817
+ }
818
+ getAttrs(space) {
819
+ return space instanceof Space && (space = space.id), Array.from(this._attrs.values()).filter((x) => x.space.id == space);
820
+ }
821
+ getAttr(id) {
822
+ return this._attrs.get(id);
823
+ }
824
+ getAttrByName(name, space) {
825
+ space instanceof Space && (space = space.id);
826
+ for (const attr of this._attrs.values())
827
+ if (attr.name == name && attr.space.id == space)
828
+ return attr;
829
+ }
830
+ attrSaved(attrData) {
831
+ const attr = this._attrFromJSON(attrData);
832
+ return attr.state == "DELETED" ? this._attrs.delete(attr.id) : this._attrs.set(attr.id, attr), attr;
833
+ }
834
+ }
835
+ class NotuHttpCacheFetcher {
836
+ constructor(url, token, fetchMethod = null) {
837
+ __publicField(this, "_url", null);
838
+ __publicField(this, "_token", null);
839
+ //Added for testing support
840
+ __publicField(this, "_fetch");
841
+ if (!url)
842
+ throw Error("Endpoint URL must be passed into NotuHttpCacheFetcher constructor");
843
+ if (!token)
844
+ throw Error("Security token must be passed into NotuHttpCacheFetcher constructor");
845
+ url.endsWith("/") && (url = url.substring(0, url.length - 1)), this._url = url, this._token = token, this._fetch = fetchMethod ?? window.fetch.bind(window);
846
+ }
847
+ get url() {
848
+ return this._url;
849
+ }
850
+ get token() {
851
+ return this._token;
852
+ }
853
+ async getSpacesData() {
854
+ return await this._getX("/spaces");
855
+ }
856
+ async getTagsData() {
857
+ return await this._getX("/tags");
858
+ }
859
+ async getAttrsData() {
860
+ return await this._getX("/attrs");
861
+ }
862
+ async _getX(endpoint) {
863
+ return await (await this._fetch(
864
+ this.url + endpoint,
865
+ {
866
+ method: "GET",
867
+ headers: { Authorization: "Bearer " + this.token }
868
+ }
869
+ )).json();
875
870
  }
876
871
  }
877
872
  class ParsedQuery {
@@ -956,11 +951,13 @@ function identifyAttrs(query, parsedQuery) {
956
951
  }
957
952
  export {
958
953
  Attr,
959
- CachedClient,
960
- HttpClient,
961
954
  Note,
962
955
  NoteAttr,
963
956
  NoteTag,
957
+ Notu,
958
+ NotuCache,
959
+ NotuHttpCacheFetcher,
960
+ NotuHttpClient,
964
961
  ParsedAttr,
965
962
  ParsedQuery,
966
963
  ParsedTag,