@aegis-framework/artemis 0.5.0 → 0.5.1
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/README.md +9 -1
- package/dist/artemis.browser.js +2 -2
- package/dist/artemis.browser.js.map +12 -12
- package/dist/artemis.js +2 -2
- package/dist/artemis.js.map +11 -11
- package/dist/types/DOM.d.ts +4 -3
- package/dist/types/DOM.d.ts.map +1 -1
- package/dist/types/Debug.d.ts.map +1 -1
- package/dist/types/Request.d.ts.map +1 -1
- package/dist/types/Space.d.ts.map +1 -1
- package/dist/types/SpaceAdapter/IndexedDB.d.ts.map +1 -1
- package/dist/types/SpaceAdapter/LocalStorage.d.ts.map +1 -1
- package/dist/types/SpaceAdapter/RemoteStorage.d.ts.map +1 -1
- package/dist/types/SpaceAdapter/SessionStorage.d.ts.map +1 -1
- package/dist/types/SpaceAdapter/types.d.ts.map +1 -1
- package/dist/types/browser.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/Debug.ts", "../src/DOM.ts", "../src/Request.ts", "../src/FileSystem.ts", "../src/Form.ts", "../src/Platform.ts", "../src/Preload.ts", "../src/SpaceAdapter/types.ts", "../src/SpaceAdapter/LocalStorage.ts", "../src/SpaceAdapter/SessionStorage.ts", "../src/SpaceAdapter/IndexedDB.ts", "../src/SpaceAdapter/RemoteStorage.ts", "../src/Space.ts", "../src/Text.ts", "../src/Util.ts", "../src/browser.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * ==============================\n * Debug\n * ==============================\n */\n\n/**\n * Debug level enum\n */\nexport enum DebugLevel {\n
|
|
6
|
-
"/**\n * ==============================\n * DOM\n * ==============================\n */\n\nexport type DOMSelector = string | Element | Element[] | NodeList | NodeListOf<Element> | HTMLElement[] | DOM | null;\n\nexport type StyleProperties = Record<string, string | number>;\n\nexport interface DOMOffset {\n\ttop: number;\n\tleft: number;\n}\n\nexport type EventCallback = (event: Event) => void;\nexport type ElementCallback = (element: HTMLElement, index: number) => void;\n\n/**\n * Simple DOM manipulation functions\n */\nexport class DOM {\n\tpublic collection: HTMLElement[];\n\tpublic length: number;\n\n\tconstructor(selector: DOMSelector) {\n\t\tif (!selector) {\n\t\t\tthis.collection = [];\n\t\t} else if (typeof selector === 'string') {\n\t\t\tthis.collection = Array.from(document.querySelectorAll(selector)) as HTMLElement[];\n\t\t} else if (selector instanceof NodeList) {\n\t\t\tthis.collection = Array.from(selector) as HTMLElement[];\n\t\t} else if (selector instanceof DOM) {\n\t\t\tthis.collection = selector.collection;\n\t\t} else if (selector instanceof Element) {\n\t\t\tthis.collection = [selector as HTMLElement];\n\t\t} else if (Array.isArray(selector)) {\n\t\t\tthis.collection = selector as HTMLElement[];\n\t\t} else {\n\t\t\tthis.collection = [];\n\t\t}\n\n\t\tthis.length = this.collection.length;\n\t}\n\n\t/**\n\t * Hide elements by setting display to none\n\t */\n\thide(): this {\n\t\treturn this.style('display', 'none');\n\t}\n\n\t/**\n\t * Show elements by setting display property\n\t *\n\t * @param display - Display value (default: 'block')\n\t */\n\tshow(display: string = 'block'): this {\n\t\treturn this.style('display', display);\n\t}\n\n\t/**\n\t * Add a class to all elements\n\t *\n\t * @param newClass - Class name to add\n\t */\n\taddClass(newClass: string): this {\n\t\tthis.collection.forEach(element => element.classList.add(newClass));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a class or all classes from all elements\n\t *\n\t * @param oldClass - Class name to remove (if omitted, removes all classes)\n\t */\n\tremoveClass(oldClass?: string): this {\n\t\tthis.collection.forEach(element => {\n\t\t\tif (!oldClass) {\n\t\t\t\telement.className = '';\n\t\t\t} else {\n\t\t\t\telement.classList.remove(oldClass);\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Toggle one or more classes on all elements\n\t *\n\t * @param classes - Space-separated class names to toggle\n\t */\n\ttoggleClass(classes: string): this {\n\t\tconst classList = classes.split(' ');\n\n\t\tthis.collection.forEach(element => {\n\t\t\tclassList.forEach(c => element.classList.toggle(c));\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Check if all elements have a given class\n\t *\n\t * @param classToCheck - Class name to check\n\t */\n\thasClass(classToCheck: string): boolean {\n\t\treturn this.collection.every(element => element.classList.contains(classToCheck));\n\t}\n\n\t/**\n\t * Get or set the value of form elements\n\t */\n\tvalue(value: string | number): this;\n\tvalue(): string | undefined;\n\tvalue(value?: string | number): this | string | undefined {\n\t\tif (value !== undefined) {\n\t\t\tconst valueString = String(value);\n\t\t\tfor (const element of this.collection) {\n\t\t\t\tif (\n\t\t\t\t\telement instanceof HTMLInputElement ||\n\t\t\t\t\telement instanceof HTMLTextAreaElement ||\n\t\t\t\t\telement instanceof HTMLSelectElement ||\n\t\t\t\t\telement instanceof HTMLButtonElement ||\n\t\t\t\t\telement instanceof HTMLOptionElement\n\t\t\t\t) {\n\t\t\t\t\telement.value = valueString;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tif (this.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst first = this.collection[0];\n\n\t\tif (\n\t\t\tfirst instanceof HTMLInputElement ||\n\t\t\tfirst instanceof HTMLTextAreaElement ||\n\t\t\tfirst instanceof HTMLSelectElement ||\n\t\t\tfirst instanceof HTMLButtonElement ||\n\t\t\tfirst instanceof HTMLOptionElement\n\t\t) {\n\t\t\treturn first.value;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Focus the first element in the collection\n\t */\n\tfocus(): this {\n\t\tif (this.length > 0) {\n\t\t\tthis.collection[0].focus();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Blur (unfocus) the first element in the collection\n\t */\n\tblur(): this {\n\t\tif (this.length > 0) {\n\t\t\tthis.collection[0].blur();\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Attach a click event handler\n\t */\n\tclick(callback: EventCallback): this {\n\t\treturn this.on('click', callback);\n\t}\n\n\t/**\n\t * Attach a keyup event handler\n\t */\n\tkeyup(callback: EventCallback): this {\n\t\treturn this.on('keyup', callback);\n\t}\n\n\t/**\n\t * Attach a keydown event handler\n\t */\n\tkeydown(callback: EventCallback): this {\n\t\treturn this.on('keydown', callback);\n\t}\n\n\t/**\n\t * Attach a submit event handler\n\t */\n\tsubmit(callback: EventCallback): this {\n\t\treturn this.on('submit', callback);\n\t}\n\n\t/**\n\t * Attach a change event handler\n\t */\n\tchange(callback: EventCallback): this {\n\t\treturn this.on('change', callback);\n\t}\n\n\t/**\n\t * Attach a scroll event handler\n\t */\n\tscroll(callback: EventCallback): this {\n\t\treturn this.on('scroll', callback);\n\t}\n\n\t/**\n\t * Attach an input event handler\n\t */\n\tinput(callback: EventCallback): this {\n\t\treturn this.on('input', callback);\n\t}\n\n\t/**\n\t * Attach event handlers to elements\n\t *\n\t * @param eventNames - Space-separated event names\n\t * @param targetOrCallback - Either a selector for delegation or a callback\n\t * @param callback - Callback function (required if using delegation)\n\t */\n\ton(eventNames: string, targetOrCallback: string | EventCallback, callback?: EventCallback): this {\n\t\tconst events = eventNames.split(' ');\n\t\tconst isDelegation = typeof targetOrCallback === 'string';\n\t\tconst callbackFunction = isDelegation ? callback : (targetOrCallback as EventCallback);\n\t\tconst selector = isDelegation ? (targetOrCallback as string) : null;\n\n\t\tif (!callbackFunction) {\n\t\t\treturn this;\n\t\t}\n\n\t\tthis.collection.forEach(element => {\n\t\t\tevents.forEach(eventName => {\n\t\t\t\telement.addEventListener(eventName, (e) => {\n\t\t\t\t\tif (isDelegation && selector) {\n\t\t\t\t\t\tconst target = e.target;\n\t\t\t\t\t\tif (target instanceof Element) {\n\t\t\t\t\t\t\tconst match = target.closest(selector);\n\n\t\t\t\t\t\t\tif (match && element.contains(match)) {\n\t\t\t\t\t\t\t\tcallbackFunction.call(match, e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcallbackFunction.call(element, e);\n\t\t\t\t\t}\n\t\t\t\t}, false);\n\t\t\t});\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove event handlers from elements\n\t *\n\t * @param eventNames - Space-separated event names\n\t * @param callback - Callback function to remove\n\t */\n\toff(eventNames: string, callback: EventCallback): this {\n\t\tconst events = eventNames.split(' ');\n\n\t\tthis.collection.forEach(element => {\n\t\t\tevents.forEach(eventName => {\n\t\t\t\telement.removeEventListener(eventName, callback);\n\t\t\t});\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Trigger events on elements\n\t *\n\t * @param eventNames - Space-separated event names\n\t * @param detail - Custom event detail data\n\t */\n\ttrigger(eventNames: string, detail?: unknown): this {\n\t\tconst events = eventNames.split(' ');\n\n\t\tthis.collection.forEach(element => {\n\t\t\tevents.forEach(eventName => {\n\t\t\t\tconst customEvent = detail !== undefined\n\t\t\t\t\t? new CustomEvent(eventName, { detail, bubbles: true, cancelable: true })\n\t\t\t\t\t: new Event(eventName, { bubbles: true, cancelable: true });\n\n\t\t\t\telement.dispatchEvent(customEvent);\n\t\t\t});\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Filter elements by a selector\n\t *\n\t * @param selector - CSS selector to match\n\t */\n\tfilter(selector: string): DOM {\n\t\treturn new DOM(this.collection.filter(element => element.matches(selector)));\n\t}\n\n\t/**\n\t * Check if the collection contains any elements\n\t */\n\texists(): boolean {\n\t\treturn this.length > 0;\n\t}\n\n\t/**\n\t * Get or set data attributes\n\t *\n\t * @param name - Data attribute name (without 'data-' prefix)\n\t * @param value - Value to set (if omitted, returns current value)\n\t */\n\tdata(name: string): string | undefined;\n\tdata(name: string, value: string): this;\n\tdata(name: string, value?: string): this | string | undefined {\n\t\tif (value !== undefined) {\n\t\t\tthis.collection.forEach(element => element.dataset[name] = value);\n\t\t\treturn this;\n\t\t}\n\n\t\treturn this.length > 0 ? this.collection[0].dataset[name] : undefined;\n\t}\n\n\t/**\n\t * Remove a data attribute from all elements\n\t *\n\t * @param name - Data attribute name to remove\n\t */\n\tremoveData(name: string): this {\n\t\tthis.collection.forEach(element => delete element.dataset[name]);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get or set text content\n\t */\n\ttext(value: string | number): this;\n\ttext(): string | undefined;\n\ttext(value?: string | number): this | string | undefined {\n\t\tif (value !== undefined) {\n\t\t\tconst valueString = String(value);\n\n\t\t\tfor (const element of this.collection) {\n\t\t\t\telement.textContent = valueString;\n\t\t\t}\n\n\t\t\treturn this;\n\t\t}\n\n\t\tif (this.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.collection[0].textContent || '';\n\t}\n\n\t/**\n\t * Get or set HTML content\n\t */\n\thtml(value: string | number): this;\n\thtml(): string | undefined;\n\thtml(value?: string | number): this | string | undefined {\n\t\tif (value !== undefined) {\n\t\t\tconst valueString = String(value);\n\n\t\t\tfor (const element of this.collection) {\n\t\t\t\telement.innerHTML = valueString;\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif (this.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.collection[0].innerHTML;\n\t}\n\n\t/**\n\t * Append content to the end of each element\n\t *\n\t * @param content - HTML string or Element to append\n\t */\n\tappend(content: string | Element): this {\n\t\tthis.collection.forEach((element, index) => {\n\t\t\tif (typeof content === 'string') {\n\t\t\t\telement.insertAdjacentHTML('beforeend', content);\n\t\t\t} else {\n\t\t\t\t// Clone if not the first iteration to allow appending one element to multiple parents\n\t\t\t\tconst node = (index === 0) ? content : content.cloneNode(true);\n\t\t\t\telement.appendChild(node as Node);\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Prepend content to the beginning of each element\n\t *\n\t * @param content - HTML string or Element to prepend\n\t */\n\tprepend(content: string | Element): this {\n\t\tthis.collection.forEach((element, index) => {\n\t\t\tif (typeof content === 'string') {\n\t\t\t\telement.insertAdjacentHTML('afterbegin', content);\n\t\t\t} else {\n\t\t\t\tconst node = (index === 0) ? content : content.cloneNode(true);\n\t\t\t\telement.prepend(node as Node);\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Iterate over each element in the collection\n\t *\n\t * @param callback - Function to call for each element\n\t */\n\teach(callback: ElementCallback): this {\n\t\tthis.collection.forEach((element, i) => callback(element, i));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get an element by index\n\t *\n\t * @param index - Zero-based index\n\t */\n\tget(index: number): HTMLElement | undefined {\n\t\treturn this.collection[index];\n\t}\n\n\t/**\n\t * Get the first element wrapped in a new DOM instance\n\t */\n\tfirst(): DOM {\n\t\treturn new DOM(this.collection[0] ?? null);\n\t}\n\n\t/**\n\t * Get the last element wrapped in a new DOM instance\n\t */\n\tlast(): DOM {\n\t\treturn new DOM(this.collection[this.collection.length - 1] ?? null);\n\t}\n\n\t/**\n\t * Get element at index wrapped in a new DOM instance\n\t *\n\t * @param index - Zero-based index (negative counts from end)\n\t */\n\teq(index: number): DOM {\n\t\tconst actualIndex = index < 0 ? this.collection.length + index : index;\n\t\treturn new DOM(this.collection[actualIndex] ?? null);\n\t}\n\n\t/**\n\t * Check if any element in the collection is visible\n\t */\n\tisVisible(): boolean {\n\t\treturn this.collection.some(element =>\n\t\t\telement.style.display !== 'none' && element.offsetWidth > 0 && element.offsetHeight > 0\n\t\t);\n\t}\n\n\t/**\n\t * Get the parent elements of all elements in the collection\n\t */\n\tparent(): DOM {\n\t\tconst parents = new Set<HTMLElement>();\n\n\t\tthis.collection.forEach(element => {\n\t\t\tif (element.parentElement) {\n\t\t\t\tparents.add(element.parentElement);\n\t\t\t}\n\t\t});\n\n\t\treturn new DOM(Array.from(parents));\n\t}\n\n\t/**\n\t * Get all parent/ancestor elements up to the document\n\t */\n\tparents(): DOM {\n\t\tconst ancestors = new Set<HTMLElement>();\n\n\t\tthis.collection.forEach(element => {\n\t\t\tlet parent = element.parentElement;\n\t\t\twhile (parent) {\n\t\t\t\tancestors.add(parent);\n\t\t\t\tparent = parent.parentElement;\n\t\t\t}\n\t\t});\n\n\t\treturn new DOM(Array.from(ancestors));\n\t}\n\n\t/**\n\t * Find descendant elements matching a selector\n\t *\n\t * @param selector - CSS selector\n\t */\n\tfind(selector: string): DOM {\n\t\tconst found = new Set<HTMLElement>();\n\n\t\tfor (const element of this.collection) {\n\t\t\tconst results = element.querySelectorAll(selector);\n\n\t\t\tfor (const result of results) {\n\t\t\t\tfound.add(result as HTMLElement);\n\t\t\t}\n\t\t}\n\n\t\treturn new DOM(Array.from(found));\n\t}\n\n\t/**\n\t * Get the offset position of the first element\n\t */\n\toffset(): DOMOffset | undefined {\n\t\tif (this.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst rect = this.collection[0].getBoundingClientRect();\n\n\t\treturn {\n\t\t\ttop: rect.top + window.scrollY,\n\t\t\tleft: rect.left + window.scrollX\n\t\t};\n\t}\n\n\t/**\n\t * Get the width of the first element\n\t */\n\twidth(): number {\n\t\tif (this.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this.collection[0].getBoundingClientRect().width;\n\t}\n\n\t/**\n\t * Get the height of the first element\n\t */\n\theight(): number {\n\t\tif (this.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this.collection[0].getBoundingClientRect().height;\n\t}\n\n\t/**\n\t * Get the closest ancestor matching a selector\n\t *\n\t * @param selector - CSS selector\n\t */\n\tclosest(selector: string): DOM {\n\t\tconst found = new Set<HTMLElement>();\n\n\t\tthis.collection.forEach(element => {\n\t\t\tconst match = element.closest(selector);\n\n\t\t\tif (match) {\n\t\t\t\tfound.add(match as HTMLElement);\n\t\t\t}\n\t\t});\n\n\t\treturn new DOM(Array.from(found));\n\t}\n\n\t/**\n\t * Get or set an attribute\n\t *\n\t * @param attr - Attribute name\n\t * @param value - Value to set (if omitted, returns current value)\n\t */\n\tattribute(attr: string): string | null | undefined;\n\tattribute(attr: string, value: string | number): this;\n\tattribute(attr: string, value?: string | number): this | string | null | undefined {\n\t\tif (value !== undefined) {\n\t\t\tthis.collection.forEach(element => element.setAttribute(attr, String(value)));\n\t\t\treturn this;\n\t\t}\n\n\t\treturn this.length > 0 ? this.collection[0].getAttribute(attr) : undefined;\n\t}\n\n\t/**\n\t * Remove an attribute from all elements\n\t *\n\t * @param attr - Attribute name to remove\n\t */\n\tremoveAttribute(attr: string): this {\n\t\tthis.collection.forEach(element => element.removeAttribute(attr));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Check if all elements have a given attribute\n\t *\n\t * @param attribute - Attribute name\n\t */\n\thasAttribute(attribute: string): boolean {\n\t\treturn this.collection.every(element => element.hasAttribute(attribute));\n\t}\n\n\t/**\n\t * Insert HTML after each element\n\t *\n\t * @param content - HTML string to insert\n\t */\n\tafter(content: string): this {\n\t\tthis.collection.forEach(element => element.insertAdjacentHTML('afterend', content));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Insert HTML before each element\n\t *\n\t * @param content - HTML string to insert\n\t */\n\tbefore(content: string): this {\n\t\tthis.collection.forEach(element => element.insertAdjacentHTML('beforebegin', content));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get or set CSS styles\n\t */\n\tstyle(prop: string): string;\n\tstyle(prop: StyleProperties): this;\n\tstyle(prop: string, value: string): this;\n\tstyle(properties: string | StyleProperties, value?: string): this | string {\n\t\tif (typeof properties === 'string' && value === undefined) {\n\t\t\treturn this.length > 0 ? this.collection[0].style.getPropertyValue(properties) : '';\n\t\t}\n\n\t\tthis.collection.forEach(element => {\n\t\t\tif (typeof properties === 'string' && value !== undefined) {\n\t\t\t\telement.style.setProperty(properties, value);\n\t\t\t} else if (typeof properties === 'object') {\n\t\t\t\tObject.entries(properties).forEach(([k, v]) => {\n\t\t\t\t\telement.style.setProperty(k, String(v));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Animate elements using the Web Animations API\n\t *\n\t * @param keyframes - Animation keyframes\n\t * @param options - Animation options\n\t */\n\tanimate(keyframes: Keyframe[] | PropertyIndexedKeyframes, options: number | KeyframeAnimationOptions): this {\n\t\tthis.collection.forEach(element => element.animate(keyframes, options));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Fade elements in\n\t *\n\t * @param duration - Animation duration in ms\n\t * @param callback - Function to call after animation completes\n\t */\n\tfadeIn(duration: number = 400, callback?: () => void): this {\n\t\tthis.collection.forEach((element, index) => {\n\t\t\tif (getComputedStyle(element).display === 'none') {\n\t\t\t\telement.style.display = 'block';\n\t\t\t}\n\n\t\t\tconst animation = element.animate([{ opacity: 0 }, { opacity: 1 }], {\n\t\t\t\tduration: duration,\n\t\t\t\tfill: 'forwards',\n\t\t\t});\n\n\t\t\t// Trigger callback only once after the last element finishes\n\t\t\tif (callback && index === this.collection.length - 1) {\n\t\t\t\tanimation.onfinish = () => callback();\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Fade elements out\n\t *\n\t * @param duration - Animation duration in ms\n\t * @param callback - Function to call after animation completes\n\t */\n\tfadeOut(duration: number = 400, callback?: () => void): this {\n\t\tthis.collection.forEach((element, index) => {\n\t\t\tconst animation = element.animate([{ opacity: 1 }, { opacity: 0 }], {\n\t\t\t\tduration: duration,\n\t\t\t\tfill: 'forwards',\n\t\t\t});\n\n\t\t\tanimation.onfinish = () => {\n\t\t\t\telement.style.display = 'none';\n\t\t\t\tif (callback && index === this.collection.length - 1) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Check if all elements match a selector\n\t *\n\t * @param selector - CSS selector\n\t */\n\tmatches(selector: string): boolean {\n\t\tif (this.length === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.collection.every(element => element.matches(selector));\n\t}\n\n\t/**\n\t * Remove all elements from the DOM\n\t */\n\tremove(): this {\n\t\tthis.collection.forEach(element => element.remove());\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove all child elements\n\t */\n\tempty(): this {\n\t\tthis.collection.forEach(element => {\n\t\t\telement.innerHTML = '';\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Clone all elements in the collection\n\t *\n\t * @param deep - Whether to clone child nodes (default: true)\n\t */\n\tclone(deep: boolean = true): DOM {\n\t\tconst clones = this.collection.map(element => element.cloneNode(deep) as HTMLElement);\n\t\treturn new DOM(clones);\n\t}\n\n\t/**\n\t * Replace elements with new content\n\t *\n\t * @param newContent - HTML string or Element to replace with\n\t */\n\treplaceWith(newContent: string | Element): this {\n\t\tfor (let i = this.collection.length - 1; i >= 0; i--) {\n\t\t\tconst element = this.collection[i];\n\n\t\t\tif (typeof newContent === 'string') {\n\t\t\t\telement.outerHTML = newContent;\n\t\t\t} else {\n\t\t\t\tconst nodeToInsert = (i === 0) ? newContent : newContent.cloneNode(true);\n\t\t\t\telement.replaceWith(nodeToInsert);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Reset form elements\n\t */\n\treset(): this {\n\t\tthis.collection.forEach(element => {\n\t\t\tif (element instanceof HTMLFormElement) {\n\t\t\t\telement.reset();\n\t\t\t}\n\t\t});\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get or set a DOM property\n\t *\n\t * @param name - Property name\n\t * @param value - Value to set (if omitted, returns current value)\n\t */\n\tproperty<K extends keyof HTMLElement>(name: K, value: HTMLElement[K]): this;\n\tproperty<K extends keyof HTMLElement>(name: K): HTMLElement[K] | undefined;\n\tproperty<K extends keyof HTMLElement>(name: K, value?: HTMLElement[K]): this | HTMLElement[K] | undefined {\n\t\tif (value !== undefined) {\n\t\t\tthis.collection.forEach(element => {\n\t\t\t\t(element as HTMLElement)[name] = value;\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tif (this.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.collection[0][name];\n\t}\n\n\t/**\n\t * Get sibling elements\n\t */\n\tsiblings(): DOM {\n\t\tconst siblings = new Set<HTMLElement>();\n\n\t\tthis.collection.forEach(element => {\n\t\t\tif (element.parentElement) {\n\t\t\t\tArray.from(element.parentElement.children).forEach(sibling => {\n\t\t\t\t\tif (sibling !== element && sibling instanceof HTMLElement) {\n\t\t\t\t\t\tsiblings.add(sibling);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\treturn new DOM(Array.from(siblings));\n\t}\n\n\t/**\n\t * Get the next sibling element\n\t */\n\tnext(): DOM {\n\t\tconst nexts = new Set<HTMLElement>();\n\n\t\tthis.collection.forEach(element => {\n\t\t\tconst next = element.nextElementSibling;\n\t\t\tif (next instanceof HTMLElement) {\n\t\t\t\tnexts.add(next);\n\t\t\t}\n\t\t});\n\n\t\treturn new DOM(Array.from(nexts));\n\t}\n\n\t/**\n\t * Get the previous sibling element\n\t */\n\tprev(): DOM {\n\t\tconst prevs = new Set<HTMLElement>();\n\n\t\tthis.collection.forEach(element => {\n\t\t\tconst prev = element.previousElementSibling;\n\t\t\tif (prev instanceof HTMLElement) {\n\t\t\t\tprevs.add(prev);\n\t\t\t}\n\t\t});\n\n\t\treturn new DOM(Array.from(prevs));\n\t}\n\n\t/**\n\t * Get all child elements\n\t */\n\tchildren(): DOM {\n\t\tconst allChildren = new Set<HTMLElement>();\n\n\t\tthis.collection.forEach(element => {\n\t\t\tArray.from(element.children).forEach(child => {\n\t\t\t\tif (child instanceof HTMLElement) {\n\t\t\t\t\tallChildren.add(child);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn new DOM(Array.from(allChildren));\n\t}\n\n\t/**\n\t * Scroll element into view\n\t *\n\t * @param options - Scroll options\n\t */\n\tscrollIntoView(options?: ScrollIntoViewOptions): this {\n\t\tif (this.length > 0) {\n\t\t\tthis.collection[0].scrollIntoView(options);\n\t\t}\n\t\treturn this;\n\t}\n}\n\n/**\n * Create a new DOM instance\n *\n * @param selector - CSS selector, Element, or collection\n */\nexport function $_(selector: DOMSelector): DOM {\n\treturn new DOM(selector);\n}\n\n/**\n * Execute a callback when the DOM is ready\n *\n * @param callback - Function to execute\n */\nexport function $_ready(callback: () => void): void {\n\tif (document.readyState === 'loading') {\n\t\tdocument.addEventListener('DOMContentLoaded', callback);\n\t} else {\n\t\tcallback();\n\t}\n}\n\n/**\n * Create a new element\n *\n * @param tagName - HTML tag name\n * @param attributes - Optional attributes to set\n */\nexport function $_create<K extends keyof HTMLElementTagNameMap>(\n\ttagName: K,\n\tattributes?: Record<string, string>\n): DOM {\n\tconst element = document.createElement(tagName);\n\n\tif (attributes) {\n\t\tObject.entries(attributes).forEach(([key, value]) => {\n\t\t\telement.setAttribute(key, value);\n\t\t});\n\t}\n\n\treturn new DOM(element);\n}\n",
|
|
7
|
-
"/**\n * ==============================\n * Request\n * ==============================\n */\n\nexport type RequestData = Record<string, unknown> | FormData;\n\nexport interface RequestOptions extends Omit<RequestInit, 'body' | 'method'> {\n\theaders?: Record<string, string>;\n\ttimeout?: number; // Timeout in milliseconds\n}\n\n/**\n * Error thrown when a request fails\n */\nexport class RequestError extends Error {\n\tpublic status: number;\n\tpublic statusText: string;\n\tpublic response: Response;\n\n\tconstructor(response: Response, message?: string) {\n\t\tsuper(message || `Request failed: ${response.status} ${response.statusText}`);\n\t\tthis.name = 'RequestError';\n\t\tthis.status = response.status;\n\t\tthis.statusText = response.statusText;\n\t\tthis.response = response;\n\t}\n}\n\n/**\n * Error thrown when a request times out\n */\nexport class RequestTimeoutError extends Error {\n\tconstructor(url: string, timeout: number) {\n\t\tsuper(`Request to \"${url}\" timed out after ${timeout}ms`);\n\t\tthis.name = 'RequestTimeoutError';\n\t}\n}\n\nexport class Request {\n\t/**\n\t * Serialize data to URL query string\n\t * Handles nested objects and arrays\n\t *\n\t * @param data - Data to serialize\n\t * @param prefix - Key prefix for nested objects\n\t */\n\tstatic serialize(data: RequestData, prefix?: string): string {\n\t\tif (data instanceof FormData) {\n\t\t\tconst params = new URLSearchParams();\n\t\t\tdata.forEach((value, key) => {\n\t\t\t\tif (typeof value === 'string') {\n\t\t\t\t\tparams.append(key, value);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn params.toString();\n\t\t}\n\n\t\tconst params: string[] = [];\n\n\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\tif (value === undefined || value === null) continue;\n\n\t\t\tconst paramKey = prefix ? `${prefix}[${key}]` : key;\n\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tvalue.forEach((item, index) => {\n\t\t\t\t\tif (typeof item === 'object' && item !== null) {\n\t\t\t\t\t\tparams.push(Request.serialize(item as Record<string, unknown>, `${paramKey}[${index}]`));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tparams.push(`${encodeURIComponent(paramKey)}[]=${encodeURIComponent(String(item))}`);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else if (typeof value === 'object') {\n\t\t\t\tparams.push(Request.serialize(value as Record<string, unknown>, paramKey));\n\t\t\t} else {\n\t\t\t\tparams.push(`${encodeURIComponent(paramKey)}=${encodeURIComponent(String(value))}`);\n\t\t\t}\n\t\t}\n\n\t\treturn params.filter(Boolean).join('&');\n\t}\n\n\t/**\n\t * Parse a URL safely\n\t *\n\t * @param url - URL to parse\n\t */\n\tprivate static parseUrl(url: string): URL {\n\t\ttry {\n\t\t\treturn new URL(url);\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\treturn new URL(url, window.location.origin);\n\t\t\t} catch (e) {\n\t\t\t\tthrow new Error(`Invalid URL: \"${url}\"`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Create an AbortController with timeout\n\t *\n\t * @param timeout - Timeout in milliseconds\n\t * @param url - URL for error message\n\t */\n\tprivate static createTimeoutController(timeout: number | undefined, url: string): { controller: AbortController; timeoutId?: ReturnType<typeof setTimeout> } {\n\t\tconst controller = new AbortController();\n\n\t\tif (!timeout) {\n\t\t\treturn { controller };\n\t\t}\n\n\t\tconst timeoutId = setTimeout(() => {\n\t\t\tcontroller.abort(new RequestTimeoutError(url, timeout));\n\t\t}, timeout);\n\n\t\treturn { controller, timeoutId };\n\t}\n\n\tprivate static async send(\n\t\tmethod: string,\n\t\turl: string,\n\t\tdata: RequestData = {},\n\t\toptions: RequestOptions = {}\n\t): Promise<Response> {\n\t\tconst { timeout, ...fetchOptions } = options;\n\t\tconst urlObj = Request.parseUrl(url);\n\t\tlet body: BodyInit | undefined = undefined;\n\t\tconst headers = { ...fetchOptions.headers };\n\n\t\tif (['GET', 'DELETE', 'HEAD'].includes(method.toUpperCase())) {\n\t\t\tif (data && typeof data === 'object' && !(data instanceof FormData)) {\n\t\t\t\tObject.entries(data).forEach(([key, val]) => {\n\t\t\t\t\tif (val !== undefined && val !== null) {\n\t\t\t\t\t\turlObj.searchParams.append(key, String(val));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tconst contentType = headers['Content-Type'] || headers['content-type'];\n\n\t\t\tif (data instanceof FormData) {\n\t\t\t\t// Browser automatically sets Content-Type to multipart/form-data with boundary\n // Removing both cases to let the browser do its job\n\t\t\t\tdelete headers['Content-Type'];\n\t\t\t\tdelete headers['content-type'];\n\t\t\t\tbody = data;\n\t\t\t} else if (contentType === 'application/json') {\n\t\t\t\tbody = JSON.stringify(data);\n\t\t\t} else {\n\t\t\t\tif (!contentType) {\n\t\t\t\t\theaders['Content-Type'] = 'application/x-www-form-urlencoded';\n\t\t\t\t}\n\n\t\t\t\tconst params = new URLSearchParams();\n\t\t\t\tObject.entries(data).forEach(([k, v]) => params.append(k, String(v)));\n\t\t\t\tbody = params;\n\t\t\t}\n\t\t}\n\n\t\tconst { controller, timeoutId } = Request.createTimeoutController(timeout, url);\n\n\t\ttry {\n\t\t\tconst response = await fetch(urlObj.toString(), {\n\t\t\t\t...fetchOptions,\n\t\t\t\tmethod,\n\t\t\t\theaders,\n\t\t\t\tbody,\n\t\t\t\tsignal: controller.signal\n\t\t\t});\n\n\t\t\treturn response;\n\t\t} finally {\n\t\t\tif (timeoutId) {\n\t\t\t\tclearTimeout(timeoutId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Make a GET request\n\t *\n\t * @param url - Request URL\n\t * @param data - Query parameters\n\t * @param options - Request options\n\t */\n\tstatic get(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Response> {\n\t\treturn Request.send('GET', url, data, options);\n\t}\n\n\t/**\n\t * Make a POST request\n\t *\n\t * @param url - Request URL\n\t * @param data - Request body\n\t * @param options - Request options\n\t */\n\tstatic post(url: string, data: RequestData, options: RequestOptions = {}): Promise<Response> {\n\t\treturn Request.send('POST', url, data, options);\n\t}\n\n\t/**\n\t * Make a PUT request\n\t *\n\t * @param url - Request URL\n\t * @param data - Request body\n\t * @param options - Request options\n\t */\n\tstatic put(url: string, data: RequestData, options: RequestOptions = {}): Promise<Response> {\n\t\treturn Request.send('PUT', url, data, options);\n\t}\n\n\t/**\n\t * Make a PATCH request\n\t *\n\t * @param url - Request URL\n\t * @param data - Request body\n\t * @param options - Request options\n\t */\n\tstatic patch(url: string, data: RequestData, options: RequestOptions = {}): Promise<Response> {\n\t\treturn Request.send('PATCH', url, data, options);\n\t}\n\n\t/**\n\t * Make a DELETE request\n\t *\n\t * @param url - Request URL\n\t * @param data - Query parameters\n\t * @param options - Request options\n\t */\n\tstatic delete(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Response> {\n\t\treturn Request.send('DELETE', url, data, options);\n\t}\n\n\t/**\n\t * Make a HEAD request\n\t *\n\t * @param url - Request URL\n\t * @param data - Query parameters\n\t * @param options - Request options\n\t */\n\tstatic head(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Response> {\n\t\treturn Request.send('HEAD', url, data, options);\n\t}\n\n\t/**\n\t * Make a GET request and parse JSON response\n\t *\n\t * @param url - Request URL\n\t * @param data - Query parameters\n\t * @param options - Request options\n\t * @throws {RequestError} If the response is not ok\n\t */\n\tstatic async json<T = unknown>(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<T> {\n\t\tconst response = await Request.get(url, data, options);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new RequestError(response);\n\t\t}\n\n\t\treturn response.json();\n\t}\n\n\t/**\n\t * Make a POST request with JSON body and parse JSON response\n\t *\n\t * @param url - Request URL\n\t * @param data - Request body\n\t * @param options - Request options\n\t * @throws {RequestError} If the response is not ok\n\t */\n\tstatic async postJson<T = unknown>(url: string, data: RequestData, options: RequestOptions = {}): Promise<T> {\n\t\tconst headers = { ...options.headers, 'Content-Type': 'application/json' };\n\t\tconst response = await Request.post(url, data, { ...options, headers });\n\n\t\tif (!response.ok) {\n\t\t\tthrow new RequestError(response);\n\t\t}\n\n\t\treturn response.json();\n\t}\n\n\t/**\n\t * Make a GET request and return as Blob\n\t *\n\t * @param url - Request URL\n\t * @param data - Query parameters\n\t * @param options - Request options\n\t * @throws {RequestError} If the response is not ok\n\t */\n\tstatic async blob(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Blob> {\n\t\tconst response = await Request.get(url, data, options);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new RequestError(response);\n\t\t}\n\n\t\treturn response.blob();\n\t}\n\n\t/**\n\t * Make a GET request and return as text\n\t *\n\t * @param url - Request URL\n\t * @param data - Query parameters\n\t * @param options - Request options\n\t * @throws {RequestError} If the response is not ok\n\t */\n\tstatic async text(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<string> {\n\t\tconst response = await Request.get(url, data, options);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new RequestError(response);\n\t\t}\n\n\t\treturn response.text();\n\t}\n\n\t/**\n\t * Make a GET request and return as ArrayBuffer\n\t *\n\t * @param url - Request URL\n\t * @param data - Query parameters\n\t * @param options - Request options\n\t * @throws {RequestError} If the response is not ok\n\t */\n\tstatic async arrayBuffer(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<ArrayBuffer> {\n\t\tconst response = await Request.get(url, data, options);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new RequestError(response);\n\t\t}\n\n\t\treturn response.arrayBuffer();\n\t}\n\n\t/**\n\t * Check if a URL exists (returns 2xx status)\n\t *\n\t * @param url - URL to check\n\t * @param options - Request options\n\t */\n\tstatic async exists(url: string, options: RequestOptions = {}): Promise<boolean> {\n\t\ttry {\n\t\t\tconst response = await Request.head(url, {}, options);\n\t\t\treturn response.ok;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n",
|
|
5
|
+
"/**\n * ==============================\n * Debug\n * ==============================\n */\n\n/**\n * Debug level enum\n */\nexport enum DebugLevel {\n NONE = 0,\n ERROR = 1,\n WARNING = 2,\n INFO = 3,\n DEBUG = 4,\n ALL = 5\n}\n\n/**\n * This class acts as a proxy for the console. It shares the same methods as the\n * web console but they are conditioned to a debug level.\n */\nexport class Debug {\n private static _level: DebugLevel = DebugLevel.NONE;\n\n /**\n * Get the current debug level\n */\n static get currentLevel(): DebugLevel {\n return this._level;\n }\n\n /**\n * Set or get the log level\n *\n * @param level - The debug level to use\n * @returns The current debug level\n */\n static level(level?: DebugLevel): DebugLevel {\n if (typeof level === 'number') {\n this._level = level;\n }\n return this._level;\n }\n\n /**\n * Set the debug level\n *\n * @param level - The debug level to set\n */\n static setLevel(level: DebugLevel): void {\n this._level = level;\n }\n\n /**\n * Check if a specific level is enabled\n *\n * @param level - The level to check\n */\n static isEnabled(level: DebugLevel): boolean {\n return this._level >= level;\n }\n\n /**\n * Log the given elements.\n * Logs will only be made if the level is set to DEBUG or above\n *\n * @param args - Arguments to log\n */\n static log(...args: unknown[]): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.log(...args);\n }\n }\n\n /**\n * Show a debugging log\n * Logs will only be made if the level is set DEBUG or above\n *\n * @param args - Arguments to log\n */\n static debug(...args: unknown[]): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.debug(...args);\n }\n }\n\n /**\n * Show an info log\n * Logs will only be made if the level is set to INFO or above\n *\n * @param args - Arguments to log\n */\n static info(...args: unknown[]): void {\n if (this._level >= DebugLevel.INFO) {\n console.info(...args);\n }\n }\n\n /**\n * Show an error log\n * Logs will only be made if the level is set to ERROR or above\n *\n * @param args - Arguments to log\n */\n static error(...args: unknown[]): void {\n if (this._level >= DebugLevel.ERROR) {\n console.error(...args);\n }\n }\n\n /**\n * Show a warning log\n * Logs will only be made if the level is set to WARNING or above\n *\n * @param args - Arguments to log\n */\n static warning(...args: unknown[]): void {\n if (this._level >= DebugLevel.WARNING) {\n console.warn(...args);\n }\n }\n\n /**\n * Alias for warning()\n *\n * @param args - Arguments to log\n */\n static warn(...args: unknown[]): void {\n this.warning(...args);\n }\n\n /**\n * Show data as a table\n * Table will only be made if the level is set to DEBUG or above\n *\n * @param data - Data to display as table\n * @param columns - Optional column names to include\n */\n static table(data: unknown, columns?: string[]): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.table(data, columns);\n }\n }\n\n /**\n * Start an indented group\n *\n * @param args - Group label arguments\n */\n static group(...args: unknown[]): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.group(...args);\n }\n }\n\n /**\n * Start an indented group collapsed by default\n *\n * @param args - Group label arguments\n */\n static groupCollapsed(...args: unknown[]): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.groupCollapsed(...args);\n }\n }\n\n /**\n * End a previously started group\n */\n static groupEnd(): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.groupEnd();\n }\n }\n\n /**\n * Start a timer\n * The timer will only start if the level is set to DEBUG or above\n *\n * @param label - Timer label\n */\n static time(label?: string): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.time(label);\n }\n }\n\n /**\n * Log the time a timer has been running for\n * The time will only be logged if the level is set to DEBUG or above\n *\n * @param label - Timer label\n * @param args - Additional arguments to log\n */\n static timeLog(label?: string, ...args: unknown[]): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.timeLog(label, ...args);\n }\n }\n\n /**\n * End a timer\n * The timer will only be available if the level is set to DEBUG or above\n *\n * @param label - Timer label\n */\n static timeEnd(label?: string): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.timeEnd(label);\n }\n }\n\n /**\n * Show the stack trace\n * The stack trace will only be available if the level is set to DEBUG or above\n *\n * @param args - Arguments to log with trace\n */\n static trace(...args: unknown[]): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.trace(...args);\n }\n }\n\n /**\n * Log a message if a condition is false\n * Only logs if the level is set to ERROR or above\n *\n * @param condition - Condition to check\n * @param args - Arguments to log if condition is false\n */\n static assert(condition: boolean, ...args: unknown[]): void {\n if (this._level >= DebugLevel.ERROR) {\n console.assert(condition, ...args);\n }\n }\n\n /**\n * Clear the console\n * Only clears if the level is set to DEBUG or above\n */\n static clear(): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.clear();\n }\n }\n\n /**\n * Increment a counter with the given label\n * Only counts if the level is set to DEBUG or above\n *\n * @param label - Counter label\n */\n static count(label?: string): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.count(label);\n }\n }\n\n /**\n * Reset a counter with the given label\n * Only resets if the level is set to DEBUG or above\n *\n * @param label - Counter label\n */\n static countReset(label?: string): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.countReset(label);\n }\n }\n\n /**\n * Display an interactive listing of the properties of an object\n * Only displays if the level is set to DEBUG or above\n *\n * @param data - Object to display\n */\n static dir(data: unknown): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.dir(data);\n }\n }\n\n /**\n * Display XML/HTML element representation\n * Only displays if the level is set to DEBUG or above\n *\n * @param data - Element to display\n */\n static dirxml(data: unknown): void {\n if (this._level >= DebugLevel.DEBUG) {\n console.dirxml(data);\n }\n }\n\n /**\n * Create a formatted string with substitution values\n *\n * @param format - Format string\n * @param args - Substitution values\n */\n static format(format: string, ...args: unknown[]): string {\n let result = format;\n let argIndex = 0;\n\n result = result.replace(/%[sdioOcj%]/g, (match) => {\n if (match === '%%') return '%';\n if (argIndex >= args.length) return match;\n\n const arg = args[argIndex++];\n\n switch (match) {\n case '%s': return String(arg);\n case '%d':\n case '%i': return String(parseInt(String(arg), 10));\n case '%o':\n case '%O': return JSON.stringify(arg);\n case '%c': return ''; // CSS styling not supported in string format\n case '%j': return JSON.stringify(arg);\n default: return match;\n }\n });\n\n return result;\n }\n}\n",
|
|
6
|
+
"/**\n * ==============================\n * DOM\n * ==============================\n */\n\nexport type DOMSelector = string | Element | Element[] | NodeList | NodeListOf<Element> | HTMLElement[] | DOM | null;\n\nexport type StyleProperties = Record<string, string | number>;\n\nexport interface DOMOffset {\n top: number;\n left: number;\n}\n\nexport type EventCallback = (event: Event) => void;\nexport type ElementCallback = (element: HTMLElement, index: number) => void;\n\ninterface StoredHandler {\n selector: string | null;\n originalCallback: EventCallback;\n wrappedListener: EventListener;\n}\n\nconst eventHandlers = new WeakMap<Element, Map<string, StoredHandler[]>>();\n\n/**\n * Simple DOM manipulation functions\n */\nexport class DOM {\n public collection: HTMLElement[];\n public length: number;\n\n constructor(selector: DOMSelector) {\n if (!selector) {\n this.collection = [];\n } else if (typeof selector === 'string') {\n this.collection = Array.from(document.querySelectorAll(selector)) as HTMLElement[];\n } else if (selector instanceof NodeList) {\n this.collection = Array.from(selector) as HTMLElement[];\n } else if (selector instanceof DOM) {\n this.collection = selector.collection;\n } else if (selector instanceof Element) {\n this.collection = [selector as HTMLElement];\n } else if (Array.isArray(selector)) {\n this.collection = selector as HTMLElement[];\n } else {\n this.collection = [];\n }\n\n this.length = this.collection.length;\n }\n\n /**\n * Hide elements by setting display to none\n */\n hide(): this {\n return this.style('display', 'none');\n }\n\n /**\n * Show elements by setting display property\n *\n * @param display - Display value (default: 'block')\n */\n show(display: string = 'block'): this {\n return this.style('display', display);\n }\n\n /**\n * Add a class to all elements\n *\n * @param newClass - Class name to add\n */\n addClass(newClass: string): this {\n this.collection.forEach(element => element.classList.add(newClass));\n return this;\n }\n\n /**\n * Remove a class or all classes from all elements\n *\n * @param oldClass - Class name to remove (if omitted, removes all classes)\n */\n removeClass(oldClass?: string): this {\n this.collection.forEach(element => {\n if (!oldClass) {\n element.className = '';\n } else {\n element.classList.remove(oldClass);\n }\n });\n\n return this;\n }\n\n /**\n * Toggle one or more classes on all elements\n *\n * @param classes - Space-separated class names to toggle\n */\n toggleClass(classes: string): this {\n const classList = classes.split(' ');\n\n this.collection.forEach(element => {\n classList.forEach(c => element.classList.toggle(c));\n });\n\n return this;\n }\n\n /**\n * Check if all elements have a given class\n *\n * @param classToCheck - Class name to check\n */\n hasClass(classToCheck: string): boolean {\n return this.collection.every(element => element.classList.contains(classToCheck));\n }\n\n /**\n * Get or set the value of form elements\n */\n value(value: string | number): this;\n value(): string | undefined;\n value(value?: string | number): this | string | undefined {\n if (value !== undefined) {\n const valueString = String(value);\n for (const element of this.collection) {\n if (\n element instanceof HTMLInputElement ||\n element instanceof HTMLTextAreaElement ||\n element instanceof HTMLSelectElement ||\n element instanceof HTMLButtonElement ||\n element instanceof HTMLOptionElement\n ) {\n element.value = valueString;\n }\n }\n\n return this;\n }\n\n if (this.length === 0) {\n return undefined;\n }\n\n const first = this.collection[0];\n\n if (\n first instanceof HTMLInputElement ||\n first instanceof HTMLTextAreaElement ||\n first instanceof HTMLSelectElement ||\n first instanceof HTMLButtonElement ||\n first instanceof HTMLOptionElement\n ) {\n return first.value;\n }\n\n return undefined;\n }\n\n /**\n * Focus the first element in the collection\n */\n focus(): this {\n if (this.length > 0) {\n this.collection[0].focus();\n }\n\n return this;\n }\n\n /**\n * Blur (unfocus) the first element in the collection\n */\n blur(): this {\n if (this.length > 0) {\n this.collection[0].blur();\n }\n\n return this;\n }\n\n /**\n * Attach a click event handler\n */\n click(callback: EventCallback): this {\n return this.on('click', callback);\n }\n\n /**\n * Attach a keyup event handler\n */\n keyup(callback: EventCallback): this {\n return this.on('keyup', callback);\n }\n\n /**\n * Attach a keydown event handler\n */\n keydown(callback: EventCallback): this {\n return this.on('keydown', callback);\n }\n\n /**\n * Attach a submit event handler\n */\n submit(callback: EventCallback): this {\n return this.on('submit', callback);\n }\n\n /**\n * Attach a change event handler\n */\n change(callback: EventCallback): this {\n return this.on('change', callback);\n }\n\n /**\n * Attach a scroll event handler\n */\n scroll(callback: EventCallback): this {\n return this.on('scroll', callback);\n }\n\n /**\n * Attach an input event handler\n */\n input(callback: EventCallback): this {\n return this.on('input', callback);\n }\n\n /**\n * Attach event handlers to elements\n *\n * @param eventNames - Space-separated event names\n * @param targetOrCallback - Either a selector for delegation or a callback\n * @param callback - Callback function (required if using delegation)\n */\n on(eventNames: string, targetOrCallback: string | EventCallback, callback?: EventCallback): this {\n const events = eventNames.split(' ');\n const isDelegation = typeof targetOrCallback === 'string';\n const callbackFunction = isDelegation ? callback : (targetOrCallback as EventCallback);\n const selector = isDelegation ? (targetOrCallback as string) : null;\n\n if (!callbackFunction) {\n return this;\n }\n\n this.collection.forEach(element => {\n events.forEach(eventName => {\n const listener: EventListener = isDelegation && selector\n ? (e: Event) => {\n const target = e.target;\n if (target instanceof Element) {\n const match = target.closest(selector);\n if (match && element.contains(match)) {\n callbackFunction.call(match, e);\n }\n }\n }\n : callbackFunction;\n\n if (!eventHandlers.has(element)) {\n eventHandlers.set(element, new Map());\n }\n\n const elementHandlers = eventHandlers.get(element)!;\n\n\n if (!elementHandlers.has(eventName)) {\n elementHandlers.set(eventName, []);\n }\n\n elementHandlers.get(eventName)!.push({\n selector,\n originalCallback: callbackFunction,\n wrappedListener: listener\n });\n\n element.addEventListener(eventName, listener, false);\n });\n });\n\n return this;\n }\n\n /**\n * Remove event handlers from elements\n *\n * @param eventNames - Space-separated event names (optional - omit to remove all)\n * @param targetOrCallback - Either a selector for delegation or a callback (optional)\n * @param callback - Callback function (required if using delegation removal)\n */\n off(eventNames?: string, targetOrCallback?: string | EventCallback, callback?: EventCallback): this {\n this.collection.forEach(element => {\n const elementHandlers = eventHandlers.get(element);\n\n if (!elementHandlers) {\n return;\n }\n\n const events = eventNames ? eventNames.split(' ') : Array.from(elementHandlers.keys());\n const isDelegation = typeof targetOrCallback === 'string';\n const selector = isDelegation ? targetOrCallback : null;\n const callbackToRemove = isDelegation ? callback : (targetOrCallback as EventCallback | undefined);\n\n events.forEach(eventName => {\n const handlers = elementHandlers.get(eventName);\n\n if (!handlers) {\n return;\n }\n\n // Find all the handlers we need to remove\n const toRemove = handlers.filter(handler => {\n if (callbackToRemove && handler.originalCallback !== callbackToRemove) {\n return false;\n }\n\n if (selector !== undefined && handler.selector !== selector) {\n return false;\n }\n\n return true;\n });\n\n toRemove.forEach(handler => {\n element.removeEventListener(eventName, handler.wrappedListener);\n });\n\n const remaining = handlers.filter(handler => !toRemove.includes(handler));\n\n if (remaining.length > 0) {\n elementHandlers.set(eventName, remaining);\n } else {\n elementHandlers.delete(eventName);\n }\n });\n\n if (elementHandlers.size === 0) {\n eventHandlers.delete(element);\n }\n });\n\n return this;\n }\n\n /**\n * Trigger events on elements\n *\n * @param eventNames - Space-separated event names\n * @param detail - Custom event detail data\n */\n trigger(eventNames: string, detail?: unknown): this {\n const events = eventNames.split(' ');\n\n this.collection.forEach(element => {\n events.forEach(eventName => {\n const customEvent = detail !== undefined\n ? new CustomEvent(eventName, { detail, bubbles: true, cancelable: true })\n : new Event(eventName, { bubbles: true, cancelable: true });\n\n element.dispatchEvent(customEvent);\n });\n });\n\n return this;\n }\n\n /**\n * Filter elements by a selector\n *\n * @param selector - CSS selector to match\n */\n filter(selector: string): DOM {\n return new DOM(this.collection.filter(element => element.matches(selector)));\n }\n\n /**\n * Check if the collection contains any elements\n */\n exists(): boolean {\n return this.length > 0;\n }\n\n /**\n * Get or set data attributes\n *\n * @param name - Data attribute name (without 'data-' prefix)\n * @param value - Value to set (if omitted, returns current value)\n */\n data(name: string): string | undefined;\n data(name: string, value: string): this;\n data(name: string, value?: string): this | string | undefined {\n if (value !== undefined) {\n this.collection.forEach(element => element.dataset[name] = value);\n return this;\n }\n\n return this.length > 0 ? this.collection[0].dataset[name] : undefined;\n }\n\n /**\n * Remove a data attribute from all elements\n *\n * @param name - Data attribute name to remove\n */\n removeData(name: string): this {\n this.collection.forEach(element => delete element.dataset[name]);\n return this;\n }\n\n /**\n * Get or set text content\n */\n text(value: string | number): this;\n text(): string | undefined;\n text(value?: string | number): this | string | undefined {\n if (value !== undefined) {\n const valueString = String(value);\n\n for (const element of this.collection) {\n element.textContent = valueString;\n }\n\n return this;\n }\n\n if (this.length === 0) {\n return undefined;\n }\n\n return this.collection[0].textContent || '';\n }\n\n /**\n * Get or set HTML content\n */\n html(value: string | number): this;\n html(): string | undefined;\n html(value?: string | number): this | string | undefined {\n if (value !== undefined) {\n const valueString = String(value);\n\n for (const element of this.collection) {\n element.innerHTML = valueString;\n }\n return this;\n }\n\n if (this.length === 0) {\n return undefined;\n }\n\n return this.collection[0].innerHTML;\n }\n\n /**\n * Append content to the end of each element\n *\n * @param content - HTML string or Element to append\n */\n append(content: string | Element): this {\n this.collection.forEach((element, index) => {\n if (typeof content === 'string') {\n element.insertAdjacentHTML('beforeend', content);\n } else {\n // Clone if not the first iteration to allow appending one element to multiple parents\n const node = (index === 0) ? content : content.cloneNode(true);\n element.appendChild(node as Node);\n }\n });\n\n return this;\n }\n\n /**\n * Prepend content to the beginning of each element\n *\n * @param content - HTML string or Element to prepend\n */\n prepend(content: string | Element): this {\n this.collection.forEach((element, index) => {\n if (typeof content === 'string') {\n element.insertAdjacentHTML('afterbegin', content);\n } else {\n const node = (index === 0) ? content : content.cloneNode(true);\n element.prepend(node as Node);\n }\n });\n\n return this;\n }\n\n /**\n * Iterate over each element in the collection\n *\n * @param callback - Function to call for each element\n */\n each(callback: ElementCallback): this {\n this.collection.forEach((element, i) => callback(element, i));\n return this;\n }\n\n /**\n * Get an element by index\n *\n * @param index - Zero-based index\n */\n get(index: number): HTMLElement | undefined {\n return this.collection[index];\n }\n\n /**\n * Get the first element wrapped in a new DOM instance\n */\n first(): DOM {\n return new DOM(this.collection[0] ?? null);\n }\n\n /**\n * Get the last element wrapped in a new DOM instance\n */\n last(): DOM {\n return new DOM(this.collection[this.collection.length - 1] ?? null);\n }\n\n /**\n * Get element at index wrapped in a new DOM instance\n *\n * @param index - Zero-based index (negative counts from end)\n */\n eq(index: number): DOM {\n const actualIndex = index < 0 ? this.collection.length + index : index;\n return new DOM(this.collection[actualIndex] ?? null);\n }\n\n /**\n * Check if any element in the collection is visible\n */\n isVisible(): boolean {\n return this.collection.some(element =>\n element.style.display !== 'none' && element.offsetWidth > 0 && element.offsetHeight > 0\n );\n }\n\n /**\n * Get the parent elements of all elements in the collection\n */\n parent(): DOM {\n const parents = new Set<HTMLElement>();\n\n this.collection.forEach(element => {\n if (element.parentElement) {\n parents.add(element.parentElement);\n }\n });\n\n return new DOM(Array.from(parents));\n }\n\n /**\n * Get all parent/ancestor elements up to the document\n */\n parents(): DOM {\n const ancestors = new Set<HTMLElement>();\n\n this.collection.forEach(element => {\n let parent = element.parentElement;\n while (parent) {\n ancestors.add(parent);\n parent = parent.parentElement;\n }\n });\n\n return new DOM(Array.from(ancestors));\n }\n\n /**\n * Find descendant elements matching a selector\n *\n * @param selector - CSS selector\n */\n find(selector: string): DOM {\n const found = new Set<HTMLElement>();\n\n for (const element of this.collection) {\n const results = element.querySelectorAll(selector);\n\n for (const result of results) {\n found.add(result as HTMLElement);\n }\n }\n\n return new DOM(Array.from(found));\n }\n\n /**\n * Get the offset position of the first element\n */\n offset(): DOMOffset | undefined {\n if (this.length === 0) {\n return undefined;\n }\n\n const rect = this.collection[0].getBoundingClientRect();\n\n return {\n top: rect.top + window.scrollY,\n left: rect.left + window.scrollX\n };\n }\n\n /**\n * Get the width of the first element\n */\n width(): number {\n if (this.length === 0) {\n return 0;\n }\n\n return this.collection[0].getBoundingClientRect().width;\n }\n\n /**\n * Get the height of the first element\n */\n height(): number {\n if (this.length === 0) {\n return 0;\n }\n\n return this.collection[0].getBoundingClientRect().height;\n }\n\n /**\n * Get the closest ancestor matching a selector\n *\n * @param selector - CSS selector\n */\n closest(selector: string): DOM {\n const found = new Set<HTMLElement>();\n\n this.collection.forEach(element => {\n const match = element.closest(selector);\n\n if (match) {\n found.add(match as HTMLElement);\n }\n });\n\n return new DOM(Array.from(found));\n }\n\n /**\n * Get or set an attribute\n *\n * @param attr - Attribute name\n * @param value - Value to set (if omitted, returns current value)\n */\n attribute(attr: string): string | null | undefined;\n attribute(attr: string, value: string | number): this;\n attribute(attr: string, value?: string | number): this | string | null | undefined {\n if (value !== undefined) {\n this.collection.forEach(element => element.setAttribute(attr, String(value)));\n return this;\n }\n\n return this.length > 0 ? this.collection[0].getAttribute(attr) : undefined;\n }\n\n /**\n * Remove an attribute from all elements\n *\n * @param attr - Attribute name to remove\n */\n removeAttribute(attr: string): this {\n this.collection.forEach(element => element.removeAttribute(attr));\n return this;\n }\n\n /**\n * Check if all elements have a given attribute\n *\n * @param attribute - Attribute name\n */\n hasAttribute(attribute: string): boolean {\n return this.collection.every(element => element.hasAttribute(attribute));\n }\n\n /**\n * Insert HTML after each element\n *\n * @param content - HTML string to insert\n */\n after(content: string): this {\n this.collection.forEach(element => element.insertAdjacentHTML('afterend', content));\n return this;\n }\n\n /**\n * Insert HTML before each element\n *\n * @param content - HTML string to insert\n */\n before(content: string): this {\n this.collection.forEach(element => element.insertAdjacentHTML('beforebegin', content));\n return this;\n }\n\n /**\n * Get or set CSS styles\n */\n style(prop: string): string;\n style(prop: StyleProperties): this;\n style(prop: string, value: string): this;\n style(properties: string | StyleProperties, value?: string): this | string {\n if (typeof properties === 'string' && value === undefined) {\n return this.length > 0 ? this.collection[0].style.getPropertyValue(properties) : '';\n }\n\n this.collection.forEach(element => {\n if (typeof properties === 'string' && value !== undefined) {\n element.style.setProperty(properties, value);\n } else if (typeof properties === 'object') {\n Object.entries(properties).forEach(([k, v]) => {\n element.style.setProperty(k, String(v));\n });\n }\n });\n\n return this;\n }\n\n /**\n * Animate elements using the Web Animations API\n *\n * @param keyframes - Animation keyframes\n * @param options - Animation options\n */\n animate(keyframes: Keyframe[] | PropertyIndexedKeyframes, options: number | KeyframeAnimationOptions): this {\n this.collection.forEach(element => element.animate(keyframes, options));\n return this;\n }\n\n /**\n * Fade elements in\n *\n * @param duration - Animation duration in ms\n * @param callback - Function to call after animation completes\n */\n fadeIn(duration: number = 400, callback?: () => void): this {\n this.collection.forEach((element, index) => {\n if (getComputedStyle(element).display === 'none') {\n element.style.display = 'block';\n }\n\n const animation = element.animate([{ opacity: 0 }, { opacity: 1 }], {\n duration: duration,\n fill: 'forwards',\n });\n\n // Trigger callback only once after the last element finishes\n if (callback && index === this.collection.length - 1) {\n animation.onfinish = () => callback();\n }\n });\n\n return this;\n }\n\n /**\n * Fade elements out\n *\n * @param duration - Animation duration in ms\n * @param callback - Function to call after animation completes\n */\n fadeOut(duration: number = 400, callback?: () => void): this {\n this.collection.forEach((element, index) => {\n const animation = element.animate([{ opacity: 1 }, { opacity: 0 }], {\n duration: duration,\n fill: 'forwards',\n });\n\n animation.onfinish = () => {\n element.style.display = 'none';\n if (callback && index === this.collection.length - 1) {\n callback();\n }\n };\n });\n\n return this;\n }\n\n /**\n * Check if all elements match a selector\n *\n * @param selector - CSS selector\n */\n matches(selector: string): boolean {\n if (this.length === 0) {\n return false;\n }\n\n return this.collection.every(element => element.matches(selector));\n }\n\n /**\n * Remove all elements from the DOM\n */\n remove(): this {\n this.collection.forEach(element => element.remove());\n return this;\n }\n\n /**\n * Remove all child elements\n */\n empty(): this {\n this.collection.forEach(element => {\n element.innerHTML = '';\n });\n\n return this;\n }\n\n /**\n * Clone all elements in the collection\n *\n * @param deep - Whether to clone child nodes (default: true)\n */\n clone(deep: boolean = true): DOM {\n const clones = this.collection.map(element => element.cloneNode(deep) as HTMLElement);\n return new DOM(clones);\n }\n\n /**\n * Replace elements with new content\n *\n * @param newContent - HTML string or Element to replace with\n */\n replaceWith(newContent: string | Element): this {\n for (let i = this.collection.length - 1; i >= 0; i--) {\n const element = this.collection[i];\n\n if (typeof newContent === 'string') {\n element.outerHTML = newContent;\n } else {\n const nodeToInsert = (i === 0) ? newContent : newContent.cloneNode(true);\n element.replaceWith(nodeToInsert);\n }\n }\n\n return this;\n }\n\n /**\n * Reset form elements\n */\n reset(): this {\n this.collection.forEach(element => {\n if (element instanceof HTMLFormElement) {\n element.reset();\n }\n });\n\n return this;\n }\n\n /**\n * Get or set a DOM property\n *\n * @param name - Property name\n * @param value - Value to set (if omitted, returns current value)\n */\n property<K extends keyof HTMLElement>(name: K, value: HTMLElement[K]): this;\n property<K extends keyof HTMLElement>(name: K): HTMLElement[K] | undefined;\n property<K extends keyof HTMLElement>(name: K, value?: HTMLElement[K]): this | HTMLElement[K] | undefined {\n if (value !== undefined) {\n this.collection.forEach(element => {\n (element as HTMLElement)[name] = value;\n });\n return this;\n }\n\n if (this.length === 0) {\n return undefined;\n }\n\n return this.collection[0][name];\n }\n\n /**\n * Get sibling elements\n */\n siblings(): DOM {\n const siblings = new Set<HTMLElement>();\n\n this.collection.forEach(element => {\n if (element.parentElement) {\n Array.from(element.parentElement.children).forEach(sibling => {\n if (sibling !== element && sibling instanceof HTMLElement) {\n siblings.add(sibling);\n }\n });\n }\n });\n\n return new DOM(Array.from(siblings));\n }\n\n /**\n * Get the next sibling element\n */\n next(): DOM {\n const nexts = new Set<HTMLElement>();\n\n this.collection.forEach(element => {\n const next = element.nextElementSibling;\n if (next instanceof HTMLElement) {\n nexts.add(next);\n }\n });\n\n return new DOM(Array.from(nexts));\n }\n\n /**\n * Get the previous sibling element\n */\n prev(): DOM {\n const prevs = new Set<HTMLElement>();\n\n this.collection.forEach(element => {\n const prev = element.previousElementSibling;\n if (prev instanceof HTMLElement) {\n prevs.add(prev);\n }\n });\n\n return new DOM(Array.from(prevs));\n }\n\n /**\n * Get all child elements\n */\n children(): DOM {\n const allChildren = new Set<HTMLElement>();\n\n this.collection.forEach(element => {\n Array.from(element.children).forEach(child => {\n if (child instanceof HTMLElement) {\n allChildren.add(child);\n }\n });\n });\n\n return new DOM(Array.from(allChildren));\n }\n\n /**\n * Scroll element into view\n *\n * @param options - Scroll options\n */\n scrollIntoView(options?: ScrollIntoViewOptions): this {\n if (this.length > 0) {\n this.collection[0].scrollIntoView(options);\n }\n return this;\n }\n}\n\n/**\n * Create a new DOM instance\n *\n * @param selector - CSS selector, Element, or collection\n */\nexport function $_(selector: DOMSelector): DOM {\n return new DOM(selector);\n}\n\n/**\n * Execute a callback when the DOM is ready\n *\n * @param callback - Function to execute\n */\nexport function $_ready(callback: () => void): void {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', callback);\n } else {\n callback();\n }\n}\n\n/**\n * Create a new element\n *\n * @param tagName - HTML tag name\n * @param attributes - Optional attributes to set\n */\nexport function $_create<K extends keyof HTMLElementTagNameMap>(\n tagName: K,\n attributes?: Record<string, string>\n): DOM {\n const element = document.createElement(tagName);\n\n if (attributes) {\n Object.entries(attributes).forEach(([key, value]) => {\n element.setAttribute(key, value);\n });\n }\n\n return new DOM(element);\n}\n",
|
|
7
|
+
"/**\n * ==============================\n * Request\n * ==============================\n */\n\nexport type RequestData = Record<string, unknown> | FormData;\n\nexport interface RequestOptions extends Omit<RequestInit, 'body' | 'method'> {\n headers?: Record<string, string>;\n timeout?: number; // Timeout in milliseconds\n}\n\n/**\n * Error thrown when a request fails\n */\nexport class RequestError extends Error {\n public status: number;\n public statusText: string;\n public response: Response;\n\n constructor(response: Response, message?: string) {\n super(message || `Request failed: ${response.status} ${response.statusText}`);\n this.name = 'RequestError';\n this.status = response.status;\n this.statusText = response.statusText;\n this.response = response;\n }\n}\n\n/**\n * Error thrown when a request times out\n */\nexport class RequestTimeoutError extends Error {\n constructor(url: string, timeout: number) {\n super(`Request to \"${url}\" timed out after ${timeout}ms`);\n this.name = 'RequestTimeoutError';\n }\n}\n\nexport class Request {\n /**\n * Serialize data to URL query string\n * Handles nested objects and arrays\n *\n * @param data - Data to serialize\n * @param prefix - Key prefix for nested objects\n */\n static serialize(data: RequestData, prefix?: string): string {\n if (data instanceof FormData) {\n const params = new URLSearchParams();\n data.forEach((value, key) => {\n if (typeof value === 'string') {\n params.append(key, value);\n }\n });\n return params.toString();\n }\n\n const params: string[] = [];\n\n for (const [key, value] of Object.entries(data)) {\n if (value === undefined || value === null) continue;\n\n const paramKey = prefix ? `${prefix}[${key}]` : key;\n\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n if (typeof item === 'object' && item !== null) {\n params.push(Request.serialize(item as Record<string, unknown>, `${paramKey}[${index}]`));\n } else {\n params.push(`${encodeURIComponent(paramKey)}[]=${encodeURIComponent(String(item))}`);\n }\n });\n } else if (typeof value === 'object') {\n params.push(Request.serialize(value as Record<string, unknown>, paramKey));\n } else {\n params.push(`${encodeURIComponent(paramKey)}=${encodeURIComponent(String(value))}`);\n }\n }\n\n return params.filter(Boolean).join('&');\n }\n\n /**\n * Parse a URL safely\n *\n * @param url - URL to parse\n */\n private static parseUrl(url: string): URL {\n try {\n return new URL(url);\n } catch {\n try {\n return new URL(url, window.location.origin);\n } catch (e) {\n throw new Error(`Invalid URL: \"${url}\"`);\n }\n }\n }\n\n /**\n * Create an AbortController with timeout\n *\n * @param timeout - Timeout in milliseconds\n * @param url - URL for error message\n */\n private static createTimeoutController(timeout: number | undefined, url: string): { controller: AbortController; timeoutId?: ReturnType<typeof setTimeout> } {\n const controller = new AbortController();\n\n if (!timeout) {\n return { controller };\n }\n\n const timeoutId = setTimeout(() => {\n controller.abort(new RequestTimeoutError(url, timeout));\n }, timeout);\n\n return { controller, timeoutId };\n }\n\n private static async send(\n method: string,\n url: string,\n data: RequestData = {},\n options: RequestOptions = {}\n ): Promise<Response> {\n const { timeout, ...fetchOptions } = options;\n const urlObj = Request.parseUrl(url);\n let body: BodyInit | undefined = undefined;\n const headers = { ...fetchOptions.headers };\n\n if (['GET', 'DELETE', 'HEAD'].includes(method.toUpperCase())) {\n if (data && typeof data === 'object' && !(data instanceof FormData)) {\n Object.entries(data).forEach(([key, val]) => {\n if (val !== undefined && val !== null) {\n urlObj.searchParams.append(key, String(val));\n }\n });\n }\n } else {\n const contentType = headers['Content-Type'] || headers['content-type'];\n\n if (data instanceof FormData) {\n // Browser automatically sets Content-Type to multipart/form-data with boundary\n // Removing both cases to let the browser do its job\n delete headers['Content-Type'];\n delete headers['content-type'];\n body = data;\n } else if (contentType === 'application/json') {\n body = JSON.stringify(data);\n } else {\n if (!contentType) {\n headers['Content-Type'] = 'application/x-www-form-urlencoded';\n }\n\n const params = new URLSearchParams();\n Object.entries(data).forEach(([k, v]) => params.append(k, String(v)));\n body = params;\n }\n }\n\n const { controller, timeoutId } = Request.createTimeoutController(timeout, url);\n\n try {\n const response = await fetch(urlObj.toString(), {\n ...fetchOptions,\n method,\n headers,\n body,\n signal: controller.signal\n });\n\n return response;\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n\n /**\n * Make a GET request\n *\n * @param url - Request URL\n * @param data - Query parameters\n * @param options - Request options\n */\n static get(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Response> {\n return Request.send('GET', url, data, options);\n }\n\n /**\n * Make a POST request\n *\n * @param url - Request URL\n * @param data - Request body\n * @param options - Request options\n */\n static post(url: string, data: RequestData, options: RequestOptions = {}): Promise<Response> {\n return Request.send('POST', url, data, options);\n }\n\n /**\n * Make a PUT request\n *\n * @param url - Request URL\n * @param data - Request body\n * @param options - Request options\n */\n static put(url: string, data: RequestData, options: RequestOptions = {}): Promise<Response> {\n return Request.send('PUT', url, data, options);\n }\n\n /**\n * Make a PATCH request\n *\n * @param url - Request URL\n * @param data - Request body\n * @param options - Request options\n */\n static patch(url: string, data: RequestData, options: RequestOptions = {}): Promise<Response> {\n return Request.send('PATCH', url, data, options);\n }\n\n /**\n * Make a DELETE request\n *\n * @param url - Request URL\n * @param data - Query parameters\n * @param options - Request options\n */\n static delete(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Response> {\n return Request.send('DELETE', url, data, options);\n }\n\n /**\n * Make a HEAD request\n *\n * @param url - Request URL\n * @param data - Query parameters\n * @param options - Request options\n */\n static head(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Response> {\n return Request.send('HEAD', url, data, options);\n }\n\n /**\n * Make a GET request and parse JSON response\n *\n * @param url - Request URL\n * @param data - Query parameters\n * @param options - Request options\n * @throws {RequestError} If the response is not ok\n */\n static async json<T = unknown>(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<T> {\n const response = await Request.get(url, data, options);\n\n if (!response.ok) {\n throw new RequestError(response);\n }\n\n return response.json();\n }\n\n /**\n * Make a POST request with JSON body and parse JSON response\n *\n * @param url - Request URL\n * @param data - Request body\n * @param options - Request options\n * @throws {RequestError} If the response is not ok\n */\n static async postJson<T = unknown>(url: string, data: RequestData, options: RequestOptions = {}): Promise<T> {\n const headers = { ...options.headers, 'Content-Type': 'application/json' };\n const response = await Request.post(url, data, { ...options, headers });\n\n if (!response.ok) {\n throw new RequestError(response);\n }\n\n return response.json();\n }\n\n /**\n * Make a GET request and return as Blob\n *\n * @param url - Request URL\n * @param data - Query parameters\n * @param options - Request options\n * @throws {RequestError} If the response is not ok\n */\n static async blob(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<Blob> {\n const response = await Request.get(url, data, options);\n\n if (!response.ok) {\n throw new RequestError(response);\n }\n\n return response.blob();\n }\n\n /**\n * Make a GET request and return as text\n *\n * @param url - Request URL\n * @param data - Query parameters\n * @param options - Request options\n * @throws {RequestError} If the response is not ok\n */\n static async text(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<string> {\n const response = await Request.get(url, data, options);\n\n if (!response.ok) {\n throw new RequestError(response);\n }\n\n return response.text();\n }\n\n /**\n * Make a GET request and return as ArrayBuffer\n *\n * @param url - Request URL\n * @param data - Query parameters\n * @param options - Request options\n * @throws {RequestError} If the response is not ok\n */\n static async arrayBuffer(url: string, data: RequestData = {}, options: RequestOptions = {}): Promise<ArrayBuffer> {\n const response = await Request.get(url, data, options);\n\n if (!response.ok) {\n throw new RequestError(response);\n }\n\n return response.arrayBuffer();\n }\n\n /**\n * Check if a URL exists (returns 2xx status)\n *\n * @param url - URL to check\n * @param options - Request options\n */\n static async exists(url: string, options: RequestOptions = {}): Promise<boolean> {\n try {\n const response = await Request.head(url, {}, options);\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n",
|
|
8
8
|
"/**\n * ==============================\n * File System\n * ==============================\n */\n\nimport { Request, RequestOptions } from './Request';\n\nexport type FileReadType = 'text' | 'base64' | 'buffer' | 'binary';\n\n/**\n * Return type mapping for file read operations\n */\nexport interface FileReadResult {\n text: string;\n base64: string;\n buffer: ArrayBuffer;\n binary: string;\n}\n\n/**\n * A utility wrapper for File/Blob operations\n */\nexport class FileSystem {\n\n /**\n * Read a file from a remote URL.\n *\n * @param url - The URL to fetch\n * @param type - The format to return ('text', 'base64', 'buffer', 'binary')\n * @param options - Request options\n */\n static async readRemote<T extends FileReadType>(\n url: string,\n type: T = 'base64' as T,\n options: RequestOptions = {}\n ): Promise<FileReadResult[T]> {\n const blob = await Request.blob(url, {}, options);\n return FileSystem.read(blob, type);\n }\n\n /**\n * Read a local File or Blob.\n *\n * @param file - The File or Blob to read\n * @param type - The format to return\n */\n static async read<T extends FileReadType>(file: File | Blob, type: T = 'text' as T): Promise<FileReadResult[T]> {\n switch (type) {\n case 'text':\n return file.text() as Promise<FileReadResult[T]>;\n\n case 'buffer':\n return file.arrayBuffer() as Promise<FileReadResult[T]>;\n\n case 'base64':\n return new Promise<FileReadResult[T]>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as FileReadResult[T]);\n reader.onerror = () => reject(reader.error);\n reader.readAsDataURL(file);\n });\n\n case 'binary':\n return new Promise<FileReadResult[T]>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const buffer = reader.result as ArrayBuffer;\n let binary = '';\n const bytes = new Uint8Array(buffer);\n const length = bytes.byteLength;\n for (let i = 0; i < length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n resolve(binary as FileReadResult[T]);\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(file);\n });\n\n default: {\n const exhaustiveCheck: never = type;\n throw new Error(`FileSystem.read: Unknown type ${exhaustiveCheck}`);\n }\n }\n }\n\n /**\n * Create a File object.\n * This is a synchronous operation.\n *\n * @param name - Filename\n * @param content - Data (String, Blob, ArrayBuffer)\n * @param mimeType - MIME type (e.g. 'application/json')\n */\n static create(name: string, content: BlobPart, mimeType: string = 'text/plain'): File {\n return new File([content], name, { type: mimeType });\n }\n\n /**\n * Trigger a browser download for a specific File or Blob.\n * This will creates a temporary anchor tag to force the download.\n *\n * @param file - The file to download\n * @param name - Optional rename for the downloaded file\n */\n static download(file: File | Blob, name?: string): void {\n const url = URL.createObjectURL(file);\n const a = document.createElement('a');\n\n a.href = url;\n\n // Determine filename: use provided name, or File.name if available, or fallback\n let filename: string;\n if (name !== undefined && name !== '') {\n filename = name;\n } else if (file instanceof File && file.name !== '') {\n filename = file.name;\n } else {\n filename = 'download';\n }\n\n a.download = filename;\n\n document.body.appendChild(a);\n a.click();\n\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n }\n\n /**\n * Get the file extension safely\n *\n * @param name - Filename or path\n * @returns Lowercase extension without the dot, or empty string\n */\n static extension(name: string, allowHiddenFiles: boolean = false): string {\n const parts = name.split('.');\n\n // No extension: \"file\" or hidden file \".gitignore\"\n if (parts.length === 1 || (parts[0] === '' && parts.length === 2 && !allowHiddenFiles)) {\n return '';\n }\n\n return parts.pop()?.toLowerCase() ?? '';\n }\n\n /**\n * Check if a file is an image based on extension.\n *\n * @param name - Filename to check\n */\n static isImage(name: string): boolean {\n const ext = FileSystem.extension(name);\n const valid = new Set([\n 'jpg', 'jpeg', 'png', 'gif', 'svg',\n 'webp', 'avif', 'bmp', 'ico', 'tiff', 'heic'\n ]);\n return valid.has(ext);\n }\n\n /**\n * Check if a file is a video based on extension.\n *\n * @param name - Filename to check\n */\n static isVideo(name: string): boolean {\n const ext = FileSystem.extension(name);\n const valid = new Set([\n 'mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv', 'm4v'\n ]);\n return valid.has(ext);\n }\n\n /**\n * Check if a file is audio based on extension.\n *\n * @param name - Filename to check\n */\n static isAudio(name: string): boolean {\n const ext = FileSystem.extension(name);\n const valid = new Set([\n 'mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a', 'wma'\n ]);\n return valid.has(ext);\n }\n\n /**\n * Convert bytes to human-readable size.\n *\n * @param bytes - Size in bytes\n * @param decimals - Number of decimal places\n */\n static humanSize(bytes: number, decimals: number = 2): string {\n if (bytes === 0) return '0 Bytes';\n\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];\n }\n}\n",
|
|
9
9
|
"/**\n * ==============================\n * Form\n * ==============================\n */\n\nexport type FormValue = string | number | boolean | File | null;\nexport type FormValues = Record<string, FormValue | FormValue[]>;\n\n/**\n * Options for parsing form values\n */\nexport interface FormParseOptions {\n parseNumbers?: boolean; // Whether to parse numeric strings as numbers\n parseBooleans?: boolean; // Whether to parse checkbox values as booleans for single checkboxes\n}\n\nexport class Form {\n\n /**\n * Fill a form with data.\n *\n * @param formName - The data-form attribute value\n * @param data - Key-value pairs to fill\n */\n static fill(formName: string, data: Record<string, unknown>): void {\n const form = document.querySelector(`form[data-form='${formName}']`) as HTMLFormElement;\n\n if (!form) {\n console.warn(`Form [data-form='${formName}'] not found.`);\n return;\n }\n\n Object.entries(data).forEach(([name, value]) => {\n const elements = form.querySelectorAll(`[name='${name}']`);\n\n if (elements.length === 0) return;\n\n const firstElement = elements[0] as HTMLInputElement;\n const type = firstElement.type;\n const valString = String(value);\n\n switch (type) {\n case 'radio':\n elements.forEach((el) => {\n const input = el as HTMLInputElement;\n if (input.value === valString) {\n input.checked = true;\n }\n });\n break;\n\n case 'checkbox':\n if (elements.length === 1) {\n // Single checkbox: treat as boolean\n (elements[0] as HTMLInputElement).checked = !!value;\n } else if (Array.isArray(value)) {\n // Multiple checkboxes: check those whose value is in the array\n const stringValues = value.map(String);\n elements.forEach((el) => {\n const input = el as HTMLInputElement;\n input.checked = stringValues.includes(input.value);\n });\n }\n break;\n\n case 'file':\n // File inputs cannot be programmatically filled for security reasons\n break;\n\n default:\n (elements[0] as HTMLInputElement | HTMLSelectElement).value = valString;\n break;\n }\n });\n }\n\n /**\n * Get all values from a form.\n *\n * @param formName - The data-form attribute value\n * @param options - Parsing options\n * @returns Form values as a record\n */\n static values(formName: string, options: FormParseOptions = {}): FormValues {\n const { parseNumbers = true, parseBooleans = true } = options;\n\n const form = document.querySelector(`form[data-form='${formName}']`) as HTMLFormElement;\n\n if (!form) {\n console.warn(`Form [data-form='${formName}'] not found.`);\n return {};\n }\n\n const formData = new FormData(form);\n const data: FormValues = {};\n\n const keys = Array.from(new Set(formData.keys()));\n\n for (const key of keys) {\n const allValues = formData.getAll(key);\n const element = form.querySelector(`[name='${key}']`) as HTMLInputElement | null;\n const inputType = element?.type;\n\n // Handle file inputs\n if (inputType === 'file') {\n const files = allValues.filter((v): v is File => v instanceof File);\n if (element?.multiple || files.length > 1) {\n data[key] = files;\n } else {\n data[key] = files[0] || null;\n }\n continue;\n }\n\n // Handle checkboxes\n if (inputType === 'checkbox') {\n const checkboxes = form.querySelectorAll(`[name='${key}']`);\n if (checkboxes.length === 1 && parseBooleans) {\n // Single checkbox: return boolean\n data[key] = (checkboxes[0] as HTMLInputElement).checked;\n continue;\n }\n // Multiple checkboxes: return array of checked values\n data[key] = allValues.map((v) => Form.parseValue(String(v), parseNumbers));\n continue;\n }\n\n // Handle number inputs\n if (inputType === 'number' && parseNumbers) {\n if (allValues.length > 1) {\n data[key] = allValues.map((v) => parseFloat(String(v)));\n } else {\n data[key] = parseFloat(String(allValues[0]));\n }\n continue;\n }\n\n // Handle other inputs\n if (allValues.length > 1) {\n data[key] = allValues.map((v) => Form.parseValue(String(v), parseNumbers));\n } else {\n data[key] = Form.parseValue(String(allValues[0]), parseNumbers);\n }\n }\n\n return data;\n }\n\n /**\n * Parse a string value, optionally converting to number.\n *\n * @param value - String value to parse\n * @param parseNumbers - Whether to parse numeric strings\n */\n private static parseValue(value: string, parseNumbers: boolean): string | number {\n if (parseNumbers && value !== '' && !isNaN(Number(value))) {\n return Number(value);\n }\n return value;\n }\n\n /**\n * Reset a form to its initial state.\n *\n * @param formName - The data-form attribute value\n */\n static reset(formName: string): void {\n const form = document.querySelector(`form[data-form='${formName}']`) as HTMLFormElement;\n\n if (!form) {\n console.warn(`Form [data-form='${formName}'] not found.`);\n return;\n }\n\n form.reset();\n }\n\n /**\n * Check if a form is valid according to HTML5 validation.\n *\n * @param formName - The data-form attribute value\n */\n static isValid(formName: string): boolean {\n const form = document.querySelector(`form[data-form='${formName}']`) as HTMLFormElement;\n\n if (!form) {\n console.warn(`Form [data-form='${formName}'] not found.`);\n return false;\n }\n\n return form.checkValidity();\n }\n\n /**\n * Report validity and show browser validation messages.\n *\n * @param formName - The data-form attribute value\n */\n static reportValidity(formName: string): boolean {\n const form = document.querySelector(`form[data-form='${formName}']`) as HTMLFormElement;\n\n if (!form) {\n console.warn(`Form [data-form='${formName}'] not found.`);\n return false;\n }\n\n return form.reportValidity();\n }\n}\n",
|
|
10
10
|
"/**\n * ==============================\n * Platform\n * ==============================\n */\n\nexport type DesktopPlatform = 'Windows' | 'macOS' | 'Linux' | 'FreeBSD' | 'Any' | 'ChromeOS';\nexport type MobilePlatform = 'Android' | 'iOS' | 'iPadOS' | 'WindowsMobile' | 'BlackBerry' | 'Any';\nexport type Orientation = 'portrait' | 'landscape';\n\ninterface NavigatorUAData {\n platform: string;\n mobile: boolean;\n brands: { brand: string; version: string }[];\n}\n\ninterface NavigatorWithStandalone extends Navigator {\n standalone?: boolean;\n userAgentData?: NavigatorUAData;\n}\n\ninterface ExtendedWindow extends Window {\n process?: {\n type?: string;\n versions?: { electron?: string };\n };\n cordova?: unknown;\n}\n\nexport class Platform {\n /**\n * Check if the screen has a high pixel density (Retina)\n */\n static get retina(): boolean {\n return window.devicePixelRatio >= 2;\n }\n\n /**\n * Check if the device is in portrait orientation.\n * Uses matchMedia to align perfectly with CSS media queries.\n */\n static get portrait(): boolean {\n return window.matchMedia('(orientation: portrait)').matches;\n }\n\n /**\n * Check if the device is in landscape orientation.\n */\n static get landscape(): boolean {\n return window.matchMedia('(orientation: landscape)').matches;\n }\n\n /**\n * Get current device orientation as a string.\n */\n static get orientation(): Orientation {\n return Platform.portrait ? 'portrait' : 'landscape';\n }\n\n /**\n * Check if the user prefers Dark Mode\n */\n static get darkMode(): boolean {\n return window.matchMedia('(prefers-color-scheme: dark)').matches;\n }\n\n /**\n * Check if the user prefers reduced motion\n */\n static get reducedMotion(): boolean {\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n }\n\n /**\n * Check if the device supports touch events.\n * Useful for distinguishing hybrid laptops from tablets.\n */\n static get touch(): boolean {\n return (\n 'ontouchstart' in window ||\n navigator.maxTouchPoints > 0\n );\n }\n\n /**\n * Check if the app is running in \"Standalone\" mode (Installed PWA).\n */\n static get standalone(): boolean {\n const nav = navigator as NavigatorWithStandalone;\n return (\n window.matchMedia('(display-mode: standalone)').matches ||\n nav.standalone === true // iOS fallback\n );\n }\n\n /**\n * Check if the app is running inside Electron.\n * Checks both Renderer process and Main process contexts.\n */\n static get electron(): boolean {\n const win = window as ExtendedWindow;\n\n if (navigator.userAgent.toLowerCase().includes(' electron/')) {\n return true;\n }\n\n if (win.process?.type === 'renderer') {\n return true;\n }\n\n if (win.process?.versions?.electron) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Check if the app is running inside Cordova / PhoneGap.\n */\n static get cordova(): boolean {\n return !!(window as ExtendedWindow).cordova;\n }\n\n /**\n * Internal helper to normalize platform detection\n */\n private static get userAgent(): string {\n return navigator.userAgent.toLowerCase();\n }\n\n /**\n * Check if the app is running on a Desktop platform.\n *\n * @param os - Specific desktop OS to check for, or 'Any' for any desktop\n */\n static desktop(os: DesktopPlatform = 'Any'): boolean {\n const nav = navigator as NavigatorWithStandalone;\n\n if (nav.userAgentData?.mobile === true) {\n return false;\n }\n\n if (Platform.isIpadOS()) {\n return false;\n }\n\n const ua = Platform.userAgent;\n const dataPlatform = nav.userAgentData?.platform?.toLowerCase() || '';\n\n const checks: Record<Exclude<DesktopPlatform, 'Any'>, boolean> = {\n 'ChromeOS': dataPlatform.includes('cros') || ua.includes('cros'),\n 'Windows': dataPlatform.includes('windows') || ua.includes('windows'),\n 'macOS': dataPlatform.includes('macos') || ua.includes('macintosh'),\n 'Linux': !ua.includes('android') && (dataPlatform.includes('linux') || ua.includes('linux')),\n 'FreeBSD': dataPlatform.includes('freebsd') || ua.includes('freebsd'),\n };\n\n if (os === 'Any') {\n return Object.values(checks).some(val => val);\n }\n\n return checks[os] || false;\n }\n\n /**\n * Check if the app is running on a Mobile platform.\n *\n * @param os - Specific mobile OS to check for, or 'Any' for any mobile\n */\n static mobile(os: MobilePlatform = 'Any'): boolean {\n const nav = navigator as NavigatorWithStandalone;\n\n if (nav.userAgentData?.mobile === true && os === 'Any') {\n return true;\n }\n\n const ua = Platform.userAgent;\n\n const checks: Record<Exclude<MobilePlatform, 'Any'>, boolean> = {\n 'Android': ua.includes('android'),\n 'iOS': /iphone|ipod/.test(ua),\n 'iPadOS': Platform.isIpadOS(),\n 'WindowsMobile': /windows phone|iemobile|wpdesktop/.test(ua),\n 'BlackBerry': /blackberry|bb10/.test(ua),\n };\n\n if (os === 'Any') {\n return Object.values(checks).some(val => val);\n }\n\n return checks[os] || false;\n }\n\n /**\n * Detect iPadOS explicitly.\n * Modern iPads send a \"Macintosh\" User Agent, but have Touch Points.\n */\n private static isIpadOS(): boolean {\n const ua = Platform.userAgent;\n\n if (ua.includes('ipad')) {\n return true;\n }\n\n if (ua.includes('macintosh') && navigator.maxTouchPoints > 0) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Check if the platform supports Service Workers.\n * Uses `isSecureContext` to accurately allow localhost/HTTPS.\n */\n static get serviceWorkers(): boolean {\n return 'serviceWorker' in navigator && window.isSecureContext;\n }\n\n /**\n * Check if the device has a coarse pointer (touch) as primary input.\n */\n static get coarsePointer(): boolean {\n return window.matchMedia('(pointer: coarse)').matches;\n }\n\n /**\n * Check if the device has a fine pointer (mouse) as primary input.\n */\n static get finePointer(): boolean {\n return window.matchMedia('(pointer: fine)').matches;\n }\n\n /**\n * Check if the device supports hover interactions.\n */\n static get canHover(): boolean {\n return window.matchMedia('(hover: hover)').matches;\n }\n}\n",
|
|
11
11
|
"/**\n * ==============================\n * Preload\n * ==============================\n */\n\ninterface RequestInitWithPriority extends RequestInit {\n priority?: 'high' | 'low' | 'auto';\n}\n\nexport class Preload {\n /**\n * Preload and decode an image. Decoding prevents the image from still having\n * a delay when it is displayed.\n *\n * @param route - URL of the image\n * @returns Promise<HTMLImageElement>\n */\n static async image(route: string): Promise<HTMLImageElement> {\n const img = new Image();\n img.src = route;\n\n await img.decode();\n\n return img;\n }\n\n /**\n * Preload multiple images in parallel.\n *\n * @param routes - Array of image URLs\n * @returns Promise<HTMLImageElement[]>\n */\n static async images(routes: string[]): Promise<HTMLImageElement[]> {\n return Promise.all(routes.map(route => Preload.image(route)));\n }\n\n /**\n * Preload a generic file by fetching it.\n *\n * @param route - URL of the file\n * @param priority - Fetch priority hint (default: 'low')\n * @returns Promise<Response>\n */\n static async file(route: string, priority: 'high' | 'low' | 'auto' = 'low'): Promise<Response> {\n const options: RequestInitWithPriority = { priority };\n const response = await fetch(route, options as RequestInit);\n\n if (!response.ok) {\n throw new Error(`Preload failed for \"${route}\": ${response.status} ${response.statusText}`);\n }\n\n return response;\n }\n\n /**\n * Preload multiple files in parallel.\n *\n * @param routes - Array of file URLs\n * @param priority - Fetch priority hint\n * @returns Promise<Response[]>\n */\n static async files(routes: string[], priority: 'high' | 'low' | 'auto' = 'low'): Promise<Response[]> {\n return Promise.all(routes.map(route => Preload.file(route, priority)));\n }\n\n /**\n * Check if a URL is cached in a specific cache.\n *\n * @param cacheName - Name of the cache to check\n * @param url - URL to look for\n * @returns Whether the URL is cached\n */\n static async isCached(cacheName: string, url: string): Promise<boolean> {\n if (!('caches' in window)) {\n return false;\n }\n\n try {\n const cache = await caches.open(cacheName);\n const match = await cache.match(url);\n return !!match;\n } catch {\n // Cache API may throw in private browsing mode or other restricted contexts\n return false;\n }\n }\n\n /**\n * Add a URL to a cache.\n *\n * @param cacheName - Name of the cache\n * @param url - URL to cache\n * @returns Promise<void>\n */\n static async addToCache(cacheName: string, url: string): Promise<void> {\n if (!('caches' in window)) {\n throw new Error('Cache API is not supported in this browser');\n }\n\n try {\n const cache = await caches.open(cacheName);\n await cache.add(url);\n } catch (error) {\n throw new Error(`Failed to cache \"${url}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n /**\n * Add multiple URLs to a cache.\n *\n * @param cacheName - Name of the cache\n * @param urls - URLs to cache\n * @returns Promise<void>\n */\n static async addAllToCache(cacheName: string, urls: string[]): Promise<void> {\n if (!('caches' in window)) {\n throw new Error('Cache API is not supported in this browser');\n }\n\n try {\n const cache = await caches.open(cacheName);\n await cache.addAll(urls);\n } catch (error) {\n throw new Error(`Failed to cache URLs: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n /**\n * Preload a CSS stylesheet.\n *\n * @param url - URL of the stylesheet\n * @returns Promise<void>\n */\n static async stylesheet(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const link = document.createElement('link');\n\n link.rel = 'preload';\n link.as = 'style';\n link.href = url;\n\n link.onload = () => resolve();\n link.onerror = () => reject(new Error(`Failed to preload stylesheet: ${url}`));\n\n document.head.appendChild(link);\n });\n }\n\n /**\n * Preload a JavaScript file.\n *\n * @param url - URL of the script\n * @returns Promise<void>\n */\n static async script(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const link = document.createElement('link');\n\n link.rel = 'preload';\n link.as = 'script';\n link.href = url;\n\n link.onload = () => resolve();\n link.onerror = () => reject(new Error(`Failed to preload script: ${url}`));\n\n document.head.appendChild(link);\n });\n }\n\n /**\n * Preload a font file.\n *\n * @param url - URL of the font\n * @param crossOrigin - Whether to use crossorigin attribute (default: true for fonts)\n * @returns Promise<void>\n */\n static async font(url: string, crossOrigin: boolean = true): Promise<void> {\n return new Promise((resolve, reject) => {\n const link = document.createElement('link');\n\n link.rel = 'preload';\n link.as = 'font';\n link.href = url;\n\n if (crossOrigin) {\n link.crossOrigin = 'anonymous';\n }\n\n link.onload = () => resolve();\n link.onerror = () => reject(new Error(`Failed to preload font: ${url}`));\n\n document.head.appendChild(link);\n });\n }\n}\n",
|
|
12
|
-
"/**\n * ==============================\n * Space Adapter Types\n * ==============================\n */\n\n/**\n * Base configuration for all space adapters\n */\nexport interface SpaceConfiguration {\n
|
|
13
|
-
"/**\n * ==============================\n * Local Storage Adapter\n * ==============================\n */\n\nimport type { LocalStorageConfiguration, StorageValue, KeyValueResult, UpgradeCallback, SpaceAdapterInterface } from './types';\nimport { versionToNumber } from './types';\n\n/**\n * Error thrown when a key is not found in storage\n */\nexport class KeyNotFoundError extends Error {\n\tconstructor(key: string) {\n\t\tsuper(`Key \"${key}\" not found in storage`);\n\t\tthis.name = 'KeyNotFoundError';\n\t}\n}\n\n/**\n * The Local Storage Adapter provides the Space Class the ability to interact\n * with the localStorage API found in most modern browsers.\n */\nexport class LocalStorage implements SpaceAdapterInterface {\n\tpublic name: string;\n\tpublic version: string;\n\tpublic store: string;\n\tpublic id: string;\n\tpublic numericVersion: number;\n\tpublic upgrades: Record<string, UpgradeCallback<LocalStorage>>;\n\tpublic storage: Storage | undefined;\n\tprivate _openPromise: Promise<this> | undefined;\n\n\t/**\n\t * Create a new LocalStorage. If no configuration is provided, the LocalStorage\n\t * global object is used. The LocalStorage Adapter can provide independency\n\t * by store name and space name.\n\t *\n\t * @param configuration - Configuration Object for the Adapter\n\t */\n\tconstructor({ name = '', version = '', store = '' }: LocalStorageConfiguration) {\n\t\tthis.name = name;\n\t\tthis.version = version;\n\t\tthis.store = store;\n\t\tthis.upgrades = {};\n\n\t\tthis.numericVersion = versionToNumber(version);\n\t\tthis.id = this.computeId();\n\t}\n\n\t/**\n\t * Compute the storage ID based on current name, version, and store\n\t *\n\t * @returns The computed ID string\n\t */\n\tprivate computeId(): string {\n\t\tif (this.name !== '' && this.version !== '' && this.store !== '') {\n\t\t\treturn `${this.name}::${this.store}::${this.version}_`;\n\t\t} else if (this.name !== '' && this.version !== '') {\n\t\t\treturn `${this.name}::${this.version}_`;\n\t\t} else if (this.name !== '') {\n\t\t\treturn `${this.name}::_`;\n\t\t} else {\n\t\t\treturn '';\n\t\t}\n\t}\n\n\t/**\n\t * Modify the configuration\n\t *\n\t * @param config - Configuration object to set up\n\t */\n\tconfiguration(config: LocalStorageConfiguration): void {\n\t\tif (config.name !== undefined) this.name = config.name;\n\t\tif (config.version !== undefined) {\n\t\t\tthis.version = config.version;\n\t\t\tthis.numericVersion = versionToNumber(config.version);\n\t\t}\n\t\tif (config.store !== undefined) this.store = config.store;\n\n\t\t// Recalculate the ID after configuration changes\n\t\tthis.id = this.computeId();\n\t}\n\n\t/**\n\t * Open the Storage Object\n\t *\n\t * @returns Promise resolving to this adapter\n\t */\n\tasync open(): Promise<this> {\n\t\t// Already opened\n\t\tif (this.storage instanceof Storage) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Currently opening - wait for it\n\t\tif (this._openPromise) {\n\t\t\treturn this._openPromise;\n\t\t}\n\n\t\t// Start opening\n\t\tthis._openPromise = (async () => {\n\t\t\tlet upgradesToApply: string[] = [];\n\n\t\t\t// Check if this space is versioned\n\t\t\tif (this.version !== '') {\n\t\t\t\t// Get the versionless part of the ID\n\t\t\t\tlet versionless = '';\n\t\t\t\tif (this.name !== '' && this.version !== '' && this.store !== '') {\n\t\t\t\t\tversionless = `${this.name}::${this.store}::`;\n\t\t\t\t} else if (this.name !== '' && this.version !== '') {\n\t\t\t\t\tversionless = `${this.name}::`;\n\t\t\t\t}\n\n\t\t\t\t// Get all the currently stored keys that contain the versionless ID\n\t\t\t\tconst storedVersions = Object.keys(window.localStorage).filter((key) => {\n\t\t\t\t\treturn key.indexOf(versionless) === 0;\n\t\t\t\t}).map((key) => {\n\t\t\t\t\treturn key.replace(versionless, '').split('_')[0];\n\t\t\t\t}).filter((key) => {\n\t\t\t\t\treturn key.indexOf('::') === -1;\n\t\t\t\t}).sort();\n\n\t\t\t\tif (storedVersions.length > 0) {\n\t\t\t\t\tconst oldVersion = storedVersions[0];\n\t\t\t\t\tconst oldVersionNumeric = versionToNumber(oldVersion);\n\n\t\t\t\t\tif (oldVersionNumeric < this.numericVersion) {\n\t\t\t\t\t\tconst availableUpgrades = Object.keys(this.upgrades).sort((a, b) => {\n\t\t\t\t\t\t\tconst [aOld] = a.split('::').map(Number);\n\t\t\t\t\t\t\tconst [bOld] = b.split('::').map(Number);\n\t\t\t\t\t\t\treturn aOld - bOld;\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst startFrom = availableUpgrades.findIndex((u) => {\n\t\t\t\t\t\t\tconst [old] = u.split('::');\n\t\t\t\t\t\t\treturn parseInt(old) === oldVersionNumeric;\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (startFrom > -1) {\n\t\t\t\t\t\t\tupgradesToApply = availableUpgrades.slice(startFrom).filter((u) => {\n\t\t\t\t\t\t\t\tconst [old, next] = u.split('::');\n\t\t\t\t\t\t\t\treturn parseInt(old) < this.numericVersion && parseInt(next) <= this.numericVersion;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Get the previous ID using the old version\n\t\t\t\t\t\tlet previousId = `${this.name}::${oldVersion}_`;\n\n\t\t\t\t\t\tif (this.name !== '' && this.version !== '' && this.store !== '') {\n\t\t\t\t\t\t\tpreviousId = `${this.name}::${this.store}::${oldVersion}_`;\n\t\t\t\t\t\t} else if (this.name !== '' && this.version !== '') {\n\t\t\t\t\t\t\tpreviousId = `${this.name}::${oldVersion}_`;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Get all keys from the previous version\n\t\t\t\t\t\tconst keys = Object.keys(window.localStorage).filter((key) => {\n\t\t\t\t\t\t\treturn key.indexOf(previousId) === 0;\n\t\t\t\t\t\t}).map((key) => {\n\t\t\t\t\t\t\treturn key.replace(previousId, '');\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tfor (const key of keys) {\n\t\t\t\t\t\t\tconst previous = window.localStorage.getItem(`${previousId}${key}`);\n\t\t\t\t\t\t\tif (previous !== null) {\n\t\t\t\t\t\t\t\twindow.localStorage.setItem(this.id + key, previous);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\twindow.localStorage.removeItem(`${previousId}${key}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.storage = window.localStorage;\n\n\t\t\t// Apply upgrades\n\t\t\tfor (const upgradeKey of upgradesToApply) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.upgrades[upgradeKey].call(this, this);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tconsole.error(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t})();\n\n\t\ttry {\n\t\t\treturn await this._openPromise;\n\t\t} finally {\n\t\t\tthis._openPromise = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Store a key-value pair\n\t *\n\t * @param key - Key with which this value will be saved\n\t * @param value - Value to save\n\t * @returns Promise with key and value\n\t */\n\tasync set(key: string, value: StorageValue): Promise<KeyValueResult> {\n\t\tawait this.open();\n\t\tif (typeof value === 'object') {\n\t\t\t(this.storage as Storage).setItem(this.id + key, JSON.stringify(value));\n\t\t} else {\n\t\t\t(this.storage as Storage).setItem(this.id + key, String(value));\n\t\t}\n\t\treturn { key, value };\n\t}\n\n\t/**\n\t * Update a key-value pair. The update method will use Object.assign()\n\t * in the case of objects so no value is lost.\n\t *\n\t * @param key - Key with which this value will be saved\n\t * @param value - Value to save\n\t * @returns Promise with key and value\n\t */\n\tasync update(key: string, value: StorageValue): Promise<KeyValueResult> {\n\t\ttry {\n\t\t\tconst currentValue = await this.get(key);\n\t\t\tif (typeof currentValue === 'object' && currentValue !== null) {\n\t\t\t\tif (typeof value === 'object' && value !== null) {\n\t\t\t\t\tvalue = { ...(currentValue as object), ...(value as object) };\n\t\t\t\t}\n\t\t\t\t(this.storage as Storage).setItem(this.id + key, JSON.stringify(value));\n\t\t\t} else {\n\t\t\t\t(this.storage as Storage).setItem(this.id + key, String(value));\n\t\t\t}\n\t\t\treturn { key, value };\n\t\t} catch {\n\t\t\treturn this.set(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves a value from storage given its key\n\t *\n\t * @param key - Key with which the value was saved\n\t * @returns Promise resolving to the retrieved value\n\t */\n\tasync get(key: string): Promise<StorageValue> {\n\t\tawait this.open();\n\t\tconst rawValue = (this.storage as Storage).getItem(this.id + key);\n\n\t\tif (rawValue === null) {\n\t\t\tthrow new KeyNotFoundError(key);\n\t\t}\n\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(rawValue);\n\t\t\tif (parsed && typeof parsed === 'object') {\n\t\t\t\treturn parsed;\n\t\t\t}\n\t\t\treturn rawValue;\n\t\t} catch {\n\t\t\t// Unable to parse to JSON, return raw value\n\t\t\treturn rawValue;\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves all the values in the space in a key-value JSON object\n\t *\n\t * @returns Promise resolving to all values\n\t */\n\tasync getAll(): Promise<Record<string, StorageValue>> {\n\t\tconst keys = await this.keys();\n\t\tconst values: Record<string, StorageValue> = {};\n\n\t\tfor (const key of keys) {\n\t\t\ttry {\n\t\t\t\tvalues[key] = await this.get(key);\n\t\t\t} catch {\n\t\t\t\t// Skip keys that fail to retrieve\n\t\t\t}\n\t\t}\n\n\t\treturn values;\n\t}\n\n\t/**\n\t * Check if the space contains a given key.\n\t *\n\t * @param key - Key to look for\n\t * @returns Promise that resolves if key exists\n\t */\n\tasync contains(key: string): Promise<void> {\n\t\tconst keys = await this.keys();\n\t\tif (keys.includes(key)) {\n\t\t\treturn;\n\t\t} else {\n\t\t\tthrow new KeyNotFoundError(key);\n\t\t}\n\t}\n\n\t/**\n\t * Upgrade a Space Version\n\t *\n\t * @param oldVersion - The version of the storage to be upgraded\n\t * @param newVersion - The version to be upgraded to\n\t * @param callback - Function to transform the old stored values\n\t * @returns Promise\n\t */\n\tasync upgrade(oldVersion: string, newVersion: string, callback: UpgradeCallback<LocalStorage>): Promise<void> {\n\t\tconst key = `${versionToNumber(oldVersion)}::${versionToNumber(newVersion)}`;\n\t\tthis.upgrades[key] = callback;\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Rename a Space\n\t *\n\t * @param name - New name to be used\n\t * @returns Promise for the rename operation\n\t */\n\tasync rename(name: string): Promise<void> {\n\t\tif (this.name === name) {\n\t\t\tthrow new Error('Cannot rename: new name is identical to current name');\n\t\t}\n\n\t\tconst keys = await this.keys();\n\t\tconst oldId = this.id;\n\t\tthis.name = name;\n\t\tthis.id = this.computeId();\n\n\t\tfor (const key of keys) {\n\t\t\tconst rawValue = (this.storage as Storage).getItem(`${oldId}${key}`);\n\t\t\tif (rawValue !== null) {\n\t\t\t\t// Directly copy the raw value to avoid double-encoding\n\t\t\t\t(this.storage as Storage).setItem(this.id + key, rawValue);\n\t\t\t\t(this.storage as Storage).removeItem(`${oldId}${key}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the key that corresponds to a given index in the storage.\n\t * Only considers keys belonging to this space.\n\t *\n\t * @param index - Index to get the key from\n\t * @param full - Whether to return the full key name including space id\n\t * @returns Promise resolving to the key's name\n\t */\n\tasync key(index: number, full: boolean = false): Promise<string> {\n\t\tconst spaceKeys = await this.keys(full);\n\n\t\tif (index < 0 || index >= spaceKeys.length) {\n\t\t\tthrow new Error(`Index ${index} out of bounds. Space has ${spaceKeys.length} keys.`);\n\t\t}\n\n\t\treturn spaceKeys[index];\n\t}\n\n\t/**\n\t * Return all keys stored in the space.\n\t *\n\t * @param full - Whether to return the full key name including space id\n\t * @returns Promise resolving to array of keys\n\t */\n\tasync keys(full: boolean = false): Promise<string[]> {\n\t\tawait this.open();\n\t\treturn Object.keys(this.storage as Storage).filter((key) => {\n\t\t\treturn key.indexOf(this.id) === 0;\n\t\t}).map((key) => {\n\t\t\tif (full === true) {\n\t\t\t\treturn key;\n\t\t\t} else {\n\t\t\t\treturn key.replace(this.id, '');\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Delete a value from the space given its key\n\t *\n\t * @param key - Key of the item to delete\n\t * @returns Promise resolving to the value of the deleted object\n\t */\n\tasync remove(key: string): Promise<StorageValue> {\n\t\tconst value = await this.get(key);\n\t\t(this.storage as Storage).removeItem(this.id + key);\n\t\treturn value;\n\t}\n\n\t/**\n\t * Clear the entire space\n\t *\n\t * @returns Promise for the clear operation\n\t */\n\tasync clear(): Promise<void> {\n\t\tconst keys = await this.keys();\n\n\t\tfor (const key of keys) {\n\t\t\t(this.storage as Storage).removeItem(this.id + key);\n\t\t}\n\t}\n}\n",
|
|
14
|
-
"/**\n * ==============================\n * Session Storage Adapter\n * ==============================\n */\n\nimport { LocalStorage } from './LocalStorage';\nimport type { LocalStorageConfiguration, UpgradeCallback } from './types';\n\n/**\n * The Session Storage Adapter provides the Space Class the ability to interact\n * with the sessionStorage API found in most modern browsers. Since this API\n * shares pretty much the same methods as the local storage one, this class\n * inherits from the LocalStorage adapter.\n *\n * Note: SessionStorage does not support versioning and upgrades because session\n * data is inherently temporary and cleared when the browser session ends.\n * Any declared upgrades will be ignored.\n */\nexport class SessionStorage extends LocalStorage {\n
|
|
15
|
-
"/**\n * ==============================\n * IndexedDB Adapter\n * ==============================\n */\n\nimport type { IndexedDBConfiguration, StorageValue, KeyValueResult, UpgradeCallback, SpaceAdapterInterface } from './types';\nimport { versionToNumber } from './types';\n\n/**\n * Error thrown when a key is not found in storage\n */\nexport class KeyNotFoundError extends Error {\n\tconstructor(key: string) {\n\t\tsuper(`Key \"${key}\" not found in IndexedDB`);\n\t\tthis.name = 'KeyNotFoundError';\n\t}\n}\n\n/**\n * The IndexedDB Adapter provides the Space Class the ability to interact\n * with the IndexedDB API found in most modern browsers.\n */\nexport class IndexedDB implements SpaceAdapterInterface {\n\tpublic name: string;\n\tpublic version: string;\n\tpublic store: string;\n\tpublic props: IDBObjectStoreParameters;\n\tpublic index: Record<string, { name: string; field: string; props?: IDBIndexParameters }>;\n\tpublic keyPath: string;\n\tpublic numericVersion: number;\n\tpublic upgrades: Record<string, UpgradeCallback<IndexedDB>>;\n\tpublic storage: IDBDatabase | Promise<IDBDatabase> | undefined;\n\n\t/**\n\t * Create a new IndexedDB. Differently from Local and Session Storages, the\n\t * IndexedDB Adapter requires a mandatory name, version and store name.\n\t *\n\t * @param configuration - Configuration Object for the Adapter\n\t */\n\tconstructor({ name = '', version = '', store = '', props = {}, index = {} }: IndexedDBConfiguration) {\n\t\tthis.name = name;\n\t\tthis.version = version;\n\t\tthis.store = store;\n\t\tthis.props = props || {};\n\t\tthis.index = index;\n\n\t\tthis.keyPath = (props?.keyPath as string) || 'id';\n\t\tthis.upgrades = {};\n\n\t\tthis.numericVersion = versionToNumber(version);\n\t}\n\n\t/**\n\t * Modify the configuration\n\t *\n\t * @param config - Configuration object to set up\n\t */\n\tconfiguration(config: IndexedDBConfiguration): void {\n\t\tif (config.name !== undefined) this.name = config.name;\n\t\tif (config.version !== undefined) {\n\t\t\tthis.version = config.version;\n\t\t\tthis.numericVersion = versionToNumber(config.version);\n\t\t}\n\t\tif (config.store !== undefined) this.store = config.store;\n\t}\n\n\t/**\n\t * Open the Storage Object\n\t *\n\t * @returns Promise resolving to this adapter\n\t */\n\tasync open(): Promise<this> {\n\t\tif (this.name === '') {\n\t\t\tthrow new Error('IndexedDB requires a name. No name has been defined for this space.');\n\t\t}\n\n\t\tif (this.store === '') {\n\t\t\tthrow new Error('IndexedDB requires a store name. No store has been defined for this space.');\n\t\t}\n\n\t\tif (this.storage instanceof IDBDatabase) {\n\t\t\treturn this;\n\t\t} else if (this.storage instanceof Promise) {\n\t\t\treturn await (this.storage as unknown as Promise<this>);\n\t\t} else {\n\t\t\tconst openTask = (async () => {\n\t\t\t\tlet upgradeEvent: IDBVersionChangeEvent | undefined;\n\t\t\t\tlet upgradesToApply: string[] = [];\n\n\t\t\t\tconst db = await new Promise<IDBDatabase>((resolve, reject) => {\n\t\t\t\t\tconst request = window.indexedDB.open(this.name, this.numericVersion);\n\n\t\t\t\t\trequest.onerror = (event) => {\n\t\t\t\t\t\treject(new Error(`Failed to open IndexedDB \"${this.name}\": ${(event.target as IDBOpenDBRequest).error?.message}`));\n\t\t\t\t\t};\n\n\t\t\t\t\trequest.onsuccess = (event) => {\n\t\t\t\t\t\tresolve((event.target as IDBOpenDBRequest).result);\n\t\t\t\t\t};\n\n\t\t\t\t\trequest.onupgradeneeded = (event: IDBVersionChangeEvent) => {\n\t\t\t\t\t\tupgradeEvent = event;\n\t\t\t\t\t\tconst db = (event.target as IDBOpenDBRequest).result;\n\n\t\t\t\t\t\tif (event.oldVersion < 1) {\n\t\t\t\t\t\t\t// Create all the needed Stores\n\t\t\t\t\t\t\tconst store = db.createObjectStore(this.store, this.props);\n\t\t\t\t\t\t\tfor (const indexKey of Object.keys(this.index)) {\n\t\t\t\t\t\t\t\tconst idx = this.index[indexKey];\n\t\t\t\t\t\t\t\tstore.createIndex(idx.name, idx.field, idx.props);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Check what upgrade functions have been declared\n\t\t\t\t\t\t\tconst availableUpgrades = Object.keys(this.upgrades).sort((a, b) => {\n\t\t\t\t\t\t\t\tconst [aOld] = a.split('::').map(Number);\n\t\t\t\t\t\t\t\tconst [bOld] = b.split('::').map(Number);\n\t\t\t\t\t\t\t\treturn aOld - bOld;\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst startFrom = availableUpgrades.findIndex((u) => {\n\t\t\t\t\t\t\t\tconst [old] = u.split('::');\n\t\t\t\t\t\t\t\treturn parseInt(old) === event.oldVersion;\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (startFrom > -1) {\n\t\t\t\t\t\t\t\tupgradesToApply = availableUpgrades.slice(startFrom).filter((u) => {\n\t\t\t\t\t\t\t\t\tconst [old, next] = u.split('::');\n\t\t\t\t\t\t\t\t\treturn parseInt(old) < this.numericVersion && parseInt(next) <= this.numericVersion;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Once the transaction is done, resolve the storage object\n\t\t\t\t\t\tconst transaction = (event.target as IDBOpenDBRequest).transaction;\n\t\t\t\t\t\tif (transaction) {\n\t\t\t\t\t\t\ttransaction.addEventListener('complete', () => {\n\t\t\t\t\t\t\t\t// Transaction completed\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\tthis.storage = db;\n\n\t\t\t\t// Apply upgrades\n\t\t\t\tfor (const upgradeKey of upgradesToApply) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.upgrades[upgradeKey].call(this, this, upgradeEvent);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(e);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn this;\n\t\t\t})();\n\n\t\t\tthis.storage = openTask as unknown as Promise<IDBDatabase>;\n\t\t\treturn await openTask;\n\t\t}\n\t}\n\n\t/**\n\t * Store a key-value pair. Because of the nature of IndexedDB,\n\t * stored values must be JSON objects.\n\t *\n\t * @param key - Key with which this value will be saved\n\t * @param value - Value to save\n\t * @returns Promise with key and value\n\t */\n\tasync set(key: string | null = null, value: StorageValue): Promise<KeyValueResult> {\n\t\tawait this.open();\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst transaction = (this.storage as IDBDatabase)\n\t\t\t\t.transaction(this.store, 'readwrite')\n\t\t\t\t.objectStore(this.store);\n\n\t\t\tlet op: IDBRequest;\n\n\t\t\tif (key !== null) {\n\t\t\t\tconst temp: Record<string, unknown> = {};\n\n\t\t\t\ttemp[this.keyPath] = key;\n\t\t\t\top = transaction.put({ ...temp, ...(value as object) });\n\t\t\t} else {\n\t\t\t\top = transaction.add(value);\n\t\t\t}\n\n\t\t\top.addEventListener('success', (event) => {\n\t\t\t\tresolve({ key: String((event.target as IDBRequest).result), value });\n\t\t\t});\n\n\t\t\top.addEventListener('error', (event) => {\n\t\t\t\treject(new Error(`Failed to set key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Update a key-value pair. The update method will use Object.assign()\n\t * in the case of objects so no value is lost.\n\t *\n\t * @param key - Key with which this value will be saved\n\t * @param value - Value to save\n\t * @returns Promise with key and value\n\t */\n\tasync update(key: string, value: StorageValue): Promise<KeyValueResult> {\n\t\ttry {\n\t\t\tconst currentValue = await this.get(key);\n\n\t\t\tif (typeof currentValue === 'undefined') {\n\t\t\t\treturn this.set(key, value);\n\t\t\t}\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tconst transaction = (this.storage as IDBDatabase)\n\t\t\t\t\t.transaction(this.store, 'readwrite')\n\t\t\t\t\t.objectStore(this.store);\n\n\t\t\t\tconst op = transaction.put({ ...(currentValue as object), ...(value as object) });\n\n\t\t\t\top.addEventListener('success', (event) => {\n\t\t\t\t\tresolve({ key: String((event.target as IDBRequest).result), value });\n\t\t\t\t});\n\n\t\t\t\top.addEventListener('error', (event) => {\n\t\t\t\t\treject(new Error(`Failed to update key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n\t\t\t\t});\n\t\t\t});\n\t\t} catch {\n\t\t\treturn this.set(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves a value from storage given its key\n\t *\n\t * @param key - Key with which the value was saved\n\t * @returns Promise resolving to the retrieved value\n\t */\n\tasync get(key: string): Promise<StorageValue> {\n\t\tawait this.open();\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst transaction = (this.storage as IDBDatabase)\n\t\t\t\t.transaction(this.store, 'readonly')\n\t\t\t\t.objectStore(this.store);\n\n\t\t\tconst op = transaction.get(key);\n\n\t\t\top.addEventListener('success', (event) => {\n\t\t\t\tconst value = (event.target as IDBRequest).result;\n\t\t\t\tif (typeof value !== 'undefined' && value !== null) {\n\t\t\t\t\tresolve(value);\n\t\t\t\t} else {\n\t\t\t\t\treject(new KeyNotFoundError(key));\n\t\t\t\t}\n\t\t\t});\n\n\t\t\top.addEventListener('error', (event) => {\n\t\t\t\treject(new Error(`Failed to get key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Retrieves all the values in the space in a key-value JSON object.\n\t * Note: The keyPath property is preserved in the returned items.\n\t *\n\t * @returns Promise resolving to all values\n\t */\n\tasync getAll(): Promise<Record<string, StorageValue>> {\n\t\tawait this.open();\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst transaction = (this.storage as IDBDatabase)\n\t\t\t\t.transaction(this.store, 'readonly')\n\t\t\t\t.objectStore(this.store);\n\n\t\t\tconst op = transaction.getAll();\n\n\t\t\top.addEventListener('success', (event) => {\n\t\t\t\tconst results: Record<string, StorageValue> = {};\n\t\t\t\tconst items = (event.target as IDBRequest).result as Record<string, unknown>[];\n\n\t\t\t\titems.forEach((item) => {\n\t\t\t\t\tconst id = item[this.keyPath] as string;\n\t\t\t\t\t// Create a shallow copy to avoid mutating the original item\n\t\t\t\t\tconst itemCopy = { ...item };\n\t\t\t\t\tdelete itemCopy[this.keyPath];\n\t\t\t\t\tresults[id] = itemCopy;\n\t\t\t\t});\n\n\t\t\t\tresolve(results);\n\t\t\t});\n\n\t\t\top.addEventListener('error', (event) => {\n\t\t\t\treject(new Error(`Failed to get all items: ${(event.target as IDBRequest).error?.message}`));\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Check if the space contains a given key.\n\t *\n\t * @param key - Key to look for\n\t * @returns Promise that resolves if key exists\n\t */\n\tasync contains(key: string): Promise<void> {\n\t\tawait this.get(key);\n\t}\n\n\t/**\n\t * Upgrade a Space Version. Upgrades must be declared before the open()\n\t * method is executed.\n\t *\n\t * @param oldVersion - The version to be upgraded\n\t * @param newVersion - The version to be upgraded to\n\t * @param callback - Function to transform the old stored values\n\t * @returns Promise\n\t */\n\tasync upgrade(oldVersion: string, newVersion: string, callback: UpgradeCallback<IndexedDB>): Promise<void> {\n\t\tconst key = `${versionToNumber(oldVersion)}::${versionToNumber(newVersion)}`;\n\t\tthis.upgrades[key] = callback;\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Renaming the space is not possible with the IndexedDB adapter therefore\n\t * this function always gets rejected.\n\t *\n\t * @returns Promise rejection\n\t */\n\trename(): Promise<never> {\n\t\treturn Promise.reject(new Error('IndexedDB does not support renaming databases. Create a new database and migrate data manually.'));\n\t}\n\n\t/**\n\t * Getting a key by its index is not possible in this adapter, therefore this\n\t * function always gets rejected.\n\t *\n\t * @returns Promise rejection\n\t */\n\tkey(): Promise<never> {\n\t\treturn Promise.reject(new Error('IndexedDB does not support getting keys by index. Use keys() to get all keys.'));\n\t}\n\n\t/**\n\t * Return all keys stored in the space.\n\t *\n\t * @returns Promise resolving to array of keys\n\t */\n\tasync keys(): Promise<string[]> {\n\t\tawait this.open();\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst transaction = (this.storage as IDBDatabase)\n\t\t\t\t.transaction(this.store, 'readonly')\n\t\t\t\t.objectStore(this.store);\n\n\t\t\tconst op = transaction.getAllKeys();\n\n\t\t\top.addEventListener('success', (event) => {\n\t\t\t\tresolve((event.target as IDBRequest).result.map(String));\n\t\t\t}, false);\n\n\t\t\top.addEventListener('error', (event) => {\n\t\t\t\treject(new Error(`Failed to get keys: ${(event.target as IDBRequest).error?.message}`));\n\t\t\t}, false);\n\t\t});\n\t}\n\n\t/**\n\t * Delete a value from the space given its key\n\t *\n\t * @param key - Key of the item to delete\n\t * @returns Promise resolving to the value of the deleted object\n\t */\n\tasync remove(key: string): Promise<StorageValue> {\n\t\tconst value = await this.get(key);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst transaction = (this.storage as IDBDatabase)\n\t\t\t\t.transaction(this.store, 'readwrite')\n\t\t\t\t.objectStore(this.store);\n\n\t\t\tconst op = transaction.delete(key);\n\n\t\t\top.addEventListener('success', () => {\n\t\t\t\tresolve(value);\n\t\t\t}, false);\n\n\t\t\top.addEventListener('error', (event) => {\n\t\t\t\treject(new Error(`Failed to delete key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n\t\t\t}, false);\n\t\t});\n\t}\n\n\t/**\n\t * Clear the entire space\n\t *\n\t * @returns Promise for the clear operation\n\t */\n\tasync clear(): Promise<void> {\n\t\tawait this.open();\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst transaction = (this.storage as IDBDatabase)\n\t\t\t\t.transaction(this.store, 'readwrite')\n\t\t\t\t.objectStore(this.store);\n\n\t\t\tconst op = transaction.clear();\n\n\t\t\top.addEventListener('success', () => {\n\t\t\t\tresolve();\n\t\t\t}, false);\n\n\t\t\top.addEventListener('error', (event) => {\n\t\t\t\treject(new Error(`Failed to clear store: ${(event.target as IDBRequest).error?.message}`));\n\t\t\t}, false);\n\t\t});\n\t}\n}\n",
|
|
16
|
-
"/**\n * ==============================\n * Remote Storage Adapter\n * ==============================\n */\n\nimport { Request } from '../Request';\nimport type { RequestOptions } from '../Request';\nimport type { RemoteStorageConfiguration, StorageValue, KeyValueResult, SpaceAdapterInterface } from './types';\nimport { normalizeUrl } from './types';\n\n/**\n * Error thrown when a key is not found in storage\n */\nexport class KeyNotFoundError extends Error {\n
|
|
17
|
-
"/**\n * ==============================\n * Space\n * ==============================\n */\n\nimport { LocalStorage } from './SpaceAdapter/LocalStorage';\nimport { SessionStorage } from './SpaceAdapter/SessionStorage';\nimport { IndexedDB } from './SpaceAdapter/IndexedDB';\nimport { RemoteStorage } from './SpaceAdapter/RemoteStorage';\nimport type { SpaceConfiguration, StorageValue, KeyValueResult, UpgradeCallback, SpaceAdapterInterface } from './SpaceAdapter/types';\nimport { cloneValue } from './SpaceAdapter/types';\n\n/**\n * List of Adapters Available\n */\nexport const SpaceAdapter = {\n\tLocalStorage,\n\tSessionStorage,\n\tIndexedDB,\n\tRemoteStorage\n};\n\n/**\n * Space adapter type (any of the available adapters)\n */\nexport type SpaceAdapterType = SpaceAdapterInterface;\n\nexport type SpaceAdapterConstructor = typeof LocalStorage | typeof SessionStorage | typeof IndexedDB | typeof RemoteStorage;\n\n/**\n * Callback function type for space events\n */\nexport type SpaceCallback = (key: string, value: StorageValue) => void;\n\n/**\n * Transformation function type\n */\nexport type TransformationFunction = (key: string, value: StorageValue) => StorageValue;\n\n/**\n * Transformation configuration\n */\nexport interface Transformation {\n\tid: string;\n\tget?: TransformationFunction | null;\n\tset?: TransformationFunction | null;\n}\n\n/**\n * Space provides a simple wrapper for different Storage APIs. It aims to\n * provide data independence through storage namespaces and versioning, allowing\n * transparent data formatting and content modifications through versions.\n */\nexport class Space {\n\tprivate _configuration: SpaceConfiguration;\n\tpublic adapter: SpaceAdapterType;\n\tpublic callbacks: {\n\t\tcreate: SpaceCallback[];\n\t\tupdate: SpaceCallback[];\n\t\tdelete: SpaceCallback[];\n\t};\n\tpublic transformations: Record<string, Transformation>;\n\n\t/**\n\t * Create a new Space Object. If no name and version is defined, the global\n\t * LocalSpace space is used.\n\t *\n\t * @param adapter - Space Adapter to use\n\t * @param configuration - Configuration object for the space\n\t */\n\tconstructor(adapter: SpaceAdapterConstructor = SpaceAdapter.LocalStorage, configuration: SpaceConfiguration = {}) {\n\t\t// Assign the provided configuration to the default one\n\t\tthis._configuration = { name: '', version: '', store: '', ...configuration };\n\n\t\t// Set up the adapter instance to use\n\t\tthis.adapter = new adapter(this._configuration);\n\n\t\t// This object stores all the callbacks the user can define for the space operations\n\t\tthis.callbacks = {\n\t\t\tcreate: [],\n\t\t\tupdate: [],\n\t\t\tdelete: []\n\t\t};\n\n\t\t// A transformation is an object that can contain set and get functions\n\t\tthis.transformations = {};\n\t}\n\n\t/**\n\t * Modify the space configuration, it will also be passed down to the adapter\n\t * using its configuration() function.\n\t *\n\t * @param object - Configuration object to set up\n\t * @returns Configuration object if no param was passed\n\t */\n\tconfiguration(object: SpaceConfiguration | null = null): SpaceConfiguration | undefined {\n\t\tif (object !== null) {\n\t\t\tthis._configuration = { ...this._configuration, ...object };\n\t\t\tif (this.adapter.configuration) {\n\t\t\t\tthis.adapter.configuration(object);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t} else {\n\t\t\treturn this._configuration;\n\t\t}\n\t}\n\n\t/**\n\t * Open the Storage Object to be used depending on the SpaceAdapter\n\t *\n\t * @returns Promise resolving to this Space\n\t */\n\tasync open(): Promise<this> {\n\t\tawait this.adapter.open();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Apply set transformations to a value\n\t *\n\t * @param key - The key being set\n\t * @param value - The value to transform\n\t * @returns The transformed value\n\t */\n\tprivate applySetTransformations(key: string, value: StorageValue): StorageValue {\n\t\tlet transformedValue = cloneValue(value);\n\t\tfor (const transformation of Object.values(this.transformations)) {\n\t\t\tif (typeof transformation.set === 'function') {\n\t\t\t\ttransformedValue = transformation.set(key, transformedValue);\n\t\t\t}\n\t\t}\n\t\treturn transformedValue;\n\t}\n\n\t/**\n\t * Apply get transformations to a value\n\t *\n\t * @param key - The key being retrieved\n\t * @param value - The value to transform\n\t * @returns The transformed value\n\t */\n\tprivate applyGetTransformations(key: string, value: StorageValue): StorageValue {\n\t\tlet transformedValue = value;\n\t\tfor (const transformation of Object.values(this.transformations)) {\n\t\t\tif (typeof transformation.get === 'function') {\n\t\t\t\ttransformedValue = transformation.get(key, transformedValue);\n\t\t\t}\n\t\t}\n\t\treturn transformedValue;\n\t}\n\n\t/**\n\t * Store a key-value pair\n\t *\n\t * @param key - Key with which this value will be saved\n\t * @param value - Value to save\n\t * @returns Promise with key and value\n\t */\n\tasync set(key: string, value: StorageValue): Promise<KeyValueResult> {\n\t\tconst transformedValue = this.applySetTransformations(key, value);\n\t\tconst result = await this.adapter.set(key, transformedValue);\n\t\tfor (const callback of this.callbacks.create) {\n\t\t\tcallback.call(null, result.key, result.value);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Update a key-value pair. In difference with the set() method, the update\n\t * method will use Object.assign() in the case of objects so no value is lost.\n\t *\n\t * @param key - Key with which this value will be saved\n\t * @param value - Value to save\n\t * @returns Promise with key and value\n\t */\n\tasync update(key: string, value: StorageValue): Promise<KeyValueResult> {\n\t\tconst transformedValue = this.applySetTransformations(key, value);\n\t\tconst result = await this.adapter.update(key, transformedValue);\n\t\tfor (const callback of this.callbacks.update) {\n\t\t\tcallback.call(null, result.key, result.value);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Retrieves a value from storage given its key\n\t *\n\t * @param key - Key with which the value was saved\n\t * @returns Promise resolving to the retrieved value\n\t */\n\tasync get(key: string): Promise<StorageValue> {\n\t\tconst value = await this.adapter.get(key);\n\t\treturn this.applyGetTransformations(key, value);\n\t}\n\n\t/**\n\t * Retrieves all the values in the space in a key-value JSON object\n\t *\n\t * @returns Promise resolving to all values\n\t */\n\tasync getAll(): Promise<Record<string, StorageValue>> {\n\t\tconst values = await this.adapter.getAll();\n\t\tconst transformedValues: Record<string, StorageValue> = {};\n\n\t\tfor (const key of Object.keys(values)) {\n\t\t\ttransformedValues[key] = this.applyGetTransformations(key, values[key]);\n\t\t}\n\n\t\treturn transformedValues;\n\t}\n\n\t/**\n\t * Iterate over every value in the space\n\t *\n\t * @param callback - A callback function receiving the key and value\n\t * @returns Promise resolving when all callbacks have been resolved\n\t */\n\tasync each(callback: (key: string, value: StorageValue) => unknown): Promise<unknown[]> {\n\t\tconst values = await this.getAll();\n\t\tconst promises: unknown[] = [];\n\t\tfor (const [key, value] of Object.entries(values)) {\n\t\t\tpromises.push(callback.call(this, key, value));\n\t\t}\n\t\treturn Promise.all(promises);\n\t}\n\n\t/**\n\t * Check if a space contains a given key. Not all adapters may give this information\n\t *\n\t * @param key - Key to look for\n\t * @returns Promise that resolves if key exists\n\t */\n\tcontains(key: string): Promise<void> {\n\t\treturn this.adapter.contains(key);\n\t}\n\n\t/**\n\t * Upgrade a Space Version. Not all adapters may provide this functionality\n\t *\n\t * @param oldVersion - The version of the storage to be upgraded\n\t * @param newVersion - The version to be upgraded to\n\t * @param callback - Function to transform the old stored values\n\t * @returns Promise for the upgrade operation\n\t */\n\tasync upgrade(oldVersion: string, newVersion: string, callback: UpgradeCallback): Promise<this> {\n\t\tawait this.adapter.upgrade(oldVersion, newVersion, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Rename a Space. Not all adapters may provide this functionality\n\t *\n\t * @param name - New name to be used\n\t * @returns Promise for the rename operation\n\t */\n\trename(name: string): Promise<void> {\n\t\treturn this.adapter.rename(name);\n\t}\n\n\t/**\n\t * Add a callback function to be run every time a value is created.\n\t *\n\t * @param callback - Callback Function. Key and Value pair will be sent as parameters.\n\t */\n\tonCreate(callback: SpaceCallback): void {\n\t\tthis.callbacks.create.push(callback);\n\t}\n\n\t/**\n\t * Add a callback function to be run every time a value is updated.\n\t *\n\t * @param callback - Callback Function. Key and Value pair will be sent as parameters.\n\t */\n\tonUpdate(callback: SpaceCallback): void {\n\t\tthis.callbacks.update.push(callback);\n\t}\n\n\t/**\n\t * Add a callback function to be run every time a value is deleted.\n\t *\n\t * @param callback - Callback Function. Key and Value pair will be sent as parameters.\n\t */\n\tonDelete(callback: SpaceCallback): void {\n\t\tthis.callbacks.delete.push(callback);\n\t}\n\n\t/**\n\t * Add a transformation function to the space.\n\t *\n\t * @param transformation - Transformation configuration with id, get, and set functions\n\t */\n\taddTransformation({ id, get, set }: Transformation): void {\n\t\tthis.transformations[id] = { id, get, set };\n\t}\n\n\t/**\n\t * Remove a transformation function given its id\n\t *\n\t * @param id - Name or identifier of the transformation to remove\n\t */\n\tremoveTransformation(id: string): void {\n\t\tdelete this.transformations[id];\n\t}\n\n\t/**\n\t * Get the key that corresponds to a given index in the storage.\n\t * Not all adapters may provide this functionality\n\t *\n\t * @param index - Index to get the key from\n\t * @param full - Whether to return the full key name including space id\n\t * @returns Promise resolving to the key's name\n\t */\n\tkey(index: number, full: boolean = false): Promise<string> {\n\t\treturn this.adapter.key(index, full);\n\t}\n\n\t/**\n\t * Return all keys stored in the space. Not all adapters may provide this functionality\n\t *\n\t * @param full - Whether to return the full key name including space id\n\t * @returns Promise resolving to array of keys\n\t */\n\tkeys(full: boolean = false): Promise<string[]> {\n\t\treturn this.adapter.keys(full);\n\t}\n\n\t/**\n\t * Delete a value from the space given its key\n\t *\n\t * @param key - Key of the item to delete\n\t * @returns Promise that resolves after deletion\n\t */\n\tasync remove(key: string): Promise<void> {\n\t\tconst value = await this.adapter.remove(key);\n\t\t// Run the callback for deletions\n\t\tfor (const callback of this.callbacks.delete) {\n\t\t\tcallback.call(null, key, value);\n\t\t}\n\t}\n\n\t/**\n\t * Clear the entire space\n\t *\n\t * @returns Promise for the clear operation\n\t */\n\tclear(): Promise<void> {\n\t\treturn this.adapter.clear();\n\t}\n}\n\n// Re-export adapter types\nexport { LocalStorage } from './SpaceAdapter/LocalStorage';\nexport { SessionStorage } from './SpaceAdapter/SessionStorage';\nexport { IndexedDB } from './SpaceAdapter/IndexedDB';\nexport { RemoteStorage } from './SpaceAdapter/RemoteStorage';\nexport type { SpaceConfiguration, StorageValue, KeyValueResult, UpgradeCallback } from './SpaceAdapter/types';\n",
|
|
12
|
+
"/**\n * ==============================\n * Space Adapter Types\n * ==============================\n */\n\n/**\n * Base configuration for all space adapters\n */\nexport interface SpaceConfiguration {\n name?: string;\n version?: string;\n store?: string;\n}\n\n/**\n * LocalStorage/SessionStorage configuration\n */\nexport type LocalStorageConfiguration = SpaceConfiguration;\n\n/**\n * IndexedDB configuration with additional options\n */\nexport interface IndexedDBConfiguration extends SpaceConfiguration {\n props?: IDBObjectStoreParameters;\n index?: Record<string, {\n name: string;\n field: string;\n props?: IDBIndexParameters;\n }>;\n}\n\n/**\n * RemoteStorage configuration\n */\nexport interface RemoteStorageConfiguration extends SpaceConfiguration {\n endpoint?: string;\n props?: Record<string, unknown>;\n}\n\n/**\n * Generic storage value type\n */\nexport type StorageValue = unknown;\n\n/**\n * Key-value result type\n */\nexport interface KeyValueResult {\n key: string;\n value: StorageValue;\n}\n\n/**\n * Upgrade callback function type\n */\nexport type UpgradeCallback<T = unknown> = (adapter: T, event?: IDBVersionChangeEvent) => Promise<void>;\n\n/**\n * Base interface for all space adapters\n */\nexport interface SpaceAdapterInterface {\n name: string;\n version: string;\n store: string;\n\n open(): Promise<this>;\n set(key: string | null, value: StorageValue): Promise<KeyValueResult>;\n update(key: string, value: StorageValue): Promise<KeyValueResult>;\n get(key: string): Promise<StorageValue>;\n getAll(): Promise<Record<string, StorageValue>>;\n contains(key: string): Promise<void>;\n upgrade(oldVersion: string, newVersion: string, callback: UpgradeCallback): Promise<void>;\n rename(name: string): Promise<void>;\n key(index: number, full?: boolean): Promise<string>;\n keys(full?: boolean): Promise<string[]>;\n remove(key: string): Promise<StorageValue>;\n clear(): Promise<void>;\n configuration?(config: SpaceConfiguration): void;\n}\n\n/**\n * Space adapter constructor type\n */\nexport type SpaceAdapterConstructor = new (config: SpaceConfiguration) => SpaceAdapterInterface;\n\n/**\n * Convert a version string to a numeric value for comparison.\n * Each segment is padded to 5 digits to support versions up to 99999.x.x\n *\n * @param version - Version string (e.g., \"1.0.0\", \"10.2.15\")\n * @returns Numeric version for comparison\n */\nexport function versionToNumber(version: string): number {\n if (version === '') {\n return 0;\n }\n\n const segments = version.split('.');\n let result = 0;\n const multipliers = [1000000000000, 100000000, 10000]; // Support up to 4 segments\n\n for (let i = 0; i < Math.min(segments.length, multipliers.length); i++) {\n const segment = parseInt(segments[i], 10) || 0;\n result += segment * multipliers[i];\n }\n\n return result;\n}\n\n/**\n * Compare two version strings\n *\n * @param v1 - First version string\n * @param v2 - Second version string\n * @returns -1 if v1 < v2, 0 if v1 === v2, 1 if v1 > v2\n */\nexport function compareVersions(v1: string, v2: string): number {\n const n1 = versionToNumber(v1);\n const n2 = versionToNumber(v2);\n\n if (n1 < n2) return -1;\n if (n1 > n2) return 1;\n return 0;\n}\n\n/**\n * Deep clone a value to prevent mutation\n *\n * @param value - Value to clone\n * @returns Cloned value\n */\nexport function cloneValue<T>(value: T): T {\n if (value === null || typeof value !== 'object') {\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => cloneValue(item)) as T;\n }\n\n const cloned: Record<string, unknown> = {};\n for (const key of Object.keys(value as object)) {\n cloned[key] = cloneValue((value as Record<string, unknown>)[key]);\n }\n return cloned as T;\n}\n\n/**\n * Normalize a URL by ensuring proper slash handling\n *\n * @param base - Base URL\n * @param path - Path to append\n * @returns Normalized URL\n */\nexport function normalizeUrl(base: string, path: string): string {\n const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n return `${normalizedBase}${normalizedPath}`;\n}\n",
|
|
13
|
+
"/**\n * ==============================\n * Local Storage Adapter\n * ==============================\n */\n\nimport type { LocalStorageConfiguration, StorageValue, KeyValueResult, UpgradeCallback, SpaceAdapterInterface } from './types';\nimport { versionToNumber } from './types';\n\n/**\n * Error thrown when a key is not found in storage\n */\nexport class KeyNotFoundError extends Error {\n constructor(key: string) {\n super(`Key \"${key}\" not found in storage`);\n this.name = 'KeyNotFoundError';\n }\n}\n\n/**\n * The Local Storage Adapter provides the Space Class the ability to interact\n * with the localStorage API found in most modern browsers.\n */\nexport class LocalStorage implements SpaceAdapterInterface {\n public name: string;\n public version: string;\n public store: string;\n public id: string;\n public numericVersion: number;\n public upgrades: Record<string, UpgradeCallback<LocalStorage>>;\n public storage: Storage | undefined;\n private _openPromise: Promise<this> | undefined;\n\n /**\n * Create a new LocalStorage. If no configuration is provided, the LocalStorage\n * global object is used. The LocalStorage Adapter can provide independency\n * by store name and space name.\n *\n * @param configuration - Configuration Object for the Adapter\n */\n constructor({ name = '', version = '', store = '' }: LocalStorageConfiguration) {\n this.name = name;\n this.version = version;\n this.store = store;\n this.upgrades = {};\n\n this.numericVersion = versionToNumber(version);\n this.id = this.computeId();\n }\n\n /**\n * Compute the storage ID based on current name, version, and store\n *\n * @returns The computed ID string\n */\n private computeId(): string {\n if (this.name !== '' && this.version !== '' && this.store !== '') {\n return `${this.name}::${this.store}::${this.version}_`;\n } else if (this.name !== '' && this.version !== '') {\n return `${this.name}::${this.version}_`;\n } else if (this.name !== '') {\n return `${this.name}::_`;\n } else {\n return '';\n }\n }\n\n /**\n * Modify the configuration\n *\n * @param config - Configuration object to set up\n */\n configuration(config: LocalStorageConfiguration): void {\n if (config.name !== undefined) this.name = config.name;\n if (config.version !== undefined) {\n this.version = config.version;\n this.numericVersion = versionToNumber(config.version);\n }\n if (config.store !== undefined) this.store = config.store;\n\n // Recalculate the ID after configuration changes\n this.id = this.computeId();\n }\n\n /**\n * Open the Storage Object\n *\n * @returns Promise resolving to this adapter\n */\n async open(): Promise<this> {\n // Already opened\n if (this.storage instanceof Storage) {\n return this;\n }\n\n // Currently opening - wait for it\n if (this._openPromise) {\n return this._openPromise;\n }\n\n // Start opening\n this._openPromise = (async () => {\n let upgradesToApply: string[] = [];\n\n // Check if this space is versioned\n if (this.version !== '') {\n // Get the versionless part of the ID\n let versionless = '';\n if (this.name !== '' && this.version !== '' && this.store !== '') {\n versionless = `${this.name}::${this.store}::`;\n } else if (this.name !== '' && this.version !== '') {\n versionless = `${this.name}::`;\n }\n\n // Get all the currently stored keys that contain the versionless ID\n const storedVersions = Object.keys(window.localStorage).filter((key) => {\n return key.indexOf(versionless) === 0;\n }).map((key) => {\n return key.replace(versionless, '').split('_')[0];\n }).filter((key) => {\n return key.indexOf('::') === -1;\n }).sort();\n\n if (storedVersions.length > 0) {\n const oldVersion = storedVersions[0];\n const oldVersionNumeric = versionToNumber(oldVersion);\n\n if (oldVersionNumeric < this.numericVersion) {\n const availableUpgrades = Object.keys(this.upgrades).sort((a, b) => {\n const [aOld] = a.split('::').map(Number);\n const [bOld] = b.split('::').map(Number);\n return aOld - bOld;\n });\n\n const startFrom = availableUpgrades.findIndex((u) => {\n const [old] = u.split('::');\n return parseInt(old) === oldVersionNumeric;\n });\n\n if (startFrom > -1) {\n upgradesToApply = availableUpgrades.slice(startFrom).filter((u) => {\n const [old, next] = u.split('::');\n return parseInt(old) < this.numericVersion && parseInt(next) <= this.numericVersion;\n });\n }\n\n // Get the previous ID using the old version\n let previousId = `${this.name}::${oldVersion}_`;\n\n if (this.name !== '' && this.version !== '' && this.store !== '') {\n previousId = `${this.name}::${this.store}::${oldVersion}_`;\n } else if (this.name !== '' && this.version !== '') {\n previousId = `${this.name}::${oldVersion}_`;\n }\n\n // Get all keys from the previous version\n const keys = Object.keys(window.localStorage).filter((key) => {\n return key.indexOf(previousId) === 0;\n }).map((key) => {\n return key.replace(previousId, '');\n });\n\n for (const key of keys) {\n const previous = window.localStorage.getItem(`${previousId}${key}`);\n if (previous !== null) {\n window.localStorage.setItem(this.id + key, previous);\n }\n window.localStorage.removeItem(`${previousId}${key}`);\n }\n }\n }\n }\n\n this.storage = window.localStorage;\n\n // Apply upgrades\n for (const upgradeKey of upgradesToApply) {\n try {\n await this.upgrades[upgradeKey].call(this, this);\n } catch (e) {\n console.error(e);\n }\n }\n\n return this;\n })();\n\n try {\n return await this._openPromise;\n } finally {\n this._openPromise = undefined;\n }\n }\n\n /**\n * Store a key-value pair\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and value\n */\n async set(key: string, value: StorageValue): Promise<KeyValueResult> {\n await this.open();\n if (typeof value === 'object') {\n (this.storage as Storage).setItem(this.id + key, JSON.stringify(value));\n } else {\n (this.storage as Storage).setItem(this.id + key, String(value));\n }\n return { key, value };\n }\n\n /**\n * Update a key-value pair. The update method will use Object.assign()\n * in the case of objects so no value is lost.\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and value\n */\n async update(key: string, value: StorageValue): Promise<KeyValueResult> {\n try {\n const currentValue = await this.get(key);\n if (typeof currentValue === 'object' && currentValue !== null) {\n if (typeof value === 'object' && value !== null) {\n value = { ...(currentValue as object), ...(value as object) };\n }\n (this.storage as Storage).setItem(this.id + key, JSON.stringify(value));\n } else {\n (this.storage as Storage).setItem(this.id + key, String(value));\n }\n return { key, value };\n } catch {\n return this.set(key, value);\n }\n }\n\n /**\n * Retrieves a value from storage given its key\n *\n * @param key - Key with which the value was saved\n * @returns Promise resolving to the retrieved value\n */\n async get(key: string): Promise<StorageValue> {\n await this.open();\n const rawValue = (this.storage as Storage).getItem(this.id + key);\n\n if (rawValue === null) {\n throw new KeyNotFoundError(key);\n }\n\n try {\n const parsed = JSON.parse(rawValue);\n if (parsed && typeof parsed === 'object') {\n return parsed;\n }\n return rawValue;\n } catch {\n // Unable to parse to JSON, return raw value\n return rawValue;\n }\n }\n\n /**\n * Retrieves all the values in the space in a key-value JSON object\n *\n * @returns Promise resolving to all values\n */\n async getAll(): Promise<Record<string, StorageValue>> {\n const keys = await this.keys();\n const values: Record<string, StorageValue> = {};\n\n for (const key of keys) {\n try {\n values[key] = await this.get(key);\n } catch {\n // Skip keys that fail to retrieve\n }\n }\n\n return values;\n }\n\n /**\n * Check if the space contains a given key.\n *\n * @param key - Key to look for\n * @returns Promise that resolves if key exists\n */\n async contains(key: string): Promise<void> {\n const keys = await this.keys();\n if (keys.includes(key)) {\n return;\n } else {\n throw new KeyNotFoundError(key);\n }\n }\n\n /**\n * Upgrade a Space Version\n *\n * @param oldVersion - The version of the storage to be upgraded\n * @param newVersion - The version to be upgraded to\n * @param callback - Function to transform the old stored values\n * @returns Promise\n */\n async upgrade(oldVersion: string, newVersion: string, callback: UpgradeCallback<LocalStorage>): Promise<void> {\n const key = `${versionToNumber(oldVersion)}::${versionToNumber(newVersion)}`;\n this.upgrades[key] = callback;\n return Promise.resolve();\n }\n\n /**\n * Rename a Space\n *\n * @param name - New name to be used\n * @returns Promise for the rename operation\n */\n async rename(name: string): Promise<void> {\n if (this.name === name) {\n throw new Error('Cannot rename: new name is identical to current name');\n }\n\n const keys = await this.keys();\n const oldId = this.id;\n this.name = name;\n this.id = this.computeId();\n\n for (const key of keys) {\n const rawValue = (this.storage as Storage).getItem(`${oldId}${key}`);\n if (rawValue !== null) {\n // Directly copy the raw value to avoid double-encoding\n (this.storage as Storage).setItem(this.id + key, rawValue);\n (this.storage as Storage).removeItem(`${oldId}${key}`);\n }\n }\n }\n\n /**\n * Get the key that corresponds to a given index in the storage.\n * Only considers keys belonging to this space.\n *\n * @param index - Index to get the key from\n * @param full - Whether to return the full key name including space id\n * @returns Promise resolving to the key's name\n */\n async key(index: number, full: boolean = false): Promise<string> {\n const spaceKeys = await this.keys(full);\n\n if (index < 0 || index >= spaceKeys.length) {\n throw new Error(`Index ${index} out of bounds. Space has ${spaceKeys.length} keys.`);\n }\n\n return spaceKeys[index];\n }\n\n /**\n * Return all keys stored in the space.\n *\n * @param full - Whether to return the full key name including space id\n * @returns Promise resolving to array of keys\n */\n async keys(full: boolean = false): Promise<string[]> {\n await this.open();\n return Object.keys(this.storage as Storage).filter((key) => {\n return key.indexOf(this.id) === 0;\n }).map((key) => {\n if (full === true) {\n return key;\n } else {\n return key.replace(this.id, '');\n }\n });\n }\n\n /**\n * Delete a value from the space given its key\n *\n * @param key - Key of the item to delete\n * @returns Promise resolving to the value of the deleted object\n */\n async remove(key: string): Promise<StorageValue> {\n const value = await this.get(key);\n (this.storage as Storage).removeItem(this.id + key);\n return value;\n }\n\n /**\n * Clear the entire space\n *\n * @returns Promise for the clear operation\n */\n async clear(): Promise<void> {\n const keys = await this.keys();\n\n for (const key of keys) {\n (this.storage as Storage).removeItem(this.id + key);\n }\n }\n}\n",
|
|
14
|
+
"/**\n * ==============================\n * Session Storage Adapter\n * ==============================\n */\n\nimport { LocalStorage } from './LocalStorage';\nimport type { LocalStorageConfiguration, UpgradeCallback } from './types';\n\n/**\n * The Session Storage Adapter provides the Space Class the ability to interact\n * with the sessionStorage API found in most modern browsers. Since this API\n * shares pretty much the same methods as the local storage one, this class\n * inherits from the LocalStorage adapter.\n *\n * Note: SessionStorage does not support versioning and upgrades because session\n * data is inherently temporary and cleared when the browser session ends.\n * Any declared upgrades will be ignored.\n */\nexport class SessionStorage extends LocalStorage {\n /**\n * Create a new SessionStorage. If no configuration is provided, the SessionStorage\n * global object is used. The SessionStorage Adapter can provide independency\n * by store name and space name.\n *\n * Note: Version is accepted for API compatibility but upgrades are not supported.\n *\n * @param configuration - Configuration Object for the Adapter\n */\n constructor({ name = '', version = '', store = '' }: LocalStorageConfiguration) {\n super({ name, version, store });\n }\n\n /**\n * Open the Storage Object.\n *\n * Unlike LocalStorage, SessionStorage does not perform upgrade migrations\n * because session data is temporary and cleared when the session ends.\n *\n * @returns Promise resolving to this adapter\n */\n async open(): Promise<this> {\n if (this.storage instanceof Storage) {\n return this;\n }\n\n this.storage = window.sessionStorage;\n return this;\n }\n\n /**\n * Upgrade is not supported for SessionStorage.\n * Session data is temporary and should not require migrations.\n *\n * @param _oldVersion - Ignored\n * @param _newVersion - Ignored\n * @param _callback - Ignored\n * @returns Promise that resolves immediately (no-op)\n */\n async upgrade(_oldVersion: string, _newVersion: string, _callback: UpgradeCallback<SessionStorage>): Promise<void> {\n console.warn('SessionStorage.upgrade() is a no-op. Session data is temporary and does not support migrations.');\n return Promise.resolve();\n }\n}\n",
|
|
15
|
+
"/**\n * ==============================\n * IndexedDB Adapter\n * ==============================\n */\n\nimport type { IndexedDBConfiguration, StorageValue, KeyValueResult, UpgradeCallback, SpaceAdapterInterface } from './types';\nimport { versionToNumber } from './types';\n\n/**\n * Error thrown when a key is not found in storage\n */\nexport class KeyNotFoundError extends Error {\n constructor(key: string) {\n super(`Key \"${key}\" not found in IndexedDB`);\n this.name = 'KeyNotFoundError';\n }\n}\n\n/**\n * The IndexedDB Adapter provides the Space Class the ability to interact\n * with the IndexedDB API found in most modern browsers.\n */\nexport class IndexedDB implements SpaceAdapterInterface {\n public name: string;\n public version: string;\n public store: string;\n public props: IDBObjectStoreParameters;\n public index: Record<string, { name: string; field: string; props?: IDBIndexParameters }>;\n public keyPath: string;\n public numericVersion: number;\n public upgrades: Record<string, UpgradeCallback<IndexedDB>>;\n public storage: IDBDatabase | Promise<IDBDatabase> | undefined;\n\n /**\n * Create a new IndexedDB. Differently from Local and Session Storages, the\n * IndexedDB Adapter requires a mandatory name, version and store name.\n *\n * @param configuration - Configuration Object for the Adapter\n */\n constructor({ name = '', version = '', store = '', props = {}, index = {} }: IndexedDBConfiguration) {\n this.name = name;\n this.version = version;\n this.store = store;\n this.props = props || {};\n this.index = index;\n\n this.keyPath = (props?.keyPath as string) || 'id';\n this.upgrades = {};\n\n this.numericVersion = versionToNumber(version);\n }\n\n /**\n * Modify the configuration\n *\n * @param config - Configuration object to set up\n */\n configuration(config: IndexedDBConfiguration): void {\n if (config.name !== undefined) this.name = config.name;\n if (config.version !== undefined) {\n this.version = config.version;\n this.numericVersion = versionToNumber(config.version);\n }\n if (config.store !== undefined) this.store = config.store;\n }\n\n /**\n * Open the Storage Object\n *\n * @returns Promise resolving to this adapter\n */\n async open(): Promise<this> {\n if (this.name === '') {\n throw new Error('IndexedDB requires a name. No name has been defined for this space.');\n }\n\n if (this.store === '') {\n throw new Error('IndexedDB requires a store name. No store has been defined for this space.');\n }\n\n if (this.storage instanceof IDBDatabase) {\n return this;\n } else if (this.storage instanceof Promise) {\n return await (this.storage as unknown as Promise<this>);\n } else {\n const openTask = (async () => {\n let upgradeEvent: IDBVersionChangeEvent | undefined;\n let upgradesToApply: string[] = [];\n\n const db = await new Promise<IDBDatabase>((resolve, reject) => {\n const request = window.indexedDB.open(this.name, this.numericVersion);\n\n request.onerror = (event) => {\n reject(new Error(`Failed to open IndexedDB \"${this.name}\": ${(event.target as IDBOpenDBRequest).error?.message}`));\n };\n\n request.onsuccess = (event) => {\n resolve((event.target as IDBOpenDBRequest).result);\n };\n\n request.onupgradeneeded = (event: IDBVersionChangeEvent) => {\n upgradeEvent = event;\n const db = (event.target as IDBOpenDBRequest).result;\n\n if (event.oldVersion < 1) {\n // Create all the needed Stores\n const store = db.createObjectStore(this.store, this.props);\n for (const indexKey of Object.keys(this.index)) {\n const idx = this.index[indexKey];\n store.createIndex(idx.name, idx.field, idx.props);\n }\n } else {\n // Check what upgrade functions have been declared\n const availableUpgrades = Object.keys(this.upgrades).sort((a, b) => {\n const [aOld] = a.split('::').map(Number);\n const [bOld] = b.split('::').map(Number);\n return aOld - bOld;\n });\n\n const startFrom = availableUpgrades.findIndex((u) => {\n const [old] = u.split('::');\n return parseInt(old) === event.oldVersion;\n });\n\n if (startFrom > -1) {\n upgradesToApply = availableUpgrades.slice(startFrom).filter((u) => {\n const [old, next] = u.split('::');\n return parseInt(old) < this.numericVersion && parseInt(next) <= this.numericVersion;\n });\n }\n }\n\n // Once the transaction is done, resolve the storage object\n const transaction = (event.target as IDBOpenDBRequest).transaction;\n if (transaction) {\n transaction.addEventListener('complete', () => {\n // Transaction completed\n });\n }\n };\n });\n\n this.storage = db;\n\n // Apply upgrades\n for (const upgradeKey of upgradesToApply) {\n try {\n await this.upgrades[upgradeKey].call(this, this, upgradeEvent);\n } catch (e) {\n console.error(e);\n }\n }\n\n return this;\n })();\n\n this.storage = openTask as unknown as Promise<IDBDatabase>;\n return await openTask;\n }\n }\n\n /**\n * Store a key-value pair. Because of the nature of IndexedDB,\n * stored values must be JSON objects.\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and value\n */\n async set(key: string | null = null, value: StorageValue): Promise<KeyValueResult> {\n await this.open();\n return new Promise((resolve, reject) => {\n const transaction = (this.storage as IDBDatabase)\n .transaction(this.store, 'readwrite')\n .objectStore(this.store);\n\n let op: IDBRequest;\n\n if (key !== null) {\n const temp: Record<string, unknown> = {};\n\n temp[this.keyPath] = key;\n op = transaction.put({ ...temp, ...(value as object) });\n } else {\n op = transaction.add(value);\n }\n\n op.addEventListener('success', (event) => {\n resolve({ key: String((event.target as IDBRequest).result), value });\n });\n\n op.addEventListener('error', (event) => {\n reject(new Error(`Failed to set key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n });\n });\n }\n\n /**\n * Update a key-value pair. The update method will use Object.assign()\n * in the case of objects so no value is lost.\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and value\n */\n async update(key: string, value: StorageValue): Promise<KeyValueResult> {\n try {\n const currentValue = await this.get(key);\n\n if (typeof currentValue === 'undefined') {\n return this.set(key, value);\n }\n\n return new Promise((resolve, reject) => {\n const transaction = (this.storage as IDBDatabase)\n .transaction(this.store, 'readwrite')\n .objectStore(this.store);\n\n const op = transaction.put({ ...(currentValue as object), ...(value as object) });\n\n op.addEventListener('success', (event) => {\n resolve({ key: String((event.target as IDBRequest).result), value });\n });\n\n op.addEventListener('error', (event) => {\n reject(new Error(`Failed to update key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n });\n });\n } catch {\n return this.set(key, value);\n }\n }\n\n /**\n * Retrieves a value from storage given its key\n *\n * @param key - Key with which the value was saved\n * @returns Promise resolving to the retrieved value\n */\n async get(key: string): Promise<StorageValue> {\n await this.open();\n return new Promise((resolve, reject) => {\n const transaction = (this.storage as IDBDatabase)\n .transaction(this.store, 'readonly')\n .objectStore(this.store);\n\n const op = transaction.get(key);\n\n op.addEventListener('success', (event) => {\n const value = (event.target as IDBRequest).result;\n if (typeof value !== 'undefined' && value !== null) {\n resolve(value);\n } else {\n reject(new KeyNotFoundError(key));\n }\n });\n\n op.addEventListener('error', (event) => {\n reject(new Error(`Failed to get key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n });\n });\n }\n\n /**\n * Retrieves all the values in the space in a key-value JSON object.\n * Note: The keyPath property is preserved in the returned items.\n *\n * @returns Promise resolving to all values\n */\n async getAll(): Promise<Record<string, StorageValue>> {\n await this.open();\n return new Promise((resolve, reject) => {\n const transaction = (this.storage as IDBDatabase)\n .transaction(this.store, 'readonly')\n .objectStore(this.store);\n\n const op = transaction.getAll();\n\n op.addEventListener('success', (event) => {\n const results: Record<string, StorageValue> = {};\n const items = (event.target as IDBRequest).result as Record<string, unknown>[];\n\n items.forEach((item) => {\n const id = item[this.keyPath] as string;\n // Create a shallow copy to avoid mutating the original item\n const itemCopy = { ...item };\n delete itemCopy[this.keyPath];\n results[id] = itemCopy;\n });\n\n resolve(results);\n });\n\n op.addEventListener('error', (event) => {\n reject(new Error(`Failed to get all items: ${(event.target as IDBRequest).error?.message}`));\n });\n });\n }\n\n /**\n * Check if the space contains a given key.\n *\n * @param key - Key to look for\n * @returns Promise that resolves if key exists\n */\n async contains(key: string): Promise<void> {\n await this.get(key);\n }\n\n /**\n * Upgrade a Space Version. Upgrades must be declared before the open()\n * method is executed.\n *\n * @param oldVersion - The version to be upgraded\n * @param newVersion - The version to be upgraded to\n * @param callback - Function to transform the old stored values\n * @returns Promise\n */\n async upgrade(oldVersion: string, newVersion: string, callback: UpgradeCallback<IndexedDB>): Promise<void> {\n const key = `${versionToNumber(oldVersion)}::${versionToNumber(newVersion)}`;\n this.upgrades[key] = callback;\n return Promise.resolve();\n }\n\n /**\n * Renaming the space is not possible with the IndexedDB adapter therefore\n * this function always gets rejected.\n *\n * @returns Promise rejection\n */\n rename(): Promise<never> {\n return Promise.reject(new Error('IndexedDB does not support renaming databases. Create a new database and migrate data manually.'));\n }\n\n /**\n * Getting a key by its index is not possible in this adapter, therefore this\n * function always gets rejected.\n *\n * @returns Promise rejection\n */\n key(): Promise<never> {\n return Promise.reject(new Error('IndexedDB does not support getting keys by index. Use keys() to get all keys.'));\n }\n\n /**\n * Return all keys stored in the space.\n *\n * @returns Promise resolving to array of keys\n */\n async keys(): Promise<string[]> {\n await this.open();\n return new Promise((resolve, reject) => {\n const transaction = (this.storage as IDBDatabase)\n .transaction(this.store, 'readonly')\n .objectStore(this.store);\n\n const op = transaction.getAllKeys();\n\n op.addEventListener('success', (event) => {\n resolve((event.target as IDBRequest).result.map(String));\n }, false);\n\n op.addEventListener('error', (event) => {\n reject(new Error(`Failed to get keys: ${(event.target as IDBRequest).error?.message}`));\n }, false);\n });\n }\n\n /**\n * Delete a value from the space given its key\n *\n * @param key - Key of the item to delete\n * @returns Promise resolving to the value of the deleted object\n */\n async remove(key: string): Promise<StorageValue> {\n const value = await this.get(key);\n return new Promise((resolve, reject) => {\n const transaction = (this.storage as IDBDatabase)\n .transaction(this.store, 'readwrite')\n .objectStore(this.store);\n\n const op = transaction.delete(key);\n\n op.addEventListener('success', () => {\n resolve(value);\n }, false);\n\n op.addEventListener('error', (event) => {\n reject(new Error(`Failed to delete key \"${key}\": ${(event.target as IDBRequest).error?.message}`));\n }, false);\n });\n }\n\n /**\n * Clear the entire space\n *\n * @returns Promise for the clear operation\n */\n async clear(): Promise<void> {\n await this.open();\n return new Promise((resolve, reject) => {\n const transaction = (this.storage as IDBDatabase)\n .transaction(this.store, 'readwrite')\n .objectStore(this.store);\n\n const op = transaction.clear();\n\n op.addEventListener('success', () => {\n resolve();\n }, false);\n\n op.addEventListener('error', (event) => {\n reject(new Error(`Failed to clear store: ${(event.target as IDBRequest).error?.message}`));\n }, false);\n });\n }\n}\n",
|
|
16
|
+
"/**\n * ==============================\n * Remote Storage Adapter\n * ==============================\n */\n\nimport { Request } from '../Request';\nimport type { RequestOptions } from '../Request';\nimport type { RemoteStorageConfiguration, StorageValue, KeyValueResult, SpaceAdapterInterface } from './types';\nimport { normalizeUrl } from './types';\n\n/**\n * Error thrown when a key is not found in storage\n */\nexport class KeyNotFoundError extends Error {\n constructor(key: string) {\n super(`Key \"${key}\" not found in remote storage`);\n this.name = 'KeyNotFoundError';\n }\n}\n\n/**\n * The Remote Storage Adapter provides the Space Class the ability to interact\n * with a server in order to handle data persistence. The server's implementation\n * is up to the developer but it will need to respond to this adapter's request\n * formatting. This adapter uses the Request class to perform its tasks.\n */\nexport class RemoteStorage implements SpaceAdapterInterface {\n public name: string;\n public version: string;\n public store: string;\n public baseEndpoint: string;\n public endpoint: string;\n public props: RequestOptions;\n public storage: typeof Request | undefined;\n\n /**\n * Create a new Remote Storage. This adapter requires an endpoint URL where\n * it will make the requests.\n *\n * @param configuration - Configuration Object for the Adapter\n */\n constructor({ name = '', version = '', store = '', endpoint = '', props = {} }: RemoteStorageConfiguration) {\n this.name = name;\n this.version = version;\n this.store = store;\n this.baseEndpoint = endpoint;\n this.endpoint = this.computeEndpoint();\n this.props = props;\n }\n\n /**\n * Compute the full endpoint URL\n *\n * @returns The computed endpoint URL\n */\n private computeEndpoint(): string {\n if (this.store) {\n return normalizeUrl(this.baseEndpoint, `${this.store}/`);\n }\n return this.baseEndpoint.endsWith('/') ? this.baseEndpoint : `${this.baseEndpoint}/`;\n }\n\n /**\n * Modify the configuration\n *\n * @param config - Configuration object to set up\n */\n configuration(config: RemoteStorageConfiguration): void {\n if (config.name !== undefined) this.name = config.name;\n if (config.version !== undefined) this.version = config.version;\n if (config.store !== undefined) this.store = config.store;\n if (config.endpoint !== undefined) this.baseEndpoint = config.endpoint;\n\n // Recalculate the endpoint after configuration changes\n this.endpoint = this.computeEndpoint();\n }\n\n /**\n * Open the Storage Object\n *\n * @returns Promise resolving to this adapter\n */\n async open(): Promise<this> {\n if (typeof this.storage === 'undefined') {\n this.storage = Request;\n }\n\n return this;\n }\n\n /**\n * Store a key-value pair. This function sends a POST request to the server\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and response\n */\n async set(key: string, value: StorageValue): Promise<KeyValueResult> {\n await this.open();\n\n const response = await this.storage!.post(this.endpoint + key, value as Record<string, unknown>, this.props);\n const json = await response.json();\n\n return { key, value: json };\n }\n\n /**\n * Update a key-value pair. The update method will use Object.assign()\n * in the case of objects so no value is lost. This function sends a PUT\n * request to the server.\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and response\n */\n async update(key: string, value: StorageValue): Promise<KeyValueResult> {\n await this.open();\n const currentValue = await this.get(key);\n const merged = { ...(currentValue as object), ...(value as object) };\n const response = await this.storage!.put(this.endpoint + key, merged as Record<string, unknown>, this.props);\n const json = await response.json();\n\n return { key, value: json };\n }\n\n /**\n * Retrieves a value from storage given its key\n *\n * @param key - Key with which the value was saved\n * @returns Promise resolving to the retrieved value\n */\n async get(key: string): Promise<StorageValue> {\n await this.open();\n return this.storage!.json(this.endpoint + key, {}, this.props);\n }\n\n /**\n * Retrieves all the values in the space in a key-value JSON object\n *\n * @returns Promise resolving to all values\n */\n async getAll(): Promise<Record<string, StorageValue>> {\n await this.open();\n return this.storage!.json(this.endpoint, {}, this.props);\n }\n\n /**\n * Check if a space contains a given key.\n *\n * @param key - Key to look for\n * @returns Promise that resolves if key exists\n */\n async contains(key: string): Promise<void> {\n const keys = await this.keys();\n if (keys.includes(key)) {\n return;\n } else {\n throw new KeyNotFoundError(key);\n }\n }\n\n /**\n * Upgrading the Storage must be done on the server side, therefore this\n * function always gets rejected.\n *\n * @returns Promise rejection\n */\n upgrade(): Promise<never> {\n return Promise.reject(new Error('RemoteStorage cannot be upgraded from the client. Upgrades must be performed server-side.'));\n }\n\n /**\n * Renaming the Storage must be done on the server side, therefore this\n * function always gets rejected.\n *\n * @returns Promise rejection\n */\n rename(): Promise<never> {\n return Promise.reject(new Error('RemoteStorage cannot be renamed from the client. Renaming must be performed server-side.'));\n }\n\n /**\n * Getting a key by its index is not possible in this adapter, therefore\n * this function always gets rejected.\n *\n * @returns Promise rejection\n */\n key(): Promise<never> {\n return Promise.reject(new Error('RemoteStorage does not support getting keys by index. Use keys() to get all keys.'));\n }\n\n /**\n * Return all keys stored in the space. This makes a GET request to the\n * full endpoint with a keys query parameter.\n *\n * @returns Promise resolving to array of keys\n */\n async keys(): Promise<string[]> {\n await this.open();\n return this.storage!.json<string[]>(this.endpoint, { keys: true }, this.props);\n }\n\n /**\n * Delete a value from the space given its key. This function sends a\n * DELETE request to the server.\n *\n * @param key - Key of the item to delete\n * @returns Promise resolving to the key and response\n */\n async remove(key: string): Promise<StorageValue> {\n await this.open();\n const response = await this.storage!.delete(this.endpoint + key, {}, this.props);\n return response.json();\n }\n\n /**\n * Clear the entire space. This function sends a DELETE request to the server.\n *\n * @returns Promise for the clear operation\n */\n async clear(): Promise<void> {\n await this.open();\n await this.storage!.delete(this.endpoint, {}, this.props);\n }\n}\n",
|
|
17
|
+
"/**\n * ==============================\n * Space\n * ==============================\n */\n\nimport { LocalStorage } from './SpaceAdapter/LocalStorage';\nimport { SessionStorage } from './SpaceAdapter/SessionStorage';\nimport { IndexedDB } from './SpaceAdapter/IndexedDB';\nimport { RemoteStorage } from './SpaceAdapter/RemoteStorage';\nimport type { SpaceConfiguration, StorageValue, KeyValueResult, UpgradeCallback, SpaceAdapterInterface } from './SpaceAdapter/types';\nimport { cloneValue } from './SpaceAdapter/types';\n\n/**\n * List of Adapters Available\n */\nexport const SpaceAdapter = {\n LocalStorage,\n SessionStorage,\n IndexedDB,\n RemoteStorage\n};\n\n/**\n * Space adapter type (any of the available adapters)\n */\nexport type SpaceAdapterType = SpaceAdapterInterface;\n\nexport type SpaceAdapterConstructor = typeof LocalStorage | typeof SessionStorage | typeof IndexedDB | typeof RemoteStorage;\n\n/**\n * Callback function type for space events\n */\nexport type SpaceCallback = (key: string, value: StorageValue) => void;\n\n/**\n * Transformation function type\n */\nexport type TransformationFunction = (key: string, value: StorageValue) => StorageValue;\n\n/**\n * Transformation configuration\n */\nexport interface Transformation {\n id: string;\n get?: TransformationFunction | null;\n set?: TransformationFunction | null;\n}\n\n/**\n * Space provides a simple wrapper for different Storage APIs. It aims to\n * provide data independence through storage namespaces and versioning, allowing\n * transparent data formatting and content modifications through versions.\n */\nexport class Space {\n private _configuration: SpaceConfiguration;\n public adapter: SpaceAdapterType;\n public callbacks: {\n create: SpaceCallback[];\n update: SpaceCallback[];\n delete: SpaceCallback[];\n };\n public transformations: Record<string, Transformation>;\n\n /**\n * Create a new Space Object. If no name and version is defined, the global\n * LocalSpace space is used.\n *\n * @param adapter - Space Adapter to use\n * @param configuration - Configuration object for the space\n */\n constructor(adapter: SpaceAdapterConstructor = SpaceAdapter.LocalStorage, configuration: SpaceConfiguration = {}) {\n // Assign the provided configuration to the default one\n this._configuration = { name: '', version: '', store: '', ...configuration };\n\n // Set up the adapter instance to use\n this.adapter = new adapter(this._configuration);\n\n // This object stores all the callbacks the user can define for the space operations\n this.callbacks = {\n create: [],\n update: [],\n delete: []\n };\n\n // A transformation is an object that can contain set and get functions\n this.transformations = {};\n }\n\n /**\n * Modify the space configuration, it will also be passed down to the adapter\n * using its configuration() function.\n *\n * @param object - Configuration object to set up\n * @returns Configuration object if no param was passed\n */\n configuration(object: SpaceConfiguration | null = null): SpaceConfiguration | undefined {\n if (object !== null) {\n this._configuration = { ...this._configuration, ...object };\n if (this.adapter.configuration) {\n this.adapter.configuration(object);\n }\n return undefined;\n } else {\n return this._configuration;\n }\n }\n\n /**\n * Open the Storage Object to be used depending on the SpaceAdapter\n *\n * @returns Promise resolving to this Space\n */\n async open(): Promise<this> {\n await this.adapter.open();\n return this;\n }\n\n /**\n * Apply set transformations to a value\n *\n * @param key - The key being set\n * @param value - The value to transform\n * @returns The transformed value\n */\n private applySetTransformations(key: string, value: StorageValue): StorageValue {\n let transformedValue = cloneValue(value);\n for (const transformation of Object.values(this.transformations)) {\n if (typeof transformation.set === 'function') {\n transformedValue = transformation.set(key, transformedValue);\n }\n }\n return transformedValue;\n }\n\n /**\n * Apply get transformations to a value\n *\n * @param key - The key being retrieved\n * @param value - The value to transform\n * @returns The transformed value\n */\n private applyGetTransformations(key: string, value: StorageValue): StorageValue {\n let transformedValue = value;\n for (const transformation of Object.values(this.transformations)) {\n if (typeof transformation.get === 'function') {\n transformedValue = transformation.get(key, transformedValue);\n }\n }\n return transformedValue;\n }\n\n /**\n * Store a key-value pair\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and value\n */\n async set(key: string, value: StorageValue): Promise<KeyValueResult> {\n const transformedValue = this.applySetTransformations(key, value);\n const result = await this.adapter.set(key, transformedValue);\n for (const callback of this.callbacks.create) {\n callback.call(null, result.key, result.value);\n }\n return result;\n }\n\n /**\n * Update a key-value pair. In difference with the set() method, the update\n * method will use Object.assign() in the case of objects so no value is lost.\n *\n * @param key - Key with which this value will be saved\n * @param value - Value to save\n * @returns Promise with key and value\n */\n async update(key: string, value: StorageValue): Promise<KeyValueResult> {\n const transformedValue = this.applySetTransformations(key, value);\n const result = await this.adapter.update(key, transformedValue);\n for (const callback of this.callbacks.update) {\n callback.call(null, result.key, result.value);\n }\n return result;\n }\n\n /**\n * Retrieves a value from storage given its key\n *\n * @param key - Key with which the value was saved\n * @returns Promise resolving to the retrieved value\n */\n async get(key: string): Promise<StorageValue> {\n const value = await this.adapter.get(key);\n return this.applyGetTransformations(key, value);\n }\n\n /**\n * Retrieves all the values in the space in a key-value JSON object\n *\n * @returns Promise resolving to all values\n */\n async getAll(): Promise<Record<string, StorageValue>> {\n const values = await this.adapter.getAll();\n const transformedValues: Record<string, StorageValue> = {};\n\n for (const key of Object.keys(values)) {\n transformedValues[key] = this.applyGetTransformations(key, values[key]);\n }\n\n return transformedValues;\n }\n\n /**\n * Iterate over every value in the space\n *\n * @param callback - A callback function receiving the key and value\n * @returns Promise resolving when all callbacks have been resolved\n */\n async each(callback: (key: string, value: StorageValue) => unknown): Promise<unknown[]> {\n const values = await this.getAll();\n const promises: unknown[] = [];\n for (const [key, value] of Object.entries(values)) {\n promises.push(callback.call(this, key, value));\n }\n return Promise.all(promises);\n }\n\n /**\n * Check if a space contains a given key. Not all adapters may give this information\n *\n * @param key - Key to look for\n * @returns Promise that resolves if key exists\n */\n contains(key: string): Promise<void> {\n return this.adapter.contains(key);\n }\n\n /**\n * Upgrade a Space Version. Not all adapters may provide this functionality\n *\n * @param oldVersion - The version of the storage to be upgraded\n * @param newVersion - The version to be upgraded to\n * @param callback - Function to transform the old stored values\n * @returns Promise for the upgrade operation\n */\n async upgrade(oldVersion: string, newVersion: string, callback: UpgradeCallback): Promise<this> {\n await this.adapter.upgrade(oldVersion, newVersion, callback);\n return this;\n }\n\n /**\n * Rename a Space. Not all adapters may provide this functionality\n *\n * @param name - New name to be used\n * @returns Promise for the rename operation\n */\n rename(name: string): Promise<void> {\n return this.adapter.rename(name);\n }\n\n /**\n * Add a callback function to be run every time a value is created.\n *\n * @param callback - Callback Function. Key and Value pair will be sent as parameters.\n */\n onCreate(callback: SpaceCallback): void {\n this.callbacks.create.push(callback);\n }\n\n /**\n * Add a callback function to be run every time a value is updated.\n *\n * @param callback - Callback Function. Key and Value pair will be sent as parameters.\n */\n onUpdate(callback: SpaceCallback): void {\n this.callbacks.update.push(callback);\n }\n\n /**\n * Add a callback function to be run every time a value is deleted.\n *\n * @param callback - Callback Function. Key and Value pair will be sent as parameters.\n */\n onDelete(callback: SpaceCallback): void {\n this.callbacks.delete.push(callback);\n }\n\n /**\n * Add a transformation function to the space.\n *\n * @param transformation - Transformation configuration with id, get, and set functions\n */\n addTransformation({ id, get, set }: Transformation): void {\n this.transformations[id] = { id, get, set };\n }\n\n /**\n * Remove a transformation function given its id\n *\n * @param id - Name or identifier of the transformation to remove\n */\n removeTransformation(id: string): void {\n delete this.transformations[id];\n }\n\n /**\n * Get the key that corresponds to a given index in the storage.\n * Not all adapters may provide this functionality\n *\n * @param index - Index to get the key from\n * @param full - Whether to return the full key name including space id\n * @returns Promise resolving to the key's name\n */\n key(index: number, full: boolean = false): Promise<string> {\n return this.adapter.key(index, full);\n }\n\n /**\n * Return all keys stored in the space. Not all adapters may provide this functionality\n *\n * @param full - Whether to return the full key name including space id\n * @returns Promise resolving to array of keys\n */\n keys(full: boolean = false): Promise<string[]> {\n return this.adapter.keys(full);\n }\n\n /**\n * Delete a value from the space given its key\n *\n * @param key - Key of the item to delete\n * @returns Promise that resolves after deletion\n */\n async remove(key: string): Promise<void> {\n const value = await this.adapter.remove(key);\n // Run the callback for deletions\n for (const callback of this.callbacks.delete) {\n callback.call(null, key, value);\n }\n }\n\n /**\n * Clear the entire space\n *\n * @returns Promise for the clear operation\n */\n clear(): Promise<void> {\n return this.adapter.clear();\n }\n}\n\n// Re-export adapter types\nexport { LocalStorage } from './SpaceAdapter/LocalStorage';\nexport { SessionStorage } from './SpaceAdapter/SessionStorage';\nexport { IndexedDB } from './SpaceAdapter/IndexedDB';\nexport { RemoteStorage } from './SpaceAdapter/RemoteStorage';\nexport type { SpaceConfiguration, StorageValue, KeyValueResult, UpgradeCallback } from './SpaceAdapter/types';\n",
|
|
18
18
|
"/**\n * ==============================\n * Text\n * ==============================\n */\n\nexport interface CapitalizeOptions {\n preserveCase?: boolean; // Wether to preserve the case of letters after the first character\n}\n\nexport class Text {\n\n /**\n * Capitalize the first letter of each word.\n *\n * @param text - Text to capitalize\n * @param options - Capitalization options\n * @returns Capitalized text\n */\n static capitalize(text: string, options: CapitalizeOptions = {}): string {\n const { preserveCase = false } = options;\n\n return text.replace(/\\w\\S*/g, (word) => {\n const firstChar = word.charAt(0).toUpperCase();\n const rest = preserveCase ? word.substring(1) : word.substring(1).toLowerCase();\n return firstChar + rest;\n });\n }\n\n /**\n * Get the currently selected text in the document.\n */\n static selection(): string {\n return window.getSelection()?.toString() || '';\n }\n\n /**\n * Get the text after a given key/substring.\n *\n * @param key - The substring to search for\n * @param text - The text to search in\n * @returns Text after the key, or empty string if not found\n */\n static suffix(key: string, text: string): string {\n const index = text.indexOf(key);\n\n if (index === -1) {\n return '';\n }\n\n return text.slice(index + key.length);\n }\n\n /**\n * Get the text before a given key/substring.\n *\n * @param key - The substring to search for\n * @param text - The text to search in\n * @returns Text before the key, or empty string if not found\n */\n static prefix(key: string, text: string): string {\n const index = text.indexOf(key);\n\n if (index === -1) {\n return '';\n }\n\n return text.slice(0, index);\n }\n\n /**\n * Convert text to a URL-friendly slug.\n *\n * @param text - Text to convert\n * @returns URL-friendly slug\n */\n static friendly(text: string): string {\n return text\n .toString() // Ensure it's a string\n .normalize('NFD') // Split accents from letters (e.g. é -> e + ´)\n .replace(/[\\u0300-\\u036f]/g, '') // Remove the separated accents\n .toLowerCase() // Standardize to lowercase\n .trim() // Remove leading/trailing whitespace\n .replace(/\\s+/g, '-') // Replace spaces with -\n .replace(/[^\\w-]+/g, '') // Remove all non-word chars (except -)\n .replace(/--+/g, '-'); // Replace multiple - with single -\n }\n\n /**\n * Truncate text to a maximum length with ellipsis.\n *\n * @param text - Text to truncate\n * @param maxLength - Maximum length (including ellipsis)\n * @param ellipsis - Ellipsis string to append (default: '...')\n */\n static truncate(text: string, maxLength: number, ellipsis: string = '...'): string {\n if (text.length <= maxLength) {\n return text;\n }\n\n return text.slice(0, maxLength - ellipsis.length).trimEnd() + ellipsis;\n }\n\n /**\n * Check if a string is empty or contains only whitespace.\n */\n static isBlank(text: string | null | undefined): boolean {\n return text === null || text === undefined || text.trim() === '';\n }\n}\n",
|
|
19
19
|
"/**\n * ==============================\n * Util\n * ==============================\n */\n\nexport type Callable<T = unknown> = (...args: unknown[]) => T | Promise<T>;\n\nexport class Util {\n /**\n * Calls a function and ensures it returns a Promise.\n *\n * @param callable - The function to run\n * @param context - The `this` context\n * @param args - Arguments to pass\n */\n static async callAsync<T = unknown>(callable: Callable<T>, context: unknown, ...args: unknown[]): Promise<T> {\n try {\n return await callable.apply(context, args);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /**\n * Generates a UUID v4.\n */\n static uuid(): string {\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return crypto.randomUUID();\n }\n\n // Fallback using crypto.getRandomValues\n if (typeof crypto !== 'undefined' && 'getRandomValues' in crypto) {\n return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => {\n const num = parseInt(c, 10);\n const random = crypto.getRandomValues(new Uint8Array(1))[0];\n const shifted = 15 >> Math.floor(num / 4);\n return (num ^ (random & shifted)).toString(16);\n });\n }\n\n // Insecure Fallback, pretty sure no current browser should need this\n const generate = (): string => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);\n return `${generate()}${generate()}-${generate()}-${generate()}-${generate()}-${generate()}${generate()}${generate()}`;\n }\n\n /**\n * Debounce a function call.\n *\n * @param fn - Function to debounce\n * @param delay - Delay in milliseconds\n */\n static debounce<T extends (...args: unknown[]) => unknown>(fn: T, delay: number): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return (...args: Parameters<T>): void => {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n timeoutId = setTimeout(() => {\n fn(...args);\n timeoutId = null;\n }, delay);\n };\n }\n\n /**\n * Throttle a function call.\n *\n * @param fn - Function to throttle\n * @param limit - Minimum time between calls in milliseconds\n */\n static throttle<T extends (...args: unknown[]) => unknown>(fn: T, limit: number): (...args: Parameters<T>) => void {\n let inThrottle = false;\n\n return (...args: Parameters<T>): void => {\n if (!inThrottle) {\n fn(...args);\n inThrottle = true;\n setTimeout(() => {\n inThrottle = false;\n }, limit);\n }\n };\n }\n}\n",
|
|
20
|
-
"// This file is basically just a hack to expose the Artemis namespace in the\n// window object. Once/if bun adds support for this, we can remove this file.\n\nimport * as Artemis from './index';\n\ndeclare global {\n
|
|
20
|
+
"// This file is basically just a hack to expose the Artemis namespace in the\n// window object. Once/if bun adds support for this, we can remove this file.\n\nimport * as Artemis from './index';\n\ndeclare global {\n interface Window {\n Artemis: typeof Artemis;\n }\n}\n\nif (typeof window === 'object') {\n window.Artemis = Artemis;\n}\n\n"
|
|
21
21
|
],
|
|
22
|
-
"mappings": "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",
|
|
23
|
-
"debugId": "
|
|
22
|
+
"mappings": "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",
|
|
23
|
+
"debugId": "8FAFB15BD5215AFD64756E2164756E21",
|
|
24
24
|
"names": []
|
|
25
25
|
}
|