@lotics/app-sdk 0.125.5 → 0.125.7

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/index.js CHANGED
@@ -3306,6 +3306,10 @@ function length(value) {
3306
3306
  if (value == null) return 0;
3307
3307
  if (typeof value === "string") return value.length;
3308
3308
  if (Array.isArray(value)) return value.length;
3309
+ if (typeof value === "object" && Object.hasOwn(value, "length")) {
3310
+ const own = Reflect.get(value, "length");
3311
+ if (typeof own === "number") return own;
3312
+ }
3309
3313
  throw new ExpressionArgumentError("length: expected string or array, got " + typeof value);
3310
3314
  }
3311
3315
  function contains(str, search) {
@@ -5775,6 +5779,46 @@ function endOfDay(date2, options) {
5775
5779
  return _date;
5776
5780
  }
5777
5781
 
5782
+ // ../../node_modules/date-fns/startOfMonth.js
5783
+ function startOfMonth(date2, options) {
5784
+ const _date = toDate(date2, options?.in);
5785
+ _date.setDate(1);
5786
+ _date.setHours(0, 0, 0, 0);
5787
+ return _date;
5788
+ }
5789
+
5790
+ // ../../node_modules/date-fns/endOfMonth.js
5791
+ function endOfMonth(date2, options) {
5792
+ const _date = toDate(date2, options?.in);
5793
+ const month = _date.getMonth();
5794
+ _date.setFullYear(_date.getFullYear(), month + 1, 0);
5795
+ _date.setHours(23, 59, 59, 999);
5796
+ return _date;
5797
+ }
5798
+
5799
+ // ../../node_modules/date-fns/addMonths.js
5800
+ function addMonths(date2, amount, options) {
5801
+ const _date = toDate(date2, options?.in);
5802
+ if (isNaN(amount)) return constructFrom(options?.in || date2, NaN);
5803
+ if (!amount) {
5804
+ return _date;
5805
+ }
5806
+ const dayOfMonth = _date.getDate();
5807
+ const endOfDesiredMonth = constructFrom(options?.in || date2, _date.getTime());
5808
+ endOfDesiredMonth.setMonth(_date.getMonth() + amount + 1, 0);
5809
+ const daysInMonth = endOfDesiredMonth.getDate();
5810
+ if (dayOfMonth >= daysInMonth) {
5811
+ return endOfDesiredMonth;
5812
+ } else {
5813
+ _date.setFullYear(
5814
+ endOfDesiredMonth.getFullYear(),
5815
+ endOfDesiredMonth.getMonth(),
5816
+ dayOfMonth
5817
+ );
5818
+ return _date;
5819
+ }
5820
+ }
5821
+
5778
5822
  // ../../node_modules/date-fns/isWithinInterval.js
5779
5823
  function isWithinInterval(date2, interval, options) {
5780
5824
  const time = +toDate(date2, options?.in);
@@ -6087,7 +6131,7 @@ function addDays2(dateStr, days) {
6087
6131
  date2.setDate(date2.getDate() + days);
6088
6132
  return formatDate(date2.getFullYear(), date2.getMonth() + 1, date2.getDate());
6089
6133
  }
6090
- function addMonths(dateStr, months) {
6134
+ function addMonths2(dateStr, months) {
6091
6135
  const parsed = parseDate2(dateStr);
6092
6136
  const target = new Date(Date.UTC(parsed.year, parsed.month - 1 + months, 1));
6093
6137
  const lastDay = new Date(Date.UTC(target.getUTCFullYear(), target.getUTCMonth() + 1, 0)).getUTCDate();
@@ -6359,7 +6403,7 @@ function resolveRelativePoint(offset, unit, fixedTime, timezone) {
6359
6403
  result = addYears(result, offset);
6360
6404
  break;
6361
6405
  case "months":
6362
- result = addMonths(result, offset);
6406
+ result = addMonths2(result, offset);
6363
6407
  break;
6364
6408
  case "weeks":
6365
6409
  result = addDays2(result, offset * 7);
@@ -6384,10 +6428,10 @@ function resolvePeriodPoint(period, boundary, offset, fixedTime, timezone) {
6384
6428
  referenceDate = addDays2(referenceDate, offset * 7);
6385
6429
  break;
6386
6430
  case "month":
6387
- referenceDate = addMonths(referenceDate, offset);
6431
+ referenceDate = addMonths2(referenceDate, offset);
6388
6432
  break;
6389
6433
  case "quarter":
6390
- referenceDate = addMonths(referenceDate, offset * 3);
6434
+ referenceDate = addMonths2(referenceDate, offset * 3);
6391
6435
  break;
6392
6436
  case "year":
6393
6437
  referenceDate = addYears(referenceDate, offset);
@@ -6882,6 +6926,44 @@ function getDateExpressionFunctions(defaultTimezone) {
6882
6926
  return endOfDay(normalized).toISOString();
6883
6927
  },
6884
6928
  // ========================================================================
6929
+ // MONTHS — payment terms ("30 days after month end") count from a month's edge
6930
+ // ========================================================================
6931
+ /**
6932
+ * Get the first moment of the date's month in the workspace timezone. Returns ISO string, or null if date is null.
6933
+ */
6934
+ startOfMonth: (date2, timezone) => {
6935
+ if (date2 == null || date2 === "") return null;
6936
+ validateDateInput(date2, "date", "startOfMonth");
6937
+ validateOptionalTimezone(timezone, "startOfMonth");
6938
+ const tz = getTimezone(timezone);
6939
+ const normalized = normalizeDateWithValidation(date2, tz, "startOfMonth");
6940
+ return startOfMonth(tz ? new TZDate(normalized, tz) : normalized).toISOString();
6941
+ },
6942
+ /**
6943
+ * Get the last moment of the date's month in the workspace timezone. Returns ISO string, or null if date is null.
6944
+ */
6945
+ endOfMonth: (date2, timezone) => {
6946
+ if (date2 == null || date2 === "") return null;
6947
+ validateDateInput(date2, "date", "endOfMonth");
6948
+ validateOptionalTimezone(timezone, "endOfMonth");
6949
+ const tz = getTimezone(timezone);
6950
+ const normalized = normalizeDateWithValidation(date2, tz, "endOfMonth");
6951
+ return endOfMonth(tz ? new TZDate(normalized, tz) : normalized).toISOString();
6952
+ },
6953
+ /**
6954
+ * Add months to a date (negative subtracts); a day past the target month's end lands on its last day
6955
+ * (31 Jan + 1 month is 28 or 29 Feb). Returns ISO string, or null if date is null.
6956
+ */
6957
+ addMonths: (date2, months, timezone) => {
6958
+ if (date2 == null || date2 === "") return null;
6959
+ validateDateInput(date2, "date", "addMonths");
6960
+ validateNumber(months, "months", "addMonths");
6961
+ validateOptionalTimezone(timezone, "addMonths");
6962
+ const tz = getTimezone(timezone);
6963
+ const normalized = normalizeDateWithValidation(date2, tz, "addMonths");
6964
+ return addMonths(tz ? new TZDate(normalized, tz) : normalized, months).toISOString();
6965
+ },
6966
+ // ========================================================================
6885
6967
  // DATE DIFFERENCES
6886
6968
  // ========================================================================
6887
6969
  /**
@@ -7382,6 +7464,9 @@ var HELPER_COST = {
7382
7464
  subMinutes: "builds",
7383
7465
  startOfDay: "builds",
7384
7466
  endOfDay: "builds",
7467
+ startOfMonth: "builds",
7468
+ endOfMonth: "builds",
7469
+ addMonths: "builds",
7385
7470
  differenceInCalendarDays: "reads",
7386
7471
  differenceInHours: "reads",
7387
7472
  differenceInMinutes: "reads",
package/docs/workflows.md CHANGED
@@ -498,7 +498,7 @@ full menu by category, so a miss is one informed retry.
498
498
  | **Number** | `sum`, `sumBy`, `mean`, `meanBy`, `min`, `max`, `minBy`, `maxBy`, `round`, `ceil`, `floor`, `abs`, `mod`, `pow`, `sqrt`, `clamp`, `percentage` |
499
499
  | **String** | `upper`, `lower`, `capitalize`, `trim`, `contains`, `startsWith`, `endsWith`, `replace`, `replaceAll`, `removeChars(text, chars)` (without every character that occurs in `chars`), `removeSpaces(text)` (without any whitespace), `substring`, `length`, `split`, `join`, `padStart`, `padEnd`, `uuidFrom(text)` (the same UUID for the same text), `formatNumber(value, decimals)` (fixed-decimal, ungrouped), `formatDecimal(value, decimals, locale)` (grouped for a reader — `formatDecimal(151000, 0, "vi-VN")` → `151.000`), `numberToWords(x, lang?)` (`"vi"` or `"en"`) |
500
500
  | **Object** | `keys`, `values`, `entries`, `get`, `pick`, `omit`, `merge`, `nonNullKeys` |
501
- | **Date** | `now`, `formatDate`, `parseDate`, `addDays`, `subDays`, `addHours`, `subHours`, `addMinutes`, `subMinutes`, `startOfDay`, `endOfDay`, `differenceInCalendarDays`, `differenceInHours`, `differenceInMinutes`, `isBefore`, `isAfter`, `isSameDay`, `isToday`, `isWithinRange`, `meetsBounds` |
501
+ | **Date** | `now`, `formatDate`, `parseDate`, `addDays`, `subDays`, `addHours`, `subHours`, `addMinutes`, `subMinutes`, `startOfDay`, `endOfDay`, `startOfMonth`, `endOfMonth`, `addMonths`, `differenceInCalendarDays`, `differenceInHours`, `differenceInMinutes`, `isBefore`, `isAfter`, `isSameDay`, `isToday`, `isWithinRange`, `meetsBounds` |
502
502
  | **Other** | `formatCurrency(amount, locale, currency)`, `randomNumber(len)`, `randomAlphaNumeric(len)`, `sample(items)`, `current_member_in_any_group(["grp_…"])`, `current_member_stands_in_for([memberId])`, `current_member_stands_in_for_any_group(["grp_…"])` |
503
503
 
504
504
  **Emptiness on a record cell.** `isNull` is the strict check — true only for `null`/`undefined`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/app-sdk",
3
- "version": "0.125.5",
3
+ "version": "0.125.7",
4
4
  "description": "The SDK a Lotics custom-code app reads and writes through — typed hooks over the host bridge, cell readers, mount() and AppRouter",
5
5
  "type": "module",
6
6
  "exports": {