nesoi 3.4.14 → 3.4.16

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.
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NesoiDatetime = void 0;
4
+ const date_1 = require("./date");
4
5
  const duration_1 = require("./duration");
5
6
  const error_1 = require("./error");
6
7
  /**
@@ -50,9 +51,39 @@ class NesoiDatetime {
50
51
  atTimezone(tz) {
51
52
  return new NesoiDatetime(this.epoch, tz);
52
53
  }
54
+ /**
55
+ * Make a new `NesoiDateTime`
56
+ * @param year Numeric year
57
+ * @param month 1~12
58
+ * @param day 1~31
59
+ * @param hour 0~24
60
+ * @param minute 0~60
61
+ * @param second 0~60
62
+ * @param ms 0~999
63
+ * @param tz
64
+ * @returns
65
+ */
66
+ static make(year = 0, month = 1, day = 1, hour = 0, minute = 0, second = 0, ms = 0, tz = 'Z') {
67
+ const _month = (month < 10 ? '0' : '') + month;
68
+ const _day = (day < 10 ? '0' : '') + day;
69
+ const _hour = (hour < 10 ? '0' : '') + hour;
70
+ const _minute = (minute < 10 ? '0' : '') + minute;
71
+ const _second = (second < 10 ? '0' : '') + second;
72
+ const _ms = (ms < 100 ? '0' : '') + (ms < 10 ? '0' : '') + ms;
73
+ return this.fromISO(`${year}-${_month}-${_day}T${_hour}:${_minute}:${_second}.${_ms}${tz}`);
74
+ }
53
75
  // Parse
76
+ static parse(value) {
77
+ if (typeof value === 'string') {
78
+ return this.fromISO(value);
79
+ }
80
+ if (value instanceof NesoiDatetime) {
81
+ return value;
82
+ }
83
+ throw error_1.NesoiError.Data.InvalidDatetime({ value });
84
+ }
54
85
  /**
55
- * Parse a timestamp from ISO 8601 format.
86
+ * Create a NesoiDatetime from a string on the ISO 8601 format.
56
87
  *
57
88
  * Example: `2025-04-16T23:04:42.000-03:00`
58
89
  */
@@ -76,26 +107,8 @@ class NesoiDatetime {
76
107
  const jsDate = Date.parse(iso);
77
108
  return new NesoiDatetime(jsDate, tz);
78
109
  }
79
- /**
80
- * Make a new `NesoiDateTime`
81
- * @param year Numeric year
82
- * @param month 1~12
83
- * @param day 1~31
84
- * @param hour 0~24
85
- * @param minute 0~60
86
- * @param second 0~60
87
- * @param ms 0~999
88
- * @param tz
89
- * @returns
90
- */
91
- static make(year = 0, month = 1, day = 1, hour = 0, minute = 0, second = 0, ms = 0, tz = 'Z') {
92
- const _month = (month < 10 ? '0' : '') + month;
93
- const _day = (day < 10 ? '0' : '') + day;
94
- const _hour = (hour < 10 ? '0' : '') + hour;
95
- const _minute = (minute < 10 ? '0' : '') + minute;
96
- const _second = (second < 10 ? '0' : '') + second;
97
- const _ms = (ms < 100 ? '0' : '') + (ms < 10 ? '0' : '') + ms;
98
- return this.fromISO(`${year}-${_month}-${_day}T${_hour}:${_minute}:${_second}.${_ms}${tz}`);
110
+ static fromJSDate(date, tz = 'Z') {
111
+ return new NesoiDatetime(date.getTime(), tz);
99
112
  }
100
113
  static fromValues(values) {
101
114
  return this.make(values.year, values.month, values.day, values.hour, values.minute, values.second, values.ms, values.tz);
@@ -118,6 +131,19 @@ class NesoiDatetime {
118
131
  .replace(',', '.')
119
132
  + this.tz;
120
133
  }
134
+ toString() {
135
+ return this.toISO();
136
+ }
137
+ toISODate() {
138
+ const date = new Date(0);
139
+ date.setUTCMilliseconds(this.epoch);
140
+ return date.toLocaleString('sv-SE', {
141
+ timeZone: NesoiDatetime.tz[this.tz],
142
+ year: 'numeric',
143
+ month: 'numeric',
144
+ day: 'numeric'
145
+ });
146
+ }
121
147
  toValues() {
122
148
  const date = new Date(0);
123
149
  date.setUTCMilliseconds(this.epoch);
@@ -160,17 +186,33 @@ class NesoiDatetime {
160
186
  }
161
187
  // Shift
162
188
  plus(period) {
163
- return this.shift(`+ ${period}`);
189
+ return this.shift(true, period);
164
190
  }
165
191
  minus(period) {
166
- return this.shift(`- ${period}`);
192
+ return this.shift(false, period);
167
193
  }
168
- shift(period) {
169
- const [_, op, val, type] = period.match(/(\+|-) (\d+) (\w+)s?/);
170
- const duration = new duration_1.NesoiDuration({
171
- [type]: parseInt(val)
172
- });
173
- const mult = op === '+' ? 1 : -1;
194
+ shift(plus, period) {
195
+ let duration;
196
+ if (typeof period === 'string') {
197
+ try {
198
+ const [_, val, type] = period.match(/(\d+) +(\w+)/);
199
+ duration = new duration_1.NesoiDuration({
200
+ [type]: val
201
+ });
202
+ }
203
+ catch {
204
+ throw new Error(`Attempt to shift NesoiDate failed due to invalid period '${period}'`);
205
+ }
206
+ }
207
+ else {
208
+ if (period instanceof duration_1.NesoiDuration) {
209
+ duration = period;
210
+ }
211
+ else {
212
+ duration = new duration_1.NesoiDuration(period);
213
+ }
214
+ }
215
+ const mult = plus ? 1 : -1;
174
216
  let epoch = this.epoch;
175
217
  switch (duration.unit) {
176
218
  case 'miliseconds':
@@ -244,5 +286,59 @@ class NesoiDatetime {
244
286
  }
245
287
  return NesoiDatetime.fromValues(values);
246
288
  }
289
+ // End Of
290
+ /**
291
+ * Returns a new `NesoiDatetime` which refers to the
292
+ * end of a given period **on the object timezone**.
293
+ * @param period
294
+ * @returns
295
+ */
296
+ endOf(period) {
297
+ const values = this.toValues();
298
+ values.ms = 999;
299
+ values.second = 59;
300
+ values.minute = 59;
301
+ values.hour = 23;
302
+ switch (period) {
303
+ case 'month':
304
+ values.day = new Date(values.year, values.month, 0).getDate();
305
+ break;
306
+ case 'year':
307
+ values.day = new Date(values.year, 12, 0).getDate();
308
+ values.month = 12;
309
+ break;
310
+ }
311
+ return NesoiDatetime.fromValues(values);
312
+ }
313
+ // Comparisons
314
+ /**
315
+ * Returns a float with the distance in milliseconds between the datetimes.
316
+ * - `> 0`: left is greater
317
+ * - `== 0`: dates match
318
+ * - `< 0`: right is greater
319
+ */
320
+ compare(other) {
321
+ return (this.epoch - other.epoch);
322
+ }
323
+ eq(other) {
324
+ return this.compare(other) === 0;
325
+ }
326
+ gt(other) {
327
+ return this.compare(other) > 0;
328
+ }
329
+ gteq(other) {
330
+ return this.compare(other) >= 0;
331
+ }
332
+ lt(other) {
333
+ return this.compare(other) < 0;
334
+ }
335
+ lteq(other) {
336
+ return this.compare(other) <= 0;
337
+ }
338
+ // to NesoiDate
339
+ toDate() {
340
+ const values = this.toValues();
341
+ return new date_1.NesoiDate(values.day, values.month, values.year);
342
+ }
247
343
  }
248
344
  exports.NesoiDatetime = NesoiDatetime;
@@ -1,9 +1,27 @@
1
+ export type TimeDuration = `${number} ${keyof typeof NesoiDuration.TIME_UNITS}` | {
2
+ miliseconds: number;
3
+ } | {
4
+ seconds: number;
5
+ } | {
6
+ minutes: number;
7
+ } | {
8
+ hours: number;
9
+ };
10
+ export type DateDuration = `${number} ${keyof typeof NesoiDuration.DATE_UNITS}` | {
11
+ days: number;
12
+ } | {
13
+ weeks: number;
14
+ } | {
15
+ months: number;
16
+ } | {
17
+ years: number;
18
+ };
1
19
  /**
2
20
  * @category Engine
3
21
  * @subcategory Data
4
22
  */
5
23
  export declare class NesoiDuration {
6
- static UNITS: {
24
+ static TIME_UNITS: {
7
25
  ms: "miliseconds";
8
26
  milisecond: "miliseconds";
9
27
  miliseconds: "miliseconds";
@@ -17,6 +35,21 @@ export declare class NesoiDuration {
17
35
  h: "hours";
18
36
  hour: "hours";
19
37
  hours: "hours";
38
+ };
39
+ static DATE_UNITS: {
40
+ d: "days";
41
+ day: "days";
42
+ days: "days";
43
+ w: "weeks";
44
+ week: "weeks";
45
+ weeks: "weeks";
46
+ month: "months";
47
+ months: "months";
48
+ y: "years";
49
+ year: "years";
50
+ years: "years";
51
+ };
52
+ static UNITS: {
20
53
  d: "days";
21
54
  day: "days";
22
55
  days: "days";
@@ -28,26 +61,27 @@ export declare class NesoiDuration {
28
61
  y: "years";
29
62
  year: "years";
30
63
  years: "years";
64
+ ms: "miliseconds";
65
+ milisecond: "miliseconds";
66
+ miliseconds: "miliseconds";
67
+ s: "seconds";
68
+ second: "seconds";
69
+ seconds: "seconds";
70
+ min: "minutes";
71
+ mins: "minutes";
72
+ minute: "minutes";
73
+ minutes: "minutes";
74
+ h: "hours";
75
+ hour: "hours";
76
+ hours: "hours";
31
77
  };
32
78
  value: number;
33
79
  unit: typeof NesoiDuration.UNITS[keyof typeof NesoiDuration.UNITS];
34
80
  constructor(value: {
35
- miliseconds: number;
36
- } | {
37
- seconds: number;
38
- } | {
39
- minutes: number;
40
- } | {
41
- hours: number;
42
- } | {
43
- days: number;
44
- } | {
45
- weeks: number;
46
- } | {
47
- months: number;
48
- } | {
49
- years: number;
50
- });
81
+ [K in keyof typeof NesoiDuration.UNITS]: {
82
+ [J in K]: number;
83
+ };
84
+ }[keyof typeof NesoiDuration.UNITS]);
51
85
  static fromString(value: string): NesoiDuration;
52
86
  toString(): string;
53
87
  }
@@ -7,7 +7,7 @@ const error_1 = require("./error");
7
7
  * @subcategory Data
8
8
  */
9
9
  class NesoiDuration {
10
- static UNITS = {
10
+ static TIME_UNITS = {
11
11
  ms: 'miliseconds',
12
12
  milisecond: 'miliseconds',
13
13
  miliseconds: 'miliseconds',
@@ -20,7 +20,9 @@ class NesoiDuration {
20
20
  minutes: 'minutes',
21
21
  h: 'hours',
22
22
  hour: 'hours',
23
- hours: 'hours',
23
+ hours: 'hours'
24
+ };
25
+ static DATE_UNITS = {
24
26
  d: 'days',
25
27
  day: 'days',
26
28
  days: 'days',
@@ -33,6 +35,10 @@ class NesoiDuration {
33
35
  year: 'years',
34
36
  years: 'years',
35
37
  };
38
+ static UNITS = {
39
+ ...this.TIME_UNITS,
40
+ ...this.DATE_UNITS
41
+ };
36
42
  value;
37
43
  unit;
38
44
  constructor(value) {
@@ -207,6 +207,12 @@ export declare namespace NesoiError {
207
207
  function InvalidISOString($: {
208
208
  value: string;
209
209
  }): BaseError;
210
+ function InvalidDate($: {
211
+ value: string;
212
+ }): BaseError;
213
+ function InvalidDatetime($: {
214
+ value: string;
215
+ }): BaseError;
210
216
  function InvalidDuration($: {
211
217
  value: string;
212
218
  }): BaseError;
@@ -347,6 +347,14 @@ var NesoiError;
347
347
  return new BaseError('Message.Data.InvalidISOString', `'${$.value}' is not a valid ISO string`, Status.BAD_REQUEST, $);
348
348
  }
349
349
  Data.InvalidISOString = InvalidISOString;
350
+ function InvalidDate($) {
351
+ return new BaseError('Message.Data.InvalidDate', `'${$.value}' is not a valid date`, Status.BAD_REQUEST, $);
352
+ }
353
+ Data.InvalidDate = InvalidDate;
354
+ function InvalidDatetime($) {
355
+ return new BaseError('Message.Data.InvalidDatetime', `'${$.value}' is not a valid datetime`, Status.BAD_REQUEST, $);
356
+ }
357
+ Data.InvalidDatetime = InvalidDatetime;
350
358
  function InvalidDuration($) {
351
359
  return new BaseError('Message.Data.InvalidDuration', `'${$.value}' is not a valid duration`, Status.BAD_REQUEST, $);
352
360
  }
@@ -57,7 +57,8 @@ class ExternalTrxNode {
57
57
  throw hold.status.error;
58
58
  }
59
59
  out = hold.status.output;
60
- if (!(tag in parent.holds)) {
60
+ const parentModule = trx_node_1.TrxNode.getModule(parent.root);
61
+ if (!(tag in parent.holds) && this.tag.module !== parentModule.name) {
61
62
  parent.holds[tag] = hold;
62
63
  }
63
64
  }
@@ -76,7 +76,7 @@ class TrxEngine {
76
76
  }
77
77
  // Chain/Continue transaction
78
78
  else {
79
- const trxData = await this.ongoing[id];
79
+ const trxData = this.ongoing[id];
80
80
  // If trxData exists, the transaction to which it refers is non-idempotent,
81
81
  // since idempotent transactions are not stored.
82
82
  //
@@ -94,16 +94,16 @@ class TrxEngine {
94
94
  // On either case, it's allowed to be idempotent or not.
95
95
  const idempotent = trxData ? false : req_idempotent;
96
96
  trx = new trx_1.Trx(this, this.module, _origin, idempotent, undefined, id);
97
- // (Begin/Continue*)
97
+ // (Begin/Continue)
98
98
  // The request is for an idempotent transaction.
99
99
  if (req_idempotent) {
100
100
  // A non-idempotent transaction with the same id exists on this module.
101
- // so it's being continued as an idempotent transaction.
101
+ // so it's being continued as an non-idempotent transaction.
102
102
  if (trxData) {
103
- log_1.Log.debug('module', this.module.name, `Continue* ${(0, log_1.scopeTag)('trx', trx.root.globalId)} @ ${(0, log_1.anyScopeTag)(_origin)}`);
104
- if (trxData.state !== 'hold') {
105
- throw new Error(`Attempt to continue transaction ${trxData.id}, currently at '${trxData.state}', failed. Should be at 'hold'. This might mean there are parallel attempts to continue a transaction, which must be handled with a queue.`);
106
- }
103
+ log_1.Log.debug('module', this.module.name, `Continue ${(0, log_1.scopeTag)('trx', trx.root.globalId)} @ ${(0, log_1.anyScopeTag)(_origin)}`);
104
+ // if (trxData.state !== 'hold') {
105
+ // throw new Error(`Attempt to continue transaction ${trxData.id}, currently at '${trxData.state}', failed. Should be at 'hold'. This might mean there are parallel attempts to continue a transaction, which must be handled with a queue.`)
106
+ // }
107
107
  for (const wrap of this.config?.wrap || []) {
108
108
  // The wrappers decide how to continue a db transaction, based on the trx idempotent flag.
109
109
  await wrap.continue(trx, this.services);
@@ -125,9 +125,9 @@ class TrxEngine {
125
125
  // so it's being continued.
126
126
  if (trxData) {
127
127
  log_1.Log.debug('module', this.module.name, `Continue ${(0, log_1.scopeTag)('trx', trx.root.globalId)} @ ${(0, log_1.anyScopeTag)(_origin)}`);
128
- if (trxData.state !== 'hold') {
129
- throw new Error(`Attempt to continue transaction ${trxData.id}, currently at '${trxData.state}', failed. Should be at 'hold'. This might mean there are parallel attempts to continue a transaction, which must be handled with a queue.`);
130
- }
128
+ // if (trxData.state !== 'hold') {
129
+ // throw new Error(`Attempt to continue transaction ${trxData.id}, currently at '${trxData.state}', failed. Should be at 'hold'. This might mean there are parallel attempts to continue a transaction, which must be handled with a queue.`)
130
+ // }
131
131
  // Update transaction with data read from adapter
132
132
  trx.start = trxData.start;
133
133
  trx.end = trxData.end;
@@ -179,7 +179,8 @@ class TrxEngine {
179
179
  await this.hold(trx, output);
180
180
  }
181
181
  catch (e) {
182
- await this.error(trx, e, false);
182
+ // Should only rollback if it's not a chained/continued trx
183
+ await this.error(trx, e, !!id);
183
184
  }
184
185
  return {
185
186
  id: trx.id,
@@ -62,7 +62,7 @@ class TrxNode {
62
62
  node.input = input;
63
63
  }
64
64
  static hold(node, output) {
65
- node.state = 'ok';
65
+ node.state = 'hold';
66
66
  node.output = output;
67
67
  node.time.hold = datetime_1.NesoiDatetime.now();
68
68
  }
@@ -252,16 +252,16 @@ class Treeshake {
252
252
  Object.values(tree).forEach(child => {
253
253
  const c = child;
254
254
  if (c.type === 'enum') {
255
- if ('dep' in c.meta.enum) {
256
- dependencies.push(c.meta.enum.dep);
255
+ if ('dep' in c._meta.enum) {
256
+ dependencies.push(c._meta.enum.dep);
257
257
  }
258
258
  }
259
259
  else if (c.type === 'id') {
260
- const ref = c.meta.id.bucket;
260
+ const ref = c._meta.id.bucket;
261
261
  dependencies.push(ref);
262
262
  }
263
263
  else if (c.type === 'msg') {
264
- dependencies.push(c.meta.msg);
264
+ dependencies.push(c._meta.msg);
265
265
  }
266
266
  else if (c.children) {
267
267
  dependencies.push(...Treeshake.messageFieldTree(node, c.children));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nesoi",
3
- "version": "3.4.14",
3
+ "version": "3.4.16",
4
4
  "description": "Declarative framework for data-driven applications",
5
5
  "repository": {
6
6
  "type": "git",