Giter Club home page Giter Club logo

permissionless.js's Introduction

permissionless.js

Node Version

permissionless.js is a TypeScript library built on top of viem for deploying and managing ERC-4337 smart accounts, interacting with bundlers and paymasters, and leveraging custom signers.

Features

  • High-Level Smart Account Support: We support a high-level API for deploying and managing smart accounts, including some of the most popular implementations (Safe, Kernel, Biconomy, etc.)
  • Bundler Support: We support all bundler actions following ERC-4337.
  • Gas Sponsorship: We support paymaster actions to allow you to easily sponsor gas fees.
  • User Operation Utility Functions: We provide many low-level utility functions useful for dealing with User Operations.
  • Modular and Extensible: We allow you to easily create and plug in your own smart account systems, bundlers, paymasters, and signers.
  • Built on & for viem: permissionless.js is designed to be a thin wrapper around viem, maintaining the same style and overall feel viem provides.
  • and a lot more...

Documentation

Take a look at our documentation to learn more about permissionless.js.

Installation

Install viem as a peer dependency.

Then install permissionless.js:

npm install viem permissionless
bun install viem permissionless
yarn add viem permissionless

Quick Start

// Import the required modules.
import { createBundlerClient } from "permissionless"
import { sepolia } from "viem/chains"
import { http } from "viem"

// Create the required clients.
const bundlerClient = createBundlerClient({
    chain: sepolia,
    transport: http(`https://api.pimlico.io/v1/sepolia/rpc?apikey=${pimlicoApiKey}`) // Use any bundler url
})

// Consume bundler, paymaster, and smart account actions!
const userOperationReceipt = await bundlerClient.getUserOperationReceipt({
    hash: "0x5faea6a3af76292c2b23468bbea96ef63fb31360848be195748437f0a79106c8"
})

Contributors

For a full explanation of permissionless.js, please visit our docs page

Build permissionless.js locally with:

bun run build

License

Distributed under an MIT License. See LICENSE for more information.

Contact

Feel free to ask any questions in our Telegram group

permissionless.js's People

Contributors

daemon-reconfig avatar derekchiang avatar github-actions[bot] avatar konfeature avatar kristofgazso avatar leekt avatar leovigna avatar livingrockrises avatar mouseless-eth avatar nikmel2803 avatar pavlovdog avatar plusminushalf avatar sahilvasava avatar starscrowding avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

permissionless.js's Issues

This member cannot have an 'override' modifier because it is not declared in the base class 'BaseError'.

I catch an error during compilation. Do you have any idea what can be a reason and how to fix it ? Thank you.

Error: node_modules/permissionless/errors/estimateUserOperationGas.ts:13:14 - error TS4113: This member cannot have an 'override' modifier because it is not declared in the base class 'BaseError'.

13     override cause: BaseError
                ~~~~~


Error: node_modules/permissionless/errors/sendUserOperation.ts:13:14 - error TS4113: This member cannot have an 'override' modifier because it is not declared in the base class 'BaseError'.

13     override cause: BaseError
                ~~~~~

Deps

"permissionless": "^0.1.22",
"typescript": "5.3.3"

Package fails to compile due to missing dependency

You might wanna include abitype as a dependency. Tested with version 0.0.31 and 0.0.33.

./node_modules/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts:1:32
Type error: Cannot find module 'abitype' or its corresponding type declarations.

> 1 | import type { TypedData } from "abitype"
    |                                ^
  2 | import {
  3 |     type Address,
  4 |     type Chain,

Type error: Type 'TPrimaryType' does not satisfy the constraint 'string'. when trying to build application

Running into an issue when trying to build my app with permissionless.js

Inside of the ./node_modules/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts:282:54 logic, I'm getting a type error.

$ next build
   Linting and checking validity of types  ..Failed to compile.

./node_modules/permissionless/accounts/biconomy/signerToBiconomySmartAccount.ts:282:54
Type error: Type 'TPrimaryType' does not satisfy the constraint 'string'.

  280 |                 | keyof TTypedData
  281 |                 | "EIP712Domain" = keyof TTypedData
> 282 |         >(typedData: TypedDataDefinition<TTypedData, TPrimaryType>) {
      |                                                      ^
  283 |             return signTypedData<TTypedData, TPrimaryType, TChain, undefined>(
  284 |                 client,
  285 |                 {
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Using:

typescript@^5.3.3
permissionless@^0.0.35

Here is my tsconfig.json:

{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "Es2022","esnext"],
    "allowJs": true,
    "checkJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "noUncheckedIndexedAccess": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": [
    ".eslintrc.cjs",
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "**/*.cjs",
    "**/*.mjs",
    "src/components/SukuriPointsCard"
  ],
  "exclude": ["node_modules"]
}

Seperating waitForUserOperationReceipt from sendTransaction

Hey, thanks for providing the library. I have a small feature request.

I would like to call smartAccountClient.sendUserOperation and smartAccountClient.waitForUserOperationReceipt within smartAccountClient.sendTransaction separately.

Reason for this is that if waitForUserOperationReceipt fails, I only want to retry that one, rather than sending the whole transaction again and possibly double spending.

Optimally, the sendUserOperation wrapper also includes all of this code:

const {
account: account_ = client.account,
data,
maxFeePerGas,
maxPriorityFeePerGas,
to,
value,
nonce,
middleware
} = args
if (!account_) {
throw new AccountOrClientNotFoundError({
docsPath: "/docs/actions/wallet/sendTransaction"
})
}
const account = parseAccount(account_) as SmartAccount<entryPoint>
if (!to) throw new Error("Missing to address")
if (account.type !== "local") {
throw new Error("RPC account type not supported")
}
const callData = await account.encodeCallData({
to,
value: value || BigInt(0),
data: data || "0x"
})
const userOpHash = await getAction(
client,
sendUserOperation<entryPoint>,
"sendUserOperation"
)({
userOperation: {
sender: account.address,
maxFeePerGas: maxFeePerGas || BigInt(0),
maxPriorityFeePerGas: maxPriorityFeePerGas || BigInt(0),
callData: callData,
nonce: nonce ? BigInt(nonce) : undefined
},
account: account,
middleware
})

The same would also go for sendTransactions.

sponsorUserOperation fails with TypeError

  const sponsorUserOperationResult = await paymasterClient.sponsorUserOperation(
    {
      userOperation,
      entryPoint,
    },
  )

Error: TypeError: Cannot convert undefined to a BigInt

On calling "pm_sponsorUserOperation" method directly I found preVerificationGas, verificationGasLimit, and callGasLimit are undefined but valid paymasterAndData, this throws sponsorUserOperation.

RPC Error in providerToSmartAccountSigner for web3auth provider

I am getting internal json rpc error when using providerToSmartAccountSigner to convert web3auth provider to smart account signer.
It seems internally permissionless is trying to call eth_requestAccounts using the web3auth provider, but web3auth provider is transfering that call to the rpc which is set when configuring chain in web3auth.

It works if we provider signerAddress to providerToSmartAccountSigner, or if we use Web3.js to convert web3auth provider to Web3Provider then calling web3Provider.eth.getAccounts() to fetch eoa address.

Package versions being used:-

"@web3auth/base": "^8.0.0",
"@web3auth/ethereum-provider": "^8.0.1",
"@web3auth/no-modal": "^8.0.1",
"@web3auth/openlogin-adapter": "^8.0.1",
"permissionless": "^0.1.18",
"viem": "^2.9.23",
"wagmi": "^2.5.20",
"web3": "^4.5.0"

Working Code:-

const web3authProvider = web3auth.provider;
const web3 = new Web3(web3authProvider);
const [_address] = await web3.eth.getAccounts();

const smartAccountSigner = await providerToSmartAccountSigner(web3authProvider, {
  signerAddress: _address,
});

Not Working Code:-

const web3authProvider = web3auth.provider;
const smartAccountSigner = await providerToSmartAccountSigner(web3authProvider);

Error:-

"The method eth_requestAccounts does not exist/is not available"

Culprit Code inside permissionless:-

export const providerToSmartAccountSigner = async (
    provider: EIP1193Provider,
    params?: {
        signerAddress: Hex
    }
) => {
    let account: Hex
    if (!params) {
        ;[account] = await provider.request({ method: "eth_requestAccounts" })
    } else {
        account = params.signerAddress
    }
    const walletClient = createWalletClient({
        account: account as Hex,
        transport: custom(provider)
    })
    return walletClientToSmartAccountSigner(walletClient)
}

getTypesForEIP712Domain error

Wagmi + Viem + AA upgrade === disaster.

Anyone seen this error:

../../node_modules/permissionless/actions/smartAccount/signTypedData.ts:137:49

 const types = {
> 137 |         EIP712Domain: getTypesForEIP712Domain({ domain }),
      |                                                 ^
  138 |         ...(types_ as TTypedData)
  139 |     }
'((TTypedData extends { [x: string]: readonly TypedDataParameter[]; [x: `string[${string}]`]: undefined; [x: `function[${string}]`]: undefined; [x: `address[${string}]`]: undefined; [x: `uint32[${string}]`]: undefined; [x: `bytes[${string}]`]: undefined; [x: `uint256[${string}]`]: undefined; [x: `bytes32[${string}]`]...' is not assignable to type 'TypedDataDomain | undefined'.
  Type '(TTypedData extends { [x: string]: readonly TypedDataParameter[]; [x: `string[${string}]`]: undefined; [x: `function[${string}]`]: undefined; [x: `address[${string}]`]: undefined; [x: `uint32[${string}]`]: undefined; [x: `bytes[${string}]`]: undefined; [x: `uint256[${string}]`]: undefined; [x: `bytes32[${string}]`]:...' is not assignable to type 'TypedDataDomain | undefined'.
    Type 'unknown' is not assignable to type 'TypedDataDomain | undefined'.
   
    "viem": "2.9.3",
    "wagmi": "2.5.12",
        "@alchemy/aa-accounts": "3.6.1",
        "@alchemy/aa-alchemy": "3.7.0",
        "@alchemy/aa-core": "3.6.1",
        "@alchemy/aa-ethers": "3.6.1",
        "@alchemy/aa-signers": "3.6.1",





   

Question: When exactly the promise from `smartAccountClient.sendTransaction` is resolved?

I just wanted to understand how implementation of smartAccountClient.sendTransaction compares to viem's walletClient.sendTransaction.

When using sendTransaction from viem, promise is resolved almost instantly after confirming it in a wallet and it returns txHash. Then when I call waitForTransactionReceipt it takes longer time and resolves only after transaction is confirmed and it shows success state on etherscan.

On the other hand, when calling smartAccountClient.sendTransaction, it takes super long for it to resolve and to return txHash. However, after txHash is resolved, calling waitForTransactionReceipt for it resolves almost immediately.

So it kind of looks that smartAccountClient.sendTransaction resolves only after transaction is fully confirmed on block explorer and there is no way to derive txHash before that.

I'll appreciate any explanation and potential hints to get transaction hash faster ๐Ÿ™

Handling of erroneous transactions

Consider this basic use case: I have a 0.5 ETH balance in my smart account, but I try to transfer 1ETH.

If I try to sendTransaction from a Viem client linked to an EOA, the operation fails before sending the transaction.

Conversely, if I do the same in a Smart Account (in our case via Kernel), the transaction is sent (and paid) "successfully", but checking on Etherscan we see that the UserOp is ofc reverted.

What would be the proper way of simulating the UserOp before actually sending it to the blockchain?

Shouldn't the UserOp be simulated as well, according to the spec? https://eips.ethereum.org/EIPS/eip-4337#-eth_estimateuseroperationgas

getSenderAddress not working on tenderly fork

Not sure if this is a tenderly issue or if this package would need to support tenderly nuances specifically.

Tenderly will just return which fails to parse the data:

ContractFunctionExecutionError: The contract function "getSenderAddress" reverted with the following reason:
execution reverted: execution reverted

Contract Call:
  address:   0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789
  function:  getSenderAddress(bytes initCode)
  args:                      (0x5de4839a76cf55d0c90e2061ef4386d962E15ae3296601cd000000000000000000000000d3f582f6b4814e989ee8e96bc3175320b5a540ab000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d1f57894000000000000000000000000d9ab5096a832b9ce79914329daee236f8eea039000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000014fBF18dD23e85d0b0d83D13c9362736dEbb811d4c00000000000000000000000000000000000000000000000000000000000000000000000000000000)

pm_sponsorUserOperation calldata hex contains 'NaN'

Executing a write function on a contract
with

  • viem 2.7.1
  • permissionless 0.0.35
    results in
Validation error: not valid hex data at "params[0].callData"

Following Use Kernel Account how-to very closely gets me these logs:

Error: The method does not exist / is not available.

URL: https://api.pimlico.io/v2/arbitrum-sepolia/rpc?apikey=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Request body: {"method":"pm_sponsorUserOperation","params":[{"sender":"0x6DcEEd434A4356e51583952974e228FCEbb64Db6","nonce":"0x1","initCode":"0x","callData":"0x519454470000000000000000000000009cc9ee1f0009025a981f2a9d785b648fdf6f4d1d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084fc9c5dfb0000000000000000000000000000000000000000000000000000000000000NaN00000000000000000000000001e36d100dba45e62924307adf7c42c9c60d6214000000000000000000000000187de399100aa962f209aa78621f5138aca6111f00000000000000000000000000000000000000000000000000005838928b100000000000000000000000000000000000000000000000000000000000","paymasterAndData":"0x","signature":"0x00000000fffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c","maxFeePerGas":"0x7270e00","maxPriorityFeePerGas":"0x0","callGasLimit":"0x0","verificationGasLimit":"0x0","preVerificationGas":"0x0"},"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"]}

Details: Validation error: not valid hex data at "params[0].callData"
Version: [email protected]

Compile error This expression is not callable. Type 'never' has no call signatures.

I am getting this error when running npm run build for my nodejs app

node_modules/permissionless/utils/getAction.ts:10:9 - error TS2349: This expression is not callable.
Type 'never' has no call signatures.

10 (
~
11 client as Client & {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
13 }
~~~~~~~~~~~~~
14 )[actionName]?.(...params) ?? action(client, ...params)
~~~~~~~~~~~~~~~~~~~~~

Found 1 error in node_modules/permissionless/utils/getAction.ts:10

Here is my ts.config file

{
  "compilerOptions": {
    "module": "CommonJS",
    "target": "ES2021",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "outDir": "./build",
    "sourceMap": true,
    "skipLibCheck": true,
    "resolveJsonModule":true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}

TypeScript Error with override Keyword in SendUserOperationError Class

Issue Description
I am encountering a TypeScript compilation error related to the SendUserOperationError class in the permissionless library. The issue seems to arise from the use of the override keyword in a class member that is not present in the base class BaseError.

Error Message
node_modules/permissionless/errors/sendUserOperation.ts:10:14 - error TS4113: This member cannot have an 'override' modifier because it is not declared in the base class 'BaseError'.

Steps to Reproduce

  1. Include the permissionless library in a TypeScript project.
  2. Run TypeScript compilation.
  3. The above error is encountered.

Attempted Workarounds

  • Adjusted tsconfig.json with "skipLibCheck": true, but the issue persists.
  • Created a custom .d.ts file to override the problematic class, but this hasn't resolved the issue.
  • Attempted patching the module, but encountered issues when deploying on our EC2 instance.

Possible Solution
It seems that the override keyword is used in a derived class where the base class (BaseError) does not declare the member being overridden. Removing the override keyword or adjusting the base class to include this member might resolve this issue.

Feature request: Complete support of kernel smart account

It could be very nice to have a complete support of the kernel smart account.

The pr: #42 only contain very basic implementation of a kernel smart account with an ecdsa validator, and sending transaction only via that default validator using the sudo mode.

Supporting other validator, enabling validator on the fly, or using validator enabled but not default one, is missing from that implementation.

If someone is brave enough, and have enough time, to implement that, here is a quick graph of how the validator stuff work with the kernel smart account: https://excalidraw.com/#json=-gCgSizH7vZ7ULgv2IS9T,Z5P0QeeNxRxp6StJNvdCYA

Feature request: Set timeout & polling interval when sending transactions from a SmartAccountClient

It could be nice to have the options to specify the polling interval & timeout when calling .sendTransaction(...) and .sendTransactions(...) method via SmartAccountClient

Something like that:

smartAccountClient.sendTransactions({
    transactions,
    polling: {
        intervalInMs: 4_000,
        timeoutInMs: 120_000
    }
})

Btw, having a single entry point for single & batched could be awesome, like supporting in the .sendTransactions(...) method an array or a single tx

BigInt literals are not available when targeting lower than ES2020

Hi,

It would be cool if you can convert bigint literals to BigInt() form, so targets lower than ES2020 are supported.

Example:

const multiplier = userOperation.paymasterAndData.length > 2 ? 3n : 1n

can be converted to:

const multiplier = userOperation.paymasterAndData.length > 2 ? BigInt(3) : BigInt(1)

Wagmi Connectors: `useWalletClient` not working

I'm successfully running the Wagmi Demo: packages/wagmi-test-demo

I'm doing a small modification and adding in App.tsx

const { data: client } = useWalletClient()

and changing the sendTransactionOnButtonPress to

const sendTransactionOnButtonPress = async () => {
    client?.sendTransaction({
        to: "0xe0a942ff2e1724A2fe10627728bE327a43fE8C26",
        value: 100n,
        chain: sepolia,
    });
};

I'm getting this error.

TransactionExecutionError: The method does not exist / is not available.

custom endpoint address

I am working on a private chain with a custom endpoint address. It conforms to v0.7, but it seems permissionlessjs makes some strong assumptions that an entrypoint is always one of the two widely deployed entrypoint addresses. Am I missing something that would allow me to have a custom entrypoint address?

Unable to resolve file when using React Native

Hi guys,
I'm facing an issue when using React Native. The cause is that this library uses 'import '.js'' while the file itself is '.ts'. This doesn't happen when using plain Node.js. Could you please advise on how to resolve this? Thank you.

image

TypeError: parameters.transport is not a function

I'm trying to replicate a demo example that is shown on the Pimlico dashboard (https://dashboard.pimlico.io/onboarding), but it running node index.js reverts with an error.

Here is my package.json:

{
  "name": "pimlico",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "type": "module",
  "author": "",
  "license": "ISC",
  "dependencies": {
    "permissionless": "^0.1.4",
    "viem": "^2.7.19"
  }
}

Here is my main.js (basically the same code as shown in the demo, but in Javascript instead of Typescript):

import { createSmartAccountClient } from "permissionless";
import { privateKeyToSimpleSmartAccount } from "permissionless/accounts";
import { http } from "viem";
import { sepolia } from "viem/chains";
import { bundlerClient, paymasterClient, publicClient } from "./clients.js";

(async function () {
const account = await privateKeyToSimpleSmartAccount(publicClient, {
	privateKey:
		"0x36e512afe490fed9b9e89e3be886640083050dee973d6c913511870ee2a51cc9",
	factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454", // simple account factory
	entryPoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", // global entrypoint
});

const smartAccountClient = createSmartAccountClient({
	account,
	chain: sepolia,
	transport: http(
		"https://api.pimlico.io/v1/mumbai/rpc?apikey=21...12", // API key truncated for privacy, it's actually a valid value
	),
	sponsorUserOperation: paymasterClient.sponsorUserOperation,
});

const gasPrices = await bundlerClient.getUserOperationGasPrice()

const txHash = await smartAccountClient.sendTransaction({
	to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
	value: 0n,
	data: "0x1234",
    maxFeePerGas: gasPrices.fast.maxFeePerGas,
    maxPriorityFeePerGas: gasPrices.fast.maxPriorityFeePerGas,
});
})();

And here is clients.js:

import { createPimlicoBundlerClient, createPimlicoPaymasterClient } from "permissionless/clients/pimlico";
import { createPublicClient, http } from "viem";

export const publicClient = createPublicClient({
	transport: http("https://rpc.ankr.com/polygon_mumbai"),
});

export const bundlerClient = createPimlicoBundlerClient({
	transport: http(
		"https://api.pimlico.io/v1/mumbai/rpc?apikey=21....12", // API key truncated for privacy, it's actually a valid value
	),
});

export const paymasterClient = createPimlicoPaymasterClient({
	transport: http(
		"https://api.pimlico.io/v2/mumbai/rpc?apikey=21....12", // API key truncated for privacy, it's actually a valid value
	),
});

The error I've been getting is the following:

node_modules/viem/_esm/clients/createClient.js:9
const { config, request, value } = parameters.transport({
^

TypeError: parameters.transport is not a function

I get an error running node index.js

Missing js output files

Tried to compile nodejs project that imports from permissionless/clients/pimlico and permissionless/accounts into binary form, with pkg. Ran into error that those modules were missing. Resolved by manually navigating into those folders and transpiling TS into JS.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.