@ciwergrp/nuxid 1.8.0 → 1.10.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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ciwergrp/nuxid",
3
3
  "configKey": "nuxid",
4
- "version": "1.8.0",
4
+ "version": "1.10.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -20,10 +20,23 @@ export interface CursorFetchOptions<TRequest extends NitroFetchRequest = NitroFe
20
20
  cursorParam?: string;
21
21
  query?: Record<string, any>;
22
22
  }
23
+ export interface FetchError<TData = any> {
24
+ statusCode: number | undefined;
25
+ statusMessage: string | undefined;
26
+ _data: TData | undefined;
27
+ }
23
28
  export declare function useCursorHttp<T extends Record<string, any> = any, TResponse extends APIResponseCursor<T> = APIResponseCursor<T>, TRequest extends NitroFetchRequest = NitroFetchRequest>(url: TRequest, options?: CursorFetchOptions<TRequest>): Promise<{
24
29
  data: import("vue").Ref<TResponse | undefined, TResponse | undefined>;
25
30
  loading: Readonly<import("vue").Ref<boolean, boolean>>;
26
- error: Readonly<import("vue").Ref<Error | null, Error | null>>;
31
+ error: Readonly<import("vue").Ref<{
32
+ readonly statusCode: number | undefined;
33
+ readonly statusMessage: string | undefined;
34
+ readonly _data: any;
35
+ } | null, {
36
+ readonly statusCode: number | undefined;
37
+ readonly statusMessage: string | undefined;
38
+ readonly _data: any;
39
+ } | null>>;
27
40
  hasNextPage: Readonly<import("vue").Ref<boolean, boolean>>;
28
41
  isLoadMoreTriggered: Readonly<import("vue").Ref<boolean, boolean>>;
29
42
  loadMore: () => Promise<void>;
@@ -36,6 +36,20 @@ export async function useCursorHttp(url, options) {
36
36
  }
37
37
  return unwrapped;
38
38
  }
39
+ function normalizeFetchError(e) {
40
+ if (e && typeof e === "object") {
41
+ const cast = e;
42
+ return {
43
+ statusCode: typeof cast.statusCode === "number" ? cast.statusCode : void 0,
44
+ statusMessage: typeof cast.statusMessage === "string" ? cast.statusMessage : cast.message ?? void 0,
45
+ _data: cast.data
46
+ };
47
+ }
48
+ if (typeof e === "string") {
49
+ return { statusCode: void 0, statusMessage: e, _data: void 0 };
50
+ }
51
+ return { statusCode: void 0, statusMessage: "Unknown error", _data: void 0 };
52
+ }
39
53
  const {
40
54
  lazy = false,
41
55
  immediate = true,
@@ -102,7 +116,7 @@ export async function useCursorHttp(url, options) {
102
116
  nextCursor.value = normalizeCursorValue(response.meta?.[cursorKey]);
103
117
  hasNextPage.value = response.meta?.[hasMoreKey] ?? false;
104
118
  } catch (e) {
105
- error.value = e;
119
+ error.value = normalizeFetchError(e);
106
120
  } finally {
107
121
  loading.value = false;
108
122
  }
@@ -1,5 +1,5 @@
1
1
  import type { FormRules } from 'element-plus';
2
- export type ValidationRule = 'required' | 'time' | 'string' | 'nullable' | 'email' | 'accepted' | `accepted_if:${string}` | 'boolean' | 'filled' | 'present' | `required_if:${string}` | `required_unless:${string}` | `required_with:${string}` | `required_with_all:${string}` | `required_without:${string}` | `required_without_all:${string}` | 'prohibited' | `prohibited_if:${string}` | `prohibited_unless:${string}` | `prohibits:${string}` | `min:${number}` | `max:${number}` | `between:${number},${number}` | `size:${number}` | `same:${string}` | 'alpha' | 'alpha_num' | 'alpha_dash' | 'alphanumeric_space' | 'alpha_space' | 'numeric' | 'integer' | 'confirmed' | `digits:${number}` | `digits_between:${number},${number}` | 'bail' | `different:${string}` | `gt:${string}` | `gte:${string}` | `lt:${string}` | `lte:${string}` | `starts_with:${string}` | `ends_with:${string}` | `regex:${string}` | `date_format:${string}` | 'date' | `before:${string}` | `after:${string}` | `before_or_equal:${string}` | `after_or_equal:${string}` | 'array' | 'distinct' | `in_array:${string}` | `required_array_keys:${string}` | 'list' | 'url' | 'ip' | 'hex_color' | `in:${string}` | `multiple_of:${number}` | `decimal:${number}` | `decimal:${number},${number}` | 'lowercase' | 'uppercase' | 'uuid' | 'ulid' | `timezone:${string}` | 'timezone';
2
+ export type ValidationRule = 'required' | 'time' | 'datetime' | 'string' | 'nullable' | 'email' | 'accepted' | `accepted_if:${string}` | 'boolean' | 'filled' | 'present' | `required_if:${string}` | `required_unless:${string}` | `required_with:${string}` | `required_with_all:${string}` | `required_without:${string}` | `required_without_all:${string}` | 'prohibited' | `prohibited_if:${string}` | `prohibited_unless:${string}` | `prohibits:${string}` | `min:${number}` | `max:${number}` | `between:${number},${number}` | `size:${number}` | `same:${string}` | 'alpha' | 'alpha_num' | 'alpha_dash' | 'alphanumeric_space' | 'alpha_space' | 'numeric' | 'integer' | 'confirmed' | `digits:${number}` | `digits_between:${number},${number}` | 'bail' | `different:${string}` | `gt:${string}` | `gte:${string}` | `lt:${string}` | `lte:${string}` | `starts_with:${string}` | `ends_with:${string}` | `regex:${string}` | `date_format:${string}` | 'date' | `before:${string}` | `after:${string}` | `before_or_equal:${string}` | `after_or_equal:${string}` | 'array' | 'distinct' | `in_array:${string}` | `required_array_keys:${string}` | 'list' | 'url' | 'ip' | 'hex_color' | `in:${string}` | `multiple_of:${number}` | `decimal:${number}` | `decimal:${number},${number}` | 'lowercase' | 'uppercase' | 'uuid' | 'ulid' | `timezone:${string}` | 'timezone';
3
3
  export interface ValidationOptions {
4
4
  messages?: Record<string, string>;
5
5
  attributes?: Record<string, string>;
@@ -84,17 +84,43 @@ const isAcceptedValue = (value) => {
84
84
  const isBooleanValue = (value) => {
85
85
  return value === true || value === false || value === 0 || value === 1 || value === "0" || value === "1";
86
86
  };
87
- const parseTimeToMinutes = (value) => {
87
+ const parseTimeToComparable = (value) => {
88
88
  if (typeof value !== "string") {
89
89
  return null;
90
90
  }
91
- const match = value.match(/^([01]\d|2[0-3]):([0-5]\d)$/);
91
+ const match = value.match(
92
+ /^([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d)(?:\.(\d{1,3}))?)?(?:(z)|([+-])([01]\d|2[0-3]):?([0-5]\d))?$/i
93
+ );
92
94
  if (!match) {
93
95
  return null;
94
96
  }
95
97
  const hours = Number(match[1]);
96
98
  const minutes = Number(match[2]);
97
- return hours * 60 + minutes;
99
+ const seconds = match[3] ? Number(match[3]) : 0;
100
+ const milliseconds = match[4] ? Number(match[4].padEnd(3, "0")) : 0;
101
+ const hasZuluOffset = Boolean(match[5]);
102
+ const offsetSign = match[6];
103
+ const offsetHours = match[7] ? Number(match[7]) : 0;
104
+ const offsetMinutes = match[8] ? Number(match[8]) : 0;
105
+ const localComparableValue = hours * 36e5 + minutes * 6e4 + seconds * 1e3 + milliseconds;
106
+ if (hasZuluOffset) {
107
+ return {
108
+ comparableValue: localComparableValue,
109
+ hasOffset: true
110
+ };
111
+ }
112
+ if (offsetSign) {
113
+ const offsetComparable = (offsetHours * 60 + offsetMinutes) * 6e4;
114
+ const direction = offsetSign === "+" ? 1 : -1;
115
+ return {
116
+ comparableValue: localComparableValue - direction * offsetComparable,
117
+ hasOffset: true
118
+ };
119
+ }
120
+ return {
121
+ comparableValue: localComparableValue,
122
+ hasOffset: false
123
+ };
98
124
  };
99
125
  const parseDateToTimestamp = (value) => {
100
126
  if (typeof value !== "string") {
@@ -109,14 +135,53 @@ const parseDateToTimestamp = (value) => {
109
135
  }
110
136
  return date.getTime();
111
137
  };
138
+ const parseDateTimeToTimestamp = (value) => {
139
+ if (typeof value !== "string") {
140
+ return null;
141
+ }
142
+ const match = value.match(
143
+ /^(\d{4})-(\d{2})-(\d{2})[T ]([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d)(?:\.(\d{1,3}))?)?(?:([zZ])|([+-])([01]\d|2[0-3]):?([0-5]\d))?$/
144
+ );
145
+ if (!match) {
146
+ return null;
147
+ }
148
+ const year = Number(match[1]);
149
+ const month = Number(match[2]);
150
+ const day = Number(match[3]);
151
+ const hours = Number(match[4]);
152
+ const minutes = Number(match[5]);
153
+ const seconds = match[6] ? Number(match[6]) : 0;
154
+ const milliseconds = match[7] ? Number(match[7].padEnd(3, "0")) : 0;
155
+ const utcCandidate = Date.UTC(year, month - 1, day, hours, minutes, seconds, milliseconds);
156
+ const utcDate = new Date(utcCandidate);
157
+ if (utcDate.getUTCFullYear() !== year || utcDate.getUTCMonth() !== month - 1 || utcDate.getUTCDate() !== day || utcDate.getUTCHours() !== hours || utcDate.getUTCMinutes() !== minutes || utcDate.getUTCSeconds() !== seconds || utcDate.getUTCMilliseconds() !== milliseconds) {
158
+ return null;
159
+ }
160
+ const hasZuluOffset = Boolean(match[8]);
161
+ const offsetSign = match[9];
162
+ const offsetHour = match[10] ? Number(match[10]) : 0;
163
+ const offsetMinute = match[11] ? Number(match[11]) : 0;
164
+ if (hasZuluOffset) {
165
+ return utcCandidate;
166
+ }
167
+ if (offsetSign) {
168
+ const totalOffsetMinutes = offsetHour * 60 + offsetMinute;
169
+ const direction = offsetSign === "+" ? 1 : -1;
170
+ return utcCandidate - direction * totalOffsetMinutes * 6e4;
171
+ }
172
+ return utcCandidate;
173
+ };
112
174
  const compareFieldValues = (left, right, compare) => {
113
- const leftTime = parseTimeToMinutes(left);
114
- const rightTime = parseTimeToMinutes(right);
175
+ const leftTime = parseTimeToComparable(left);
176
+ const rightTime = parseTimeToComparable(right);
115
177
  if (leftTime !== null || rightTime !== null) {
116
178
  if (leftTime === null || rightTime === null) {
117
179
  return false;
118
180
  }
119
- return compare(leftTime, rightTime);
181
+ if (leftTime.hasOffset !== rightTime.hasOffset) {
182
+ return false;
183
+ }
184
+ return compare(leftTime.comparableValue, rightTime.comparableValue);
120
185
  }
121
186
  const leftDate = parseDateToTimestamp(left);
122
187
  const rightDate = parseDateToTimestamp(right);
@@ -126,6 +191,14 @@ const compareFieldValues = (left, right, compare) => {
126
191
  }
127
192
  return compare(leftDate, rightDate);
128
193
  }
194
+ const leftDateTime = parseDateTimeToTimestamp(left);
195
+ const rightDateTime = parseDateTimeToTimestamp(right);
196
+ if (leftDateTime !== null || rightDateTime !== null) {
197
+ if (leftDateTime === null || rightDateTime === null) {
198
+ return false;
199
+ }
200
+ return compare(leftDateTime, rightDateTime);
201
+ }
129
202
  const leftNumber = Number(left);
130
203
  const rightNumber = Number(right);
131
204
  if (Number.isNaN(leftNumber) || Number.isNaN(rightNumber)) {
@@ -173,7 +246,7 @@ const createTimeValidator = (message) => {
173
246
  if (isEmptyValue(value)) {
174
247
  return callback();
175
248
  }
176
- if (parseTimeToMinutes(value) === null) {
249
+ if (parseTimeToComparable(value) === null) {
177
250
  return callback(new Error(message));
178
251
  }
179
252
  callback();
@@ -232,6 +305,17 @@ const createDateValidator = (message) => {
232
305
  callback();
233
306
  };
234
307
  };
308
+ const createDateTimeValidator = (message) => {
309
+ return (_rule, value, callback) => {
310
+ if (isEmptyValue(value)) {
311
+ return callback();
312
+ }
313
+ if (parseDateTimeToTimestamp(value) === null) {
314
+ return callback(new Error(message));
315
+ }
316
+ callback();
317
+ };
318
+ };
235
319
  const createDateComparisonValidator = (compareDate, message, compare) => {
236
320
  return (_rule, value, callback) => {
237
321
  if (!value) {
@@ -665,7 +749,7 @@ export const createValidationRules = (definitions, formState, options = {}) => {
665
749
  break;
666
750
  case "time":
667
751
  fieldRules.push({
668
- validator: createTimeValidator(getMessage(fieldName, "time", `${attributeName} must be a valid time in HH:mm format`)),
752
+ validator: createTimeValidator(getMessage(fieldName, "time", `${attributeName} must be a valid time`)),
669
753
  trigger: pickTrigger(fieldName, "blur")
670
754
  });
671
755
  break;
@@ -784,6 +868,12 @@ export const createValidationRules = (definitions, formState, options = {}) => {
784
868
  trigger: pickTrigger(fieldName, "blur")
785
869
  });
786
870
  break;
871
+ case "datetime":
872
+ fieldRules.push({
873
+ validator: createDateTimeValidator(getMessage(fieldName, "datetime", `${attributeName} must be a valid datetime`)),
874
+ trigger: pickTrigger(fieldName, "blur")
875
+ });
876
+ break;
787
877
  case "before":
788
878
  if (!firstParam) {
789
879
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ciwergrp/nuxid",
3
- "version": "1.8.0",
3
+ "version": "1.10.0",
4
4
  "description": "All-in-one essential modules for Nuxt",
5
5
  "repository": {
6
6
  "type": "git",