ddan-js 2.4.8 → 2.4.10

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,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isAllowed = exports.queryPermission = exports.legacyCopy = exports.copyText = void 0;
3
4
  const qs_1 = require("./qs");
4
5
  const dataURLtoFile = (dataurl, filename) => {
5
6
  // const _dataurl = decodeURIComponent(dataurl);
6
- let arr = dataurl.split(",");
7
+ let arr = dataurl.split(',');
7
8
  let mime = arr[0].match(/:(.*?);/)[1];
8
9
  let bstr = window.atob(arr[1]);
9
10
  let n = bstr.length;
@@ -14,7 +15,7 @@ const dataURLtoFile = (dataurl, filename) => {
14
15
  return new File([u8arr], filename, { type: mime });
15
16
  };
16
17
  const dataURLtoBlob = (dataurl) => {
17
- let arr = dataurl.split(",");
18
+ let arr = dataurl.split(',');
18
19
  let mime = arr[0].match(/:(.*?);/)[1];
19
20
  let bstr = window.atob(arr[1]);
20
21
  let n = bstr.length;
@@ -39,7 +40,7 @@ const readAsDataURL = (file, cb) => {
39
40
  };
40
41
  const _downloadUrl = (url, filename) => {
41
42
  try {
42
- const ele = document.createElement("a");
43
+ const ele = document.createElement('a');
43
44
  ele.style.display = 'none';
44
45
  ele.href = url;
45
46
  ele.download = filename;
@@ -51,7 +52,7 @@ const _downloadUrl = (url, filename) => {
51
52
  console.error(`[ddan] _downloadUrl ${url}`, err);
52
53
  }
53
54
  };
54
- const downloadUrl = (url, filename = "", checkSomeOrigin = false) => {
55
+ const downloadUrl = (url, filename = '', checkSomeOrigin = false) => {
55
56
  try {
56
57
  if (!url)
57
58
  return;
@@ -66,8 +67,8 @@ const downloadUrl = (url, filename = "", checkSomeOrigin = false) => {
66
67
  params.t = Date.now();
67
68
  const _url = `${map.path}?${qs_1.default.stringify(params, { uri: false })}`;
68
69
  const xhr = new XMLHttpRequest();
69
- xhr.open("GET", _url, true);
70
- xhr.responseType = "blob";
70
+ xhr.open('GET', _url, true);
71
+ xhr.responseType = 'blob';
71
72
  xhr.onload = function () {
72
73
  downloadFile(xhr.response, _filename);
73
74
  };
@@ -94,7 +95,7 @@ const getBlob = (url) => {
94
95
  xhr.send();
95
96
  });
96
97
  };
97
- const downloadFile = (data, filename = "") => {
98
+ const downloadFile = (data, filename = '') => {
98
99
  try {
99
100
  if (!data)
100
101
  return;
@@ -108,10 +109,10 @@ const downloadFile = (data, filename = "") => {
108
109
  console.error(`[ddan] downloadFile`, error);
109
110
  }
110
111
  };
111
- const download = (urlOrFile, filename = "") => {
112
+ const download = (urlOrFile, filename = '') => {
112
113
  if (!urlOrFile)
113
114
  return;
114
- if (typeof urlOrFile === "string") {
115
+ if (typeof urlOrFile === 'string') {
115
116
  downloadUrl(urlOrFile, filename);
116
117
  return;
117
118
  }
@@ -125,32 +126,32 @@ const downloadImage = (url) => {
125
126
  //下载群二维码
126
127
  const img = new Image();
127
128
  img.onload = () => {
128
- let canvas = document.createElement("canvas");
129
+ let canvas = document.createElement('canvas');
129
130
  canvas.width = img.width;
130
131
  canvas.height = img.height;
131
- let context = canvas.getContext("2d");
132
+ let context = canvas.getContext('2d');
132
133
  context && context.drawImage(img, 0, 0, img.width, img.height);
133
134
  let base64 = canvas.toDataURL(); //得到图片的base64编码数据
134
135
  downloadUrl(base64, name);
135
136
  };
136
137
  img.src = url; // 将canvas对象转换为图片的data url
137
- img.setAttribute("crossOrigin", "Anonymous");
138
+ img.setAttribute('crossOrigin', 'Anonymous');
138
139
  }
139
140
  catch (err) {
140
141
  console.error(`[ddan] downloadImage`, err);
141
142
  }
142
143
  return Promise.resolve();
143
144
  };
144
- const watermark = (text, { width = 400, height = 300, angle = 0, fillStyle = "rgba(0, 0, 0, 0.2)", font = "16px Arial", textAlign = "left", textBaseline = "middle" } = {}) => {
145
+ const watermark = (text, { width = 400, height = 300, angle = 0, fillStyle = 'rgba(0, 0, 0, 0.2)', font = '16px Arial', textAlign = 'left', textBaseline = 'middle', } = {}) => {
145
146
  try {
146
147
  if (!text)
147
- return "";
148
- const canvas = document.createElement("canvas");
148
+ return '';
149
+ const canvas = document.createElement('canvas');
149
150
  canvas.width = width;
150
151
  canvas.height = height;
151
- const ctx = canvas.getContext("2d");
152
+ const ctx = canvas.getContext('2d');
152
153
  if (!ctx)
153
- return "";
154
+ return '';
154
155
  angle && ctx.rotate((angle * Math.PI) / 180);
155
156
  fillStyle && (ctx.fillStyle = fillStyle);
156
157
  font && (ctx.font = font);
@@ -161,9 +162,75 @@ const watermark = (text, { width = 400, height = 300, angle = 0, fillStyle = "rg
161
162
  }
162
163
  catch (err) {
163
164
  console.error(`[ddan] watermark`, err);
164
- return "";
165
+ return '';
165
166
  }
166
167
  };
168
+ const copyText = (text, legacy = false) => {
169
+ return new Promise((resolve) => {
170
+ if (legacy || !navigator.clipboard) {
171
+ resolve((0, exports.legacyCopy)(text));
172
+ return;
173
+ }
174
+ (0, exports.queryPermission)('clipboard-write')
175
+ .then((state) => {
176
+ if ((0, exports.isAllowed)(state, false)) {
177
+ navigator.clipboard.writeText(text);
178
+ resolve(true);
179
+ }
180
+ else {
181
+ resolve((0, exports.legacyCopy)(text));
182
+ }
183
+ })
184
+ .catch(() => {
185
+ resolve(false);
186
+ });
187
+ });
188
+ };
189
+ exports.copyText = copyText;
190
+ const legacyCopy = (text) => {
191
+ try {
192
+ const _textarea = document.createElement('textarea');
193
+ document.body.appendChild(_textarea);
194
+ // 隐藏此输入框
195
+ _textarea.style.position = 'fixed';
196
+ _textarea.style.clip = 'rect(0 0 0 0)';
197
+ _textarea.style.top = '10px';
198
+ _textarea.style.opacity = '0';
199
+ // 赋值
200
+ _textarea.value = text ?? '';
201
+ // 选中
202
+ _textarea.select();
203
+ // 复制
204
+ const result = document.execCommand('copy');
205
+ // 移除输入框
206
+ document.body.removeChild(_textarea);
207
+ return result;
208
+ }
209
+ catch (err) {
210
+ console.error(`[ddan] copyText`, err);
211
+ return false;
212
+ }
213
+ };
214
+ exports.legacyCopy = legacyCopy;
215
+ const queryPermission = (name, def = 'denied') => {
216
+ return new Promise((resolve) => {
217
+ const permissions = navigator?.permissions;
218
+ if (!permissions || !permissions.query)
219
+ return resolve(def);
220
+ const desc = { name };
221
+ permissions
222
+ .query(desc)
223
+ .then((res) => resolve(res.state))
224
+ .catch(() => resolve(def));
225
+ });
226
+ };
227
+ exports.queryPermission = queryPermission;
228
+ const isAllowed = (status, prompt = true) => {
229
+ if (prompt && status === 'prompt')
230
+ return true;
231
+ return status === 'granted';
232
+ };
233
+ exports.isAllowed = isAllowed;
167
234
  exports.default = {
168
235
  dataURLtoFile,
169
236
  dataURLtoBlob,
@@ -174,4 +241,7 @@ exports.default = {
174
241
  downloadFile,
175
242
  downloadImage,
176
243
  watermark,
244
+ copyText: exports.copyText,
245
+ queryPermission: exports.queryPermission,
246
+ isAllowed: exports.isAllowed,
177
247
  };
@@ -1,5 +1,5 @@
1
- import DEvent from "./event";
2
- import { Ddan } from "../typings";
1
+ import DEvent from './event';
2
+ import { Ddan } from '../typings';
3
3
  export default class DStore extends DEvent implements Ddan.IDStore {
4
4
  setters: Record<string, Ddan.TStoreSetterFunction>;
5
5
  getters: Record<string, Ddan.TStoreGetterFunction>;
@@ -1,7 +1,7 @@
1
1
  export default class DTask<T = any> {
2
2
  __source: any;
3
3
  constructor(source?: any);
4
- run(): Promise<[null, T] | [any, undefined]>;
4
+ run: () => Promise<[any, undefined] | [null, T]>;
5
5
  static _lockedMap: Map<string, Promise<any[]>>;
6
6
  static _lock(id: string, func: Function): Promise<[any, undefined] | [null, any]> | undefined;
7
7
  static _unlock(id: string): void;
@@ -186,6 +186,7 @@ declare const dUtil: {
186
186
  };
187
187
  };
188
188
  declare const dHook: {
189
+ sleep: (ms?: number) => Promise<unknown>;
189
190
  run: <T = any>(task?: Function | Promise<T> | undefined, wait?: number) => Promise<[any, undefined] | [null, T]>;
190
191
  exec: (func: Function, taskId?: string) => Promise<any[]>;
191
192
  debounce: typeof import("./modules/hook/debounce").default;
@@ -194,7 +195,23 @@ declare const dHook: {
194
195
  mutex: typeof import("./modules/hook/mutex").default;
195
196
  polling: typeof import("./modules/hook/polling").default;
196
197
  to: <T_1 = any, U extends object = any>(promise: Promise<T_1>, errorExt?: object | undefined) => Promise<[null, T_1] | [U, undefined]>;
197
- delay: (time?: number) => Promise<unknown>;
198
+ go: <T_2 = any>(task?: Function | Promise<T_2> | undefined) => Promise<[any, undefined] | [null, T_2]>;
199
+ delay: (ms?: number) => Promise<unknown>;
200
+ safeDo: <T_3 = any>(func: any) => Promise<[null, T_3] | [any, undefined]>;
201
+ base64: {
202
+ encode: (input: string) => string;
203
+ decode: (input: string) => string;
204
+ encodeByOss: (input: string) => string;
205
+ };
206
+ uuid: (len?: number, radix?: number) => string;
207
+ guid: (len: number, prefix?: boolean, sep?: string) => string;
208
+ keyNumber: string;
209
+ keyLower: string;
210
+ keyUpper: string;
211
+ keyChars: string;
212
+ uint8ArrayToString: (arr: any) => string;
213
+ stringToArrayBuffer: (str: any) => ArrayBuffer;
214
+ arrayBufferToString: (data: ArrayBuffer, base64?: boolean) => string;
198
215
  };
199
216
  declare const dMini: {
200
217
  mini: {
@@ -268,7 +285,7 @@ declare const dMini: {
268
285
  download: (urlOrFile: string | Blob | MediaSource, filename?: string) => void;
269
286
  downloadFile: (data: Blob | MediaSource, filename?: string) => void;
270
287
  downloadImage: (url: string) => Promise<void> | undefined;
271
- watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline }?: {
288
+ watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline, }?: {
272
289
  width?: number | undefined;
273
290
  height?: number | undefined;
274
291
  angle?: number | undefined;
@@ -277,6 +294,9 @@ declare const dMini: {
277
294
  textAlign?: "center" | "end" | "left" | "right" | "start" | undefined;
278
295
  textBaseline?: "alphabetic" | "bottom" | "hanging" | "ideographic" | "middle" | "top" | undefined;
279
296
  }) => string;
297
+ copyText: (text: string, legacy?: boolean) => Promise<unknown>;
298
+ queryPermission: (name: string, def?: PermissionState) => Promise<PermissionState>;
299
+ isAllowed: (status: PermissionState | undefined, prompt?: boolean) => boolean;
280
300
  };
281
301
  };
282
302
  declare const dCdn: {
@@ -397,7 +417,7 @@ declare const dWeb: {
397
417
  download: (urlOrFile: string | Blob | MediaSource, filename?: string) => void;
398
418
  downloadFile: (data: Blob | MediaSource, filename?: string) => void;
399
419
  downloadImage: (url: string) => Promise<void> | undefined;
400
- watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline }?: {
420
+ watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline, }?: {
401
421
  width?: number | undefined;
402
422
  height?: number | undefined;
403
423
  angle?: number | undefined;
@@ -406,6 +426,9 @@ declare const dWeb: {
406
426
  textAlign?: "center" | "end" | "left" | "right" | "start" | undefined;
407
427
  textBaseline?: "alphabetic" | "bottom" | "hanging" | "ideographic" | "middle" | "top" | undefined;
408
428
  }) => string;
429
+ copyText: (text: string, legacy?: boolean) => Promise<unknown>;
430
+ queryPermission: (name: string, def?: PermissionState) => Promise<PermissionState>;
431
+ isAllowed: (status: PermissionState | undefined, prompt?: boolean) => boolean;
409
432
  };
410
433
  };
411
434
  export { dUtil, dHook, dWeb, dMini, dCdn, dStore, dJoker, dTracker, dLogger };
@@ -436,6 +459,7 @@ declare const _default: {
436
459
  oneSecond: number;
437
460
  };
438
461
  hook: {
462
+ sleep: (ms?: number) => Promise<unknown>;
439
463
  run: <T = any>(task?: Function | Promise<T> | undefined, wait?: number) => Promise<[any, undefined] | [null, T]>;
440
464
  exec: (func: Function, taskId?: string) => Promise<any[]>;
441
465
  debounce: typeof import("./modules/hook/debounce").default;
@@ -444,7 +468,9 @@ declare const _default: {
444
468
  mutex: typeof import("./modules/hook/mutex").default;
445
469
  polling: typeof import("./modules/hook/polling").default;
446
470
  to: <T_1 = any, U extends object = any>(promise: Promise<T_1>, errorExt?: object | undefined) => Promise<[null, T_1] | [U, undefined]>;
447
- delay: (time?: number) => Promise<unknown>;
471
+ go: <T_2 = any>(task?: Function | Promise<T_2> | undefined) => Promise<[any, undefined] | [null, T_2]>;
472
+ delay: (ms?: number) => Promise<unknown>;
473
+ safeDo: <T_3 = any>(func: any) => Promise<[null, T_3] | [any, undefined]>;
448
474
  };
449
475
  math: {
450
476
  random: (max: number) => number;
@@ -469,12 +495,12 @@ declare const _default: {
469
495
  util: {
470
496
  includes: typeof import("./util/includes").default;
471
497
  forof: (source: any, cb: (key: any, val: any) => void) => void;
472
- singleton: <T_2>() => {
498
+ singleton: <T_4>() => {
473
499
  new (): {};
474
500
  __instance__: any;
475
- readonly Instance: T_2;
501
+ readonly Instance: T_4;
476
502
  };
477
- getset: <T_3 = any>(t?: T_3 | undefined) => import("./typings").Ddan.IGetset<T_3>;
503
+ getset: <T_5 = any>(t?: T_5 | undefined) => import("./typings").Ddan.IGetset<T_5>;
478
504
  copy: (source: any, options?: {
479
505
  fields?: string[] | undefined;
480
506
  camel?: boolean | undefined;
@@ -487,7 +513,7 @@ declare const _default: {
487
513
  number?: boolean | undefined;
488
514
  boolean?: boolean | undefined;
489
515
  }) => any;
490
- cloneClass: <T_4>(source: T_4) => T_4;
516
+ cloneClass: <T_6>(source: T_6) => T_6;
491
517
  combine: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => any;
492
518
  combines: (objs: any[], options?: import("./typings").Ddan.IIgnoreParams) => {};
493
519
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
@@ -513,16 +539,16 @@ declare const _default: {
513
539
  isPromise: (value: any) => boolean;
514
540
  };
515
541
  list: {
516
- stepAction: <T_5>(list: T_5[], func: import("./typings").Ddan.Task<T_5, void>, stepCount?: number) => void;
517
- skip: <T_6>(list: T_6[], count: number) => T_6[];
518
- take: <T_7>(list: T_7[], count: number, skip?: number) => T_7[];
519
- distinct: <T_8>(list: T_8[]) => T_8[];
520
- randoms: <T_9>(list: T_9[], count?: number, repeat?: boolean) => T_9[];
542
+ stepAction: <T_7>(list: T_7[], func: import("./typings").Ddan.Task<T_7, void>, stepCount?: number) => void;
543
+ skip: <T_8>(list: T_8[], count: number) => T_8[];
544
+ take: <T_9>(list: T_9[], count: number, skip?: number) => T_9[];
545
+ distinct: <T_10>(list: T_10[]) => T_10[];
546
+ randoms: <T_11>(list: T_11[], count?: number, repeat?: boolean) => T_11[];
521
547
  toKV: (list: import("./typings").Ddan.KV<any>[], key: string, value: string) => import("./typings").Ddan.KV<any>;
522
- groupBy: <T_10>(list: T_10[], key: string) => Record<string, T_10[]>;
523
- first: <T_11>(list: T_11[]) => T_11 | undefined;
524
- last: <T_12>(list: T_12[]) => T_12 | undefined;
525
- toList: <T_13>(val: T_13 | T_13[]) => T_13[];
548
+ groupBy: <T_12>(list: T_12[], key: string) => Record<string, T_12[]>;
549
+ first: <T_13>(list: T_13[]) => T_13 | undefined;
550
+ last: <T_14>(list: T_14[]) => T_14 | undefined;
551
+ toList: <T_15>(val: T_15 | T_15[]) => T_15[];
526
552
  };
527
553
  string: {
528
554
  toString: (value: any) => any;
@@ -554,7 +580,7 @@ declare const _default: {
554
580
  number?: boolean | undefined;
555
581
  boolean?: boolean | undefined;
556
582
  }) => any;
557
- cloneClass: <T_4>(source: T_4) => T_4;
583
+ cloneClass: <T_6>(source: T_6) => T_6;
558
584
  combine: (target: any, source: any, options?: import("./typings").Ddan.IIgnoreParams) => any;
559
585
  combines: (objs: any[], options?: import("./typings").Ddan.IIgnoreParams) => {};
560
586
  observe: (obj: any, key: any, watchFun: any, owner: any, deep?: boolean) => void;
@@ -658,7 +684,7 @@ declare const _default: {
658
684
  download: (urlOrFile: string | Blob | MediaSource, filename?: string) => void;
659
685
  downloadFile: (data: Blob | MediaSource, filename?: string) => void;
660
686
  downloadImage: (url: string) => Promise<void> | undefined;
661
- watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline }?: {
687
+ watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline, }?: {
662
688
  width?: number | undefined;
663
689
  height?: number | undefined;
664
690
  angle?: number | undefined;
@@ -667,6 +693,9 @@ declare const _default: {
667
693
  textAlign?: "center" | "end" | "left" | "right" | "start" | undefined;
668
694
  textBaseline?: "alphabetic" | "bottom" | "hanging" | "ideographic" | "middle" | "top" | undefined;
669
695
  }) => string;
696
+ copyText: (text: string, legacy?: boolean) => Promise<unknown>;
697
+ queryPermission: (name: string, def?: PermissionState) => Promise<PermissionState>;
698
+ isAllowed: (status: PermissionState | undefined, prompt?: boolean) => boolean;
670
699
  };
671
700
  icon: import("./class/icon").DIcon;
672
701
  rule: {
@@ -1,6 +1,8 @@
1
1
  declare function to<T = any, U extends object = any>(promise: Promise<T>, errorExt?: object): Promise<[null, T] | [U, undefined]>;
2
2
  declare const _default: {
3
3
  to: typeof to;
4
- delay: (time?: number) => Promise<unknown>;
4
+ go: <T = any>(task?: Function | Promise<T> | undefined) => Promise<[any, undefined] | [null, T]>;
5
+ delay: (ms?: number) => Promise<unknown>;
6
+ safeDo: <T_1 = any>(func: any) => Promise<[null, T_1] | [any, undefined]>;
5
7
  };
6
8
  export default _default;
@@ -1,9 +1,9 @@
1
- import debounce from "./debounce";
2
- import throttle from "./throttle";
3
- import mutex from "./mutex";
4
- import DPipeTask from "../../class/pipeTask";
5
- import { Ddan } from "../../typings";
6
- import polling from "./polling";
1
+ import debounce from './debounce';
2
+ import throttle from './throttle';
3
+ import mutex from './mutex';
4
+ import DPipeTask from '../../class/pipeTask';
5
+ import { Ddan } from '../../typings';
6
+ import polling from './polling';
7
7
  /**
8
8
  *
9
9
  * @param task 任务
@@ -12,6 +12,7 @@ import polling from "./polling";
12
12
  */
13
13
  declare function run<T = any>(task?: Promise<T> | Function, wait?: number): Promise<[any, undefined] | [null, T]>;
14
14
  declare const _default: {
15
+ sleep: (ms?: number) => Promise<unknown>;
15
16
  run: typeof run;
16
17
  exec: (func: Function, taskId?: string) => Promise<any[]>;
17
18
  debounce: typeof debounce;
@@ -20,6 +21,8 @@ declare const _default: {
20
21
  mutex: typeof mutex;
21
22
  polling: typeof polling;
22
23
  to: <T = any, U extends object = any>(promise: Promise<T>, errorExt?: object | undefined) => Promise<[null, T] | [U, undefined]>;
23
- delay: (time?: number) => Promise<unknown>;
24
+ go: <T_1 = any>(task?: Function | Promise<T_1> | undefined) => Promise<[any, undefined] | [null, T_1]>;
25
+ delay: (ms?: number) => Promise<unknown>;
26
+ safeDo: <T_2 = any>(func: any) => Promise<[null, T_2] | [any, undefined]>;
24
27
  };
25
28
  export default _default;
@@ -1,3 +1,7 @@
1
+ export declare const copyText: (text: string, legacy?: boolean) => Promise<unknown>;
2
+ export declare const legacyCopy: (text: string) => boolean;
3
+ export declare const queryPermission: (name: string, def?: PermissionState) => Promise<PermissionState>;
4
+ export declare const isAllowed: (status: PermissionState | undefined, prompt?: boolean) => boolean;
1
5
  declare const _default: {
2
6
  dataURLtoFile: (dataurl: any, filename: any) => File;
3
7
  dataURLtoBlob: (dataurl: any) => Blob;
@@ -7,7 +11,7 @@ declare const _default: {
7
11
  download: (urlOrFile: string | Blob | MediaSource, filename?: string) => void;
8
12
  downloadFile: (data: Blob | MediaSource, filename?: string) => void;
9
13
  downloadImage: (url: string) => Promise<void> | undefined;
10
- watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline }?: {
14
+ watermark: (text: string, { width, height, angle, fillStyle, font, textAlign, textBaseline, }?: {
11
15
  width?: number | undefined;
12
16
  height?: number | undefined;
13
17
  angle?: number | undefined;
@@ -16,5 +20,8 @@ declare const _default: {
16
20
  textAlign?: "center" | "end" | "left" | "right" | "start" | undefined;
17
21
  textBaseline?: "alphabetic" | "bottom" | "hanging" | "ideographic" | "middle" | "top" | undefined;
18
22
  }) => string;
23
+ copyText: (text: string, legacy?: boolean) => Promise<unknown>;
24
+ queryPermission: (name: string, def?: PermissionState) => Promise<PermissionState>;
25
+ isAllowed: (status: PermissionState | undefined, prompt?: boolean) => boolean;
19
26
  };
20
27
  export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ddan-js",
3
- "version": "2.4.8",
3
+ "version": "2.4.10",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "ddan-js",