Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ribajs/core

Package Overview
Dependencies
Maintainers
2
Versions
98
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ribajs/core - npm Package Compare versions

Comparing version 2.0.0-rc.3 to 2.0.0-rc.4

62

package.json
{
"name": "@ribajs/core",
"description": "Core module of Riba.js",
"version": "2.0.0-rc.3",
"version": "2.0.0-rc.4",
"type": "module",

@@ -51,4 +51,4 @@ "engines": {

"devDependencies": {
"@babel/cli": "^7.22.5",
"@babel/core": "^7.22.5",
"@babel/cli": "^7.22.9",
"@babel/core": "^7.22.9",
"@babel/plugin-proposal-class-properties": "^7.18.6",

@@ -58,31 +58,31 @@ "@babel/plugin-proposal-object-rest-spread": "^7.20.7",

"@babel/plugin-syntax-export-default-from": "^7.22.5",
"@babel/plugin-transform-runtime": "^7.22.5",
"@babel/plugin-transform-typescript": "^7.22.5",
"@babel/preset-env": "^7.22.5",
"@babel/plugin-transform-runtime": "^7.22.9",
"@babel/plugin-transform-typescript": "^7.22.9",
"@babel/preset-env": "^7.22.9",
"@babel/preset-react": "^7.22.5",
"@babel/preset-typescript": "^7.22.5",
"@babel/runtime": "^7.22.5",
"@babel/runtime-corejs3": "^7.22.5",
"@jest/globals": "^29.5.0",
"@ribajs/eslint-config": "^2.0.0-rc.3",
"@ribajs/tsconfig": "^2.0.0-rc.3",
"@ribajs/types": "^2.0.0-rc.3",
"@babel/runtime": "^7.22.6",
"@babel/runtime-corejs3": "^7.22.6",
"@jest/globals": "^29.6.2",
"@ribajs/eslint-config": "^2.0.0-rc.4",
"@ribajs/tsconfig": "^2.0.0-rc.4",
"@ribajs/types": "^2.0.0-rc.4",
"@types/core-js": "^2.5.5",
"@types/jest": "^29.5.2",
"@types/node": "^18.16.18",
"babel-jest": "^29.5.0",
"babel-loader": "^9.1.2",
"@types/jest": "^29.5.3",
"@types/node": "^18.17.1",
"babel-jest": "^29.6.2",
"babel-loader": "^9.1.3",
"babel-plugin-array-includes": "^2.0.3",
"core-js": "^3.31.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.5.0",
"jest-config": "^29.5.0",
"core-js": "^3.32.0",
"eslint": "^8.46.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.6.2",
"jest-config": "^29.6.2",
"jest-extended": "^4.0.0",
"prettier": "^2.8.8",
"prettier": "^3.0.1",
"source-map-support": "^0.5.21",
"ts-jest": "^29.1.0",
"typescript": "5.1.3",
"webpack": "^5.88.0",
"ts-jest": "^29.1.1",
"typescript": "5.1.6",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",

@@ -99,8 +99,8 @@ "webpack-glob-entry": "^2.1.1"

"dependencies": {
"@ribajs/events": "^2.0.0-rc.3",
"@ribajs/history": "^2.0.0-rc.3",
"@ribajs/jsx": "^2.0.0-rc.3",
"@ribajs/ssr": "^2.0.0-rc.3",
"@ribajs/utils": "^2.0.0-rc.3"
"@ribajs/events": "^2.0.0-rc.4",
"@ribajs/history": "^2.0.0-rc.4",
"@ribajs/jsx": "^2.0.0-rc.4",
"@ribajs/ssr": "^2.0.0-rc.4",
"@ribajs/utils": "^2.0.0-rc.4"
}
}

@@ -67,3 +67,3 @@ import {

callback.sync();
}
},
);

@@ -70,0 +70,0 @@ }

@@ -116,3 +116,3 @@ import { parseType, PRIMITIVE, KEYPATH } from "@ribajs/utils";

formatters: string[] | null,
identifier: string | null
identifier: string | null,
) {

@@ -142,3 +142,3 @@ this.view = view;

keypath: string,
callback: ObserverSyncCallback
callback: ObserverSyncCallback,
): Observer {

@@ -176,3 +176,3 @@ return new Observer(model, keypath, callback);

args: string[],
formatterIndex: number
formatterIndex: number,
): string[] {

@@ -233,9 +233,9 @@ return args

}] No args matched with regex "FORMATTER_ARGS"!\nvalue: ${JSON.stringify(
value
value,
)}\nresult: ${JSON.stringify(
result
result,
)}\ndeclaration: ${JSON.stringify(
declaration
)}\nindex: ${index}\n`
)
declaration,
)}\nindex: ${index}\n`,
),
);

@@ -258,3 +258,3 @@ return result;

throw new Error(
`[${this.name}] No formatters with id "${id}" found!`
`[${this.name}] No formatters with id "${id}" found!`,
);

@@ -279,3 +279,3 @@ }

return result.then((value: any) =>
this.formattedValue(value, index + 1)
this.formattedValue(value, index + 1),
);

@@ -285,3 +285,3 @@ }

},
value
value,
);

@@ -298,3 +298,3 @@ }

fn: eventHandlerFunction,
el: HTMLElement
el: HTMLElement,
): (ev: Event) => any {

@@ -371,3 +371,3 @@ const handler = this.view.options.handler;

declaration: string /*check type*/,
index: number
index: number,
) => {

@@ -392,3 +392,3 @@ const args = declaration.split(FORMATTER_SPLIT);

},
this._getValue(this.el)
this._getValue(this.el),
);

@@ -395,0 +395,0 @@

@@ -38,3 +38,3 @@ import { Binder } from "../binder.js";

detail: { name: this.type, newValue: newValueFormatted, oldValue },
} as BinderAttributeChangedEvent)
} as BinderAttributeChangedEvent),
);

@@ -41,0 +41,0 @@ }

@@ -27,3 +27,3 @@ import { Binder } from "../binder.js";

NO_RIBA_COMPONENT_ERROR_MESSAGE.replace("{tagName}", el.tagName),
el
el,
);

@@ -42,3 +42,3 @@ }

NO_RIBA_COMPONENT_ERROR_MESSAGE.replace("{tagName}", el.tagName),
el
el,
);

@@ -53,3 +53,3 @@ }

NO_RIBA_COMPONENT_ERROR_MESSAGE.replace("{tagName}", el.tagName),
el
el,
);

@@ -74,3 +74,3 @@ return;

NO_RIBA_COMPONENT_ERROR_MESSAGE.replace("{tagName}", el.tagName),
el
el,
);

@@ -77,0 +77,0 @@ }

@@ -65,3 +65,3 @@ import { Bindable } from "../types/index.js";

this.args[0]
} needs an array or object to iterate over, but it is ${typeof collection}`
} needs an array or object to iterate over, but it is ${typeof collection}`,
);

@@ -68,0 +68,0 @@ }

@@ -19,3 +19,3 @@ import { Binder } from "../binder.js";

this.marker = window?.document?.createComment(
" riba: " + this.type + " " + this.keypath + " "
" riba: " + this.type + " " + this.keypath + " ",
);

@@ -22,0 +22,0 @@ this.attached = false;

@@ -21,3 +21,3 @@ import { Binder } from "../binder.js";

el.localName,
customElements.get(el.localName)
customElements.get(el.localName),
);

@@ -33,3 +33,3 @@ }

`[parentBinder] CustomElement ${el.localName} has been defined, but is not yet upgraded. Waiting for upgrade..`,
el
el,
);

@@ -41,3 +41,3 @@ await waitForCustomElement(el);

"[parentBinder] You can only use this binder on Riba components",
el.localName
el.localName,
);

@@ -44,0 +44,0 @@ }

@@ -58,3 +58,3 @@ import { Binder } from "../binder.js";

el: HTMLElement | HTMLSelectElement,
newValue?: number | string | string[]
newValue?: number | string | string[],
) {

@@ -61,0 +61,0 @@ let oldValue = this.getValue(el);

@@ -133,3 +133,3 @@ /**

!this.observedAttributesToCheck[key]?.passed ||
this.observedAttributesToCheck[key]?.initialized
this.observedAttributesToCheck[key]?.initialized,
);

@@ -194,7 +194,7 @@ }

binding: Binder,
el: HTMLElement
el: HTMLElement,
) {
if (!this || !this.call) {
const error = new Error(
`[rv-${binding.type}="${binding.keypath}"] Event handler "${binding.keypath}" not found!"`
`[rv-${binding.type}="${binding.keypath}"] Event handler "${binding.keypath}" not found!"`,
);

@@ -243,3 +243,3 @@ console.error(binding, el);

newValue: any,
namespace: string | null
namespace: string | null,
) {

@@ -270,3 +270,3 @@ // this.debug("attributeChangedCallback", attributeName, newValue);

newValue,
namespace
namespace,
);

@@ -286,3 +286,3 @@ }

newValue: any,
namespace: string | null
namespace: string | null,
) {

@@ -294,3 +294,3 @@ this.debug(

newValue,
namespace
namespace,
);

@@ -351,3 +351,3 @@ }

protected async afterTemplate(
template: JsxElement | HTMLElement | string | null
template: JsxElement | HTMLElement | string | null,
): Promise<any> {

@@ -377,3 +377,3 @@ this.debug("afterTemplate", template);

attributeName: string,
callback: ObserverSyncCallback
callback: ObserverSyncCallback,
): Observer {

@@ -395,3 +395,3 @@ const parsedAttributeName = camelCase(attributeName);

newValue: any,
namespace: string | null = null
namespace: string | null = null,
) {

@@ -398,0 +398,0 @@ const parsedAttributeName = camelCase(attributeName);

@@ -61,3 +61,3 @@ /**

"Component:constructor",
this.getLifecycleEventData()
this.getLifecycleEventData(),
);

@@ -67,3 +67,3 @@ this.lifecycleEvents.on(

this.afterAllBind,
this
this,
);

@@ -77,3 +77,3 @@ }

"Component:init",
this.getLifecycleEventData()
this.getLifecycleEventData(),
);

@@ -100,3 +100,3 @@ return await this.bindIfReady();

error,
this.getLifecycleEventData()
this.getLifecycleEventData(),
);

@@ -126,3 +126,3 @@ this.error(error);

this.observedAttributesToCheck,
this.scope
this.scope,
);

@@ -138,3 +138,3 @@ return;

"Component:beforeBind",
this.getLifecycleEventData()
this.getLifecycleEventData(),
);

@@ -154,3 +154,3 @@ }

"Component:afterBind",
this.getLifecycleEventData()
this.getLifecycleEventData(),
);

@@ -216,3 +216,3 @@ }

"Component:disconnected",
this.getLifecycleEventData()
this.getLifecycleEventData(),
);

@@ -222,3 +222,3 @@ this.lifecycleEvents.off(

this.afterAllBind,
this
this,
);

@@ -228,3 +228,3 @@ this.lifecycleEvents.off(

this.afterAllBind,
this
this,
);

@@ -247,3 +247,3 @@ } catch (error) {

"Component:connected",
this.getLifecycleEventData()
this.getLifecycleEventData(),
);

@@ -267,3 +267,3 @@ } catch (error) {

newValue: any,
namespace: string | null
namespace: string | null,
) {

@@ -275,3 +275,3 @@ try {

newValue,
namespace
namespace,
);

@@ -293,3 +293,3 @@ await this.bindIfReady();

throw new Error(
`[${self.tagName}] Can not use "call" formatter: fn is undefined!`
`[${self.tagName}] Can not use "call" formatter: fn is undefined!`,
);

@@ -316,3 +316,3 @@ }

throw new Error(
`[${self.tagName}] Can not use "args" formatter: fn is undefined!`
`[${self.tagName}] Can not use "args" formatter: fn is undefined!`,
);

@@ -379,3 +379,3 @@ }

this.scope,
viewOptions
viewOptions,
);

@@ -382,0 +382,0 @@ return view;

@@ -44,3 +44,3 @@ import { Component, ScopeBase } from "@ribajs/core";

value: any,
type?: AttributeType
type?: AttributeType,
) {

@@ -76,3 +76,3 @@ switch (type) {

tpl: HTMLTemplateElement | HTMLElement,
index: number
index: number,
) {

@@ -84,3 +84,3 @@ const attributes: any = {};

console.error(
new Error(`template "${attribute.name}" attribute is required!`)
new Error(`template "${attribute.name}" attribute is required!`),
);

@@ -90,3 +90,3 @@ } else {

attribute.name,
tpl.getAttribute(attribute.name)
tpl.getAttribute(attribute.name),
);

@@ -100,3 +100,3 @@ }

tpl: HTMLTemplateElement | HTMLElement,
index: number
index: number,
) {

@@ -113,3 +113,3 @@ const attributes = this.getTemplateAttributes(tpl, index);

const templates = this.querySelectorAll<HTMLTemplateElement | HTMLElement>(
"template, .template"
"template, .template",
);

@@ -126,3 +126,3 @@ for (let index = 0; index < templates.length; index++) {

const templates = this.querySelectorAll<HTMLTemplateElement | HTMLElement>(
"template, .template"
"template, .template",
);

@@ -140,5 +140,5 @@ for (let index = 0; index < templates.length; index++) {

!child.classList?.contains("template") &&
child.nodeName !== "#text"
child.nodeName !== "#text",
);
}
}

@@ -21,3 +21,3 @@ import {

"[containsFormatter] The second parameter must be of type number for arrays but is " +
typeof attr
typeof attr,
);

@@ -41,3 +41,3 @@ }

"[containsFormatter] The second parameter must be of type string for objects" +
typeof attr
typeof attr,
);

@@ -44,0 +44,0 @@ }

@@ -7,3 +7,3 @@ import { Formatter } from "@ribajs/core";

toPrint: any,
level: "log" | "debug" | "info" | "error" | "warn" = "debug"
level: "log" | "debug" | "info" | "error" | "warn" = "debug",
) {

@@ -10,0 +10,0 @@ console[level](toPrint);

@@ -29,3 +29,3 @@ import { Formatter } from "../../types/index.js";

decimalSeparator = DEFAULT_DECIMAL_SEPARATOR,
thousandSeparator = DEFAULT_THOUSAND_SEPARATOR
thousandSeparator = DEFAULT_THOUSAND_SEPARATOR,
) {

@@ -32,0 +32,0 @@ if (!toDecimalFormatter.read) {

@@ -17,3 +17,3 @@ import { isObject, parseType } from "@ribajs/utils/src/type.js";

console.warn(
"[parseFormatter] You do not need to parse the value because since it already been parsed"
"[parseFormatter] You do not need to parse the value because since it already been parsed",
);

@@ -20,0 +20,0 @@ return str;

@@ -77,3 +77,3 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */

obj: Obj,
callback: ObserverSyncCallback
callback: ObserverSyncCallback,
) {

@@ -126,4 +126,4 @@ if (active) {

`[Observer] Must define at least one adapter interface. interfaces: "${JSON.stringify(
Observer.interfaces
)}" adapters: "${JSON.stringify(Observer.adapters)}"`
Observer.interfaces,
)}" adapters: "${JSON.stringify(Observer.adapters)}"`,
);

@@ -130,0 +130,0 @@ }

@@ -10,3 +10,3 @@ import { DataElement } from "./types/index.js";

node: DataElement,
templateDelimiters: Array<string>
templateDelimiters: Array<string>,
) {

@@ -13,0 +13,0 @@ /** If true stop / block the parseNode recursion */

@@ -28,7 +28,7 @@ import {

binder: Binder,
el: HTMLElement
el: HTMLElement,
) {
if (!this || !this.call) {
const error = new Error(
`[rv-${binder.type}="${binder.keypath}"] Event handler "${binder.keypath}" not found!"`
`[rv-${binder.type}="${binder.keypath}"] Event handler "${binder.keypath}" not found!"`,
);

@@ -114,3 +114,3 @@ console.error(error, binder, el, binder.view.models);

this.formatters,
this.adapters
this.adapters,
);

@@ -248,3 +248,3 @@ if (Riba.instance) {

const attributeBinders = Object.keys(viewOptions.binders).filter(
(key) => key.indexOf("*") >= 1 // Should contain, but not start with, *
(key) => key.indexOf("*") >= 1, // Should contain, but not start with, *
);

@@ -267,3 +267,3 @@ viewOptions.attributeBinders.push(...attributeBinders);

models: any = {},
options?: Options
options?: Options,
) {

@@ -270,0 +270,0 @@ const viewOptions: Options = this.getViewOptions(options);

@@ -29,3 +29,3 @@ import {

fallbackName?: string,
forceFallback = false
forceFallback = false,
): Adapters {

@@ -32,0 +32,0 @@ const name = forceFallback

@@ -24,3 +24,3 @@ import { Binders, ModuleElementType, ClassOfBinder } from "../types/index.js";

fallbackName?: string,
forceFallback = false
forceFallback = false,
) {

@@ -27,0 +27,0 @@ if (!Binder) {

@@ -22,3 +22,3 @@ import { Components, ModuleElementType } from "../types/index.js";

fallbackName?: string,
forceFallback = false
forceFallback = false,
): Components {

@@ -25,0 +25,0 @@ const name = forceFallback

@@ -21,3 +21,3 @@ import { CoreModuleOptions } from "../types/index.js";

throw new Error(
`Singleton of CoreService not defined, please call setSingleton first!`
`Singleton of CoreService not defined, please call setSingleton first!`,
);

@@ -24,0 +24,0 @@ }

@@ -21,3 +21,3 @@ import { Formatter, Formatters } from "../types/index.js";

fallbackName?: string,
forceFallback = false
forceFallback = false,
): Formatters {

@@ -24,0 +24,0 @@ const name = forceFallback

@@ -28,3 +28,3 @@ import { extend, isJson } from "@ribajs/utils/src/type.js";

headers: any = {},
options: HttpServiceOptions = {}
options: HttpServiceOptions = {},
) {

@@ -46,3 +46,3 @@ return this.fetch<T>(url, "GET", data, "json", headers, options);

headers: any = {},
options: HttpServiceOptions = {}
options: HttpServiceOptions = {},
) {

@@ -57,3 +57,3 @@ return this.fetch<T>(url, "POST", data, dataType, headers, options);

headers: any = {},
options: HttpServiceOptions = {}
options: HttpServiceOptions = {},
) {

@@ -68,3 +68,3 @@ return this.fetch<T>(url, "DELETE", data, dataType, headers, options);

headers: any = {},
options: HttpServiceOptions = {}
options: HttpServiceOptions = {},
) {

@@ -86,3 +86,3 @@ return this.fetch<T>(url, "PUT", data, dataType, headers, options);

headers: any = {},
options: HttpServiceOptions = {}
options: HttpServiceOptions = {},
) {

@@ -141,7 +141,7 @@ return this.fetch<T>(url, "GET", data, dataType, headers, options);

headers: any = {},
options: HttpServiceOptions = {}
options: HttpServiceOptions = {},
): Promise<HttpServiceResponse<T>> {
if (!fetch) {
throw new Error(
"Your browser does not support the fetch API, use xhr instead or install a polyfill."
"Your browser does not support the fetch API, use xhr instead or install a polyfill.",
);

@@ -148,0 +148,0 @@ }

@@ -58,3 +58,3 @@ import { EventDispatcher } from "@ribajs/events";

this.components[data.tagName].components.push(data.component);
}
},
);

@@ -70,3 +70,3 @@

this.checkStates();
}
},
);

@@ -82,3 +82,3 @@

this.checkStates();
}
},
);

@@ -90,3 +90,3 @@

this.onError(error, data);
}
},
);

@@ -105,3 +105,3 @@

dataset: any,
firstPageLoad: boolean
firstPageLoad: boolean,
) => {

@@ -115,3 +115,3 @@ if (this.debug)

"firstPageLoad",
firstPageLoad
firstPageLoad,
);

@@ -121,3 +121,3 @@ if (!firstPageLoad) {

}
}
},
);

@@ -193,3 +193,3 @@ }

`The component "${data.tagName}" has caused an error:`,
error
error,
);

@@ -224,3 +224,3 @@ this.events.trigger("ComponentLifecycle:error", error, data);

new Error(errorMessage),
{}
{},
);

@@ -240,3 +240,3 @@ }

this.onTimeout.bind(this),
CoreService.options.lifecycle?.timeout || 5000
CoreService.options.lifecycle?.timeout || 5000,
);

@@ -243,0 +243,0 @@ return this.timeout;

@@ -30,3 +30,3 @@ import {

formatters: Formatters,
adapters: Adapters
adapters: Adapters,
) {

@@ -33,0 +33,0 @@ this.binder = new BindersService(binders);

@@ -33,3 +33,3 @@ /**

ref: string,
keypath: string
keypath: string,
) => void;

@@ -39,3 +39,3 @@ public abstract unobserveMutations?: (

ref: string,
keypath: string
keypath: string,
) => void;

@@ -45,3 +45,3 @@ public abstract observe: (

keypath: string,
callback: ObserverSyncCallback
callback: ObserverSyncCallback,
) => void;

@@ -51,3 +51,3 @@ public abstract unobserve: (

keypath: string,
callback: ObserverSyncCallback
callback: ObserverSyncCallback,
) => void;

@@ -54,0 +54,0 @@ public abstract get: (obj: any, keypath: string) => any;

@@ -8,3 +8,3 @@ import type { View } from "../view.js";

*/
export interface ClassOfBinder<T = Binder<any, any>, E = any> extends Function {
export interface ClassOfBinder<T = Binder<any, any>, E = any> {
// tslint:disable:callable-types

@@ -18,3 +18,3 @@ new (

formatters: string[] | null,
identifier: string | null
identifier: string | null,
): T;

@@ -21,0 +21,0 @@ block: boolean;

@@ -7,3 +7,3 @@ import type { BasicComponent, Component } from "../component/index.js";

export interface ClassOfComponent<
T = BasicComponent | Component | PageComponent
T = BasicComponent | Component | PageComponent,
> extends ClassOf<T> {

@@ -10,0 +10,0 @@ tagName: string;

@@ -5,5 +5,5 @@ /**

*/
export interface ClassOf<T> extends Function {
export interface ClassOf<T> {
// tslint:disable:callable-types
new (...args: any[]): T;
}

@@ -9,3 +9,3 @@ import type { Binder } from "../binder.js";

binding: Binder<any, any>,
el: HTMLElement
el: HTMLElement,
) => void;

@@ -42,3 +42,3 @@ import {

models: any,
anchorEl: HTMLElement | Node | null
anchorEl: HTMLElement | Node | null,
) {

@@ -79,3 +79,3 @@ const template = binder.el.cloneNode(true);

models: any,
options: Options
options: Options,
) {

@@ -193,3 +193,3 @@ if (Array.isArray(els)) {

element as DataElement,
this.options.templateDelimiters
this.options.templateDelimiters,
);

@@ -222,3 +222,3 @@ }

regexp = new RegExp(
`^${identifier.replace("*", "([^-]*)").replaceAll("-*", "-(.+)")}$`
`^${identifier.replace("*", "([^-]*)").replaceAll("-*", "-(.+)")}$`,
);

@@ -237,3 +237,3 @@ } else {

node: BindableElement,
attributeBinders = this.options.attributeBinders
attributeBinders = this.options.attributeBinders,
) {

@@ -289,3 +289,3 @@ let block = false;

Binder,
identifier
identifier,
);

@@ -310,3 +310,3 @@ if (node.removeAttribute && this.options.removeBinderAttributes) {

bindInfo.Binder,
bindInfo.identifier
bindInfo.identifier,
);

@@ -372,3 +372,3 @@ if (node.removeAttribute && this.options.removeBinderAttributes) {

Binder: ClassOfBinder,
identifier: string | null
identifier: string | null,
) {

@@ -379,3 +379,3 @@ const parsedDeclaration = parseDeclaration(declaration);

this.bindings.push(
new Binder(this, node, type, Binder.key, keypath, pipes, identifier)
new Binder(this, node, type, Binder.key, keypath, pipes, identifier),
);

@@ -382,0 +382,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc