Code Monkey home page Code Monkey logo

js-multiaddr's Introduction

@multiformats/multiaddr

multiformats.io codecov CI

multiaddr implementation (binary + string representation of network addresses)

About

A standard way to represent addresses that

  • support any standard network protocol
  • are self-describing
  • have a binary packed format
  • have a nice string representation
  • encapsulate well

Example

import { multiaddr } from '@multiformats/multiaddr'
const addr =  multiaddr("/ip4/127.0.0.1/udp/1234")
// Multiaddr(/ip4/127.0.0.1/udp/1234)

const addr = multiaddr("/ip4/127.0.0.1/udp/1234")
// Multiaddr(/ip4/127.0.0.1/udp/1234)

addr.bytes
// <Uint8Array 04 7f 00 00 01 11 04 d2>

addr.toString()
// '/ip4/127.0.0.1/udp/1234'

addr.protos()
// [
//   {code: 4, name: 'ip4', size: 32},
//   {code: 273, name: 'udp', size: 16}
// ]

// gives you an object that is friendly with what Node.js core modules expect for addresses
addr.nodeAddress()
// {
//   family: 4,
//   port: 1234,
//   address: "127.0.0.1"
// }

addr.encapsulate('/sctp/5678')
// Multiaddr(/ip4/127.0.0.1/udp/1234/sctp/5678)

Resolving DNSADDR addresses

DNSADDR is a spec that allows storing a TXT DNS record that contains a Multiaddr.

To resolve DNSADDR addresses, call the .resolve() function the multiaddr, optionally passing a DNS resolver.

DNSADDR addresses can resolve to multiple multiaddrs, since there is no limit to the number of TXT records that can be stored.

Example - Resolving DNSADDR Multiaddrs

import { multiaddr, resolvers } from '@multiformats/multiaddr'
import { dnsaddr } from '@multiformats/multiaddr/resolvers'

resolvers.set('dnsaddr', dnsaddr)

const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io')

// resolve with a 5s timeout
const resolved = await ma.resolve({
  signal: AbortSignal.timeout(5000)
})

console.info(await ma.resolve(resolved)
// [Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...')...]

Example - Using a custom DNS resolver to resolve DNSADDR Multiaddrs

See the docs for @multiformats/dns for a full breakdown of how to specify multiple resolvers or resolvers that can be used for specific TLDs.

import { multiaddr } from '@multiformats/multiaddr'
import { dns } from '@multiformats/dns'
import { dnsJsonOverHttps } from '@multiformats/dns/resolvers'

const resolver = dns({
  '.': dnsJsonOverHttps('https://cloudflare-dns.com/dns-query')
})

const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io')
const resolved = await ma.resolve({
 dns: resolver
})

console.info(resolved)
// [Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...')...]

Install

$ npm i @multiformats/multiaddr

Browser <script> tag

Loading this module through a script tag will make it's exports available as MultiformatsMultiaddr in the global namespace.

<script src="https://unpkg.com/@multiformats/multiaddr/dist/index.min.js"></script>

API Docs

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

js-multiaddr's People

Contributors

achingbrain avatar alanshaw avatar binarybaron avatar daviddias avatar dependabot-preview[bot] avatar dependabot[bot] avatar dignifiedquire avatar dryajov avatar greenkeeper[bot] avatar hugomrdias avatar jacobheun avatar jbenet avatar lidel avatar marcopolo avatar mkg20001 avatar mpetrunic avatar nijynot avatar npmcdn-to-unpkg-bot avatar olizilla avatar richardlitt avatar semantic-release-bot avatar stebalien avatar tabcat avatar twoeths avatar vasco-santos avatar victorb avatar vmx avatar web3-bot avatar wemeetagain avatar zcstarr 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-multiaddr's Issues

Outdated README.md

Hi! Currently I'm looking at README.md and have some notes:

  • the npm project name is @multiformats/multiaddr but in README multiaddr is used.
    An example: npm i multiaddr in "Install" section
  • Since v10.1.0 the package can only be loaded via import. require('@multiformats/multiaddr') will throw as there is no exports for it.
  • Why non-breaking spaces are used in README.md? Four such spaces are used in "Usage" section.

I would like to create a PR to fix the above if you can confirm it.

getPeerId can return an unexpected peer id

.getPeerId() returns the peer id from a multiaddr if one is present but it may not be the one we expect.

If the mulitaddr is a relay address but doesn't have the relay client's peer id in the address, the peer id returned is that of the relay.

I believe the intention of .getPeerId is to return the peer id of the remote peer that can be dialled using the peer id, not just any peer id that happens to be in the multiaddr.

We could fix this by treating p2p-circuit as a special case and returning the value part of the p2p-circuit tuple if found, or more generally by only returning a peer id if it's in the final tuple?

Refs: libp2p/js-libp2p#1680

Encapsulation/decapsulation semantics are backwards

The docs say:

addr.encapsulate(str)
Returns a new multiaddress that encapsulates addr in a new protocol string, str.

addr.encapsulate('/sctp/5678')
// <Multiaddr /ip4/127.0.0.1/udp/1234/sctp/5678>

I am fairly sure this is intended to illustrate RFC6951 encapsulation. However, the RFC clearly states that STCP is "encapsulated into" UDP (passive) or, more plainly, UDP encapsulates STCP. So, in this case the docs can be corrected to something like "Returns a new multiaddress that encapsulates a new protocol in the stack already specified by addr"

However, the semantics of decapsulate are wrong at the API level:

addr.decapsulate(str)
Returns a new multiaddress with the right-most protocol string str removed.

multiaddress('/ip4/127.0.0.1/udp/1234').decapsulate('/udp')
// <Multiaddr /ip4/127.0.0.1>

Let's extend this to a fuller example:

<Multiaddr 043692e377062329a5032212204ca777e3b2d5d6dc5524ddb742b3b3fd3ce19e8ef11e3e6172dcc42f73638859 - /ip4/54.146.227.119/tcp/9001/ipfs/QmTVsocFCSEdPyM8dZ734GRhjvvmYyL9fShyezVkbPj17E>
> m.decapsulate('/ip4')
<Multiaddr  - />
> m.decapsulate('/tcp')
<Multiaddr 043692e377 - /ip4/54.146.227.119>
> m.decapsulate('/ipfs')
<Multiaddr 043692e377062329 - /ip4/54.146.227.119/tcp/9001>

There's two problems with this.

One: the API should specify either the outer layer which to strip (as in https://loicpefferkorn.net/ipdecap/) or the inner layer which to return https://tools.ietf.org/html/rfc3948#section-3.3

Two: there appears to be no way to actually get the innermost protocol using these calls -- please correct me if I'm wrong

Both of these issues can be corrected by returning a tuple of [outer, inner] multiaddresses from the decapsulate call.

The current behavior can also be preserved as a getEncapsulatingProtocol method.

Export Multiaddr to allow type checking

declare class Multiaddr {

Right now, only the constructor and the static methods are exported. This limits the usage to sth like

let x = Multiaddr('...')

but it does not allow requiring Multiaddr as e.g. function parameters

function foo(ma: Multiaddr): void {
    // do sth. nice
}

Adding this might help

export { Multiaddr }

Quick validate if a string is a multi address

I was not able to find in the docs and I am not sure if there is something for that:
What I want to achieve is a clean way to test if an string is a multi address.

I am not sure if is-ipfs is helping, but I would like to validate specific multiaddr

Is there anything out there? If something pops up, I will comment a link here so other people can find it.

Add a static method `isValid`

I think a static method that checks whether a string or JavaScript Object nodeAddress is a valid Multiaddr or not would be nice to have.

Example:

const validAddr = '/ip4/0.0.0.0/tcp/0';
const notValidAddr1 = '/ip4/0.0.0.0/tcp';
const notValidAddr2 = '/ip4/0.0.0.0/ipfs/asdf';
const notValidAddr3 = { family: 123 };

console.log(Multiaddr.isValid(validAddr))
// => true

console.log(Multiaddr.isValid(notValidAddr1))
// => false

console.log(Multiaddr.isValid(notValidAddr2))
// => false

console.log(Multiaddr.isValid(notValidAddr3))
// => false

Would love to know what you guys think - can try to add this if it's of interest.

Current ipv6 implementation doesn't account for interface

Suppose this is my following multiaddr string:

/ip6/fe80::ba27:ebff:fecd:680b%wlp2s0/tcp/5001/p2p/QmVCTgLguTMHTAHKfxQSmML4nUgm33tMrWYKMGxyXeHsVn

After parsing, the host should be

fe80::ba27:ebff:fecd:680b%wlp2s0

but the interface and the % is omitted.

This means that ipv6 link/local addresses are not parsed correctly.
This also creates issues with libp2p-tcp, when attempting to bootstrap a node with a local "neighbor node" as the interface is omitted when converting the string to a multiaddr object.

I've started working on a fix, and will hopefully have a pull request soon, just thought of creating an issue before in case anyone else runs into this

See:
libp2p/js-libp2p-bootstrap#105

Implementation of DNS Support

Created this issue to track the implementation of DNS support in JS and throughout js-libp2p and js-ipfs

Given multiformats/multiaddr#22 (comment), we need:

  • Add support for the DNS code in js-multiaddr
    • .isName method - check if the multiaddr is a name #39
    • .resolve method - resolve the name, if it is a name Needs more consideration, not necessary right now
    • update js-mafmt to for libp2p-webrtc-star to understand that dns is also valid option multiformats/js-mafmt#12
  • libp2p-webrtc-star + DNS
    • Migrate libp2p-webrtc-star signalling to use DNS instead
    • Put a libp2p-webrtc-star signalling behind DNS and a reverse proxy with TLS @lgierth
    • Get @lgierth to get a cert for signal.libp2p.io
    • Ensure that it is all good in apps loaded behind https
  • Migrate repo/.config to have:
    • libp2p key to isolate all libp2p config specifically
    • addrs to listen (listen)
    • addrs to announce (broadcast)
    • addrs to not announce (filter)
    • Add these distinctions to the peerInfo object too
  • Test that a js-ipfs node can dial do a node behind DNS
    • Deploy a node using the dokku thing
    • Test it out
    • Ensure that Identify sends the right addrs

Respect `.../ipfs/...` when it is passed?

With v7.x.x the default name of protocol 421 was changed from ipfs to p2p. This has led to the situation where this test will fail:

it('parses a string and turns it back into a string', () => {
  const addr = '/ip4/73.109.217.58/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm'
  const ma = multiaddr(addr)
  expect(ma.toString()).to.equal(addr)
})

It's weird because you could use ipfs swarm connect .../ipfs/... but then see .../p2p/... in the output of ipfs swarm peers.

Replace Multiaddr class with an interface

Most of ipfs / libp2p stack depends on Multiaddr class which introduces large number of dependencies, it is made worth by the fact that typescript forces all of them to agree on the same exact package to type check.

We should instead introduce Multiaddr interface and type our APIs so they take / produce value compatible with that interface. That way they become implementation agnostic allowing us to swap / upgrade implementation without coordinating these changes across the board.

Multiaddr Implementation in this library will just become a one implementation of that interface.

Having issues connecting to Substrate Network

I'm trying to connect to the Polkadot Substrate network and it looks like the multiaddr library is converting all p2p protocol into ipfs

So while I'm able to ping bootnodes for IPFS network, when I try to ping bootnodes for Substrate, I get errors like
Error: dialed to the wrong peer, Ids do not match
or
Error: No available transports to dial peer

I feel like one of the reason is that when I run the command to ping an address like
/ip4/40.117.153.33/tcp/30363/p2p/QmPiGU1jwL9UDw2FMyMQFr9FdpF9hURKxkfy6PWw6aLsur (one of the substrate bootnodes)
it automatically converts it to an IPFS address
/ip4/40.117.153.33/tcp/30363/ipfs/QmPiGU1jwL9UDw2FMyMQFr9FdpF9hURKxkfy6PWw6aLsur

This seems to be coded in the spec:
https://github.com/multiformats/js-multiaddr/blob/master/test/index.spec.js#L223

This is an extension of the discussions from:
https://discuss.libp2p.io/t/libp2p-on-the-polkadot-network/211/3

The automated release is failing ๐Ÿšจ

๐Ÿšจ The automated release from the master branch failed. ๐Ÿšจ

I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. Iโ€™m sure you can fix this ๐Ÿ’ช.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here are some links that can help you:

If those donโ€™t help, or if this issue is reporting something you think isnโ€™t right, you can always ask the humans behind semantic-release.


Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.

If you are using Two Factor Authentication for your account, set its level to "Authorization only" in your account settings. semantic-release cannot publish with the default "
Authorization and writes" level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.


Good luck with your project โœจ

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€

Transitive dependency on `node-fetch`

Describe the bug

When using Vite as bundler, it will fail when it cannot find node-fetch. However, if node-fetch is installed, the bundler will fail too, since Node API are not available in browser.

โ€‰WARNโ€‰ Issues with peer dependencies found

.
โ””โ”€โ”ฌ libp2p
  โ””โ”€โ”ฌ libp2p-interfaces
    โ””โ”€โ”ฌ multiaddr
      โ””โ”€โ”ฌ dns-over-http-resolver
        โ””โ”€โ”ฌ native-fetch
          โ””โ”€โ”€ โœ• missing peer node-fetch@"*"

To Reproduce

  1. Download this project https://github.com/libp2p/js-libp2p/tree/master/examples/libp2p-in-the-browser
  2. Run pnpm install
  3. Run pnpm start

Expected behavior
multiaddr should not depend on node-fetch

What does js-multiaddr do?

It's not clear from the first textful of README what js-multiaddr does. It's an implementation of multiaddr, but what does that mean? The README should ideally aim to very quickly answer the question "what are the inputs and outputs of this module", or "what does this module do"?

port is returned as string instead of integer

Hello - due to recent attepts to integrate 3box, IPFS and IPLD into native-react we fell over an issue with multiaddr, which causes the native socket component to fault.
The issue in question is:

port: parts[3] // tcp or udp port

The return value of port here is string, as the input type is a string.

  • Can we add a parseInt() for the port here?
  • Are there cases where the port does not contain the port number?

Refer:
libp2p/js-libp2p-tcp#108

Thanks!
Chris

Add toJSON?

If I JSON.stringify(multiaddr('/ip4/127.0.0.1')) I get "{\"buffer\":{\"type\":\"Buffer\",\"data\":[4,127,0,0,1]}}" should it be '/ip4/127.0.0.1' instead?

Invalid ipv4 address are converted to valid ones

Summary: The ipv4 regex here is what node-ip uses to verify valid ip address format, this logic is being used to validate ip addresses , and right now an invalid address 555.555.555.55 will be converted to a valid address and return 43.43.43.55.

Proposal: I think ideally it would make sense that the regex within the ip-node package were fixed, however the project seems like it hasn't been touched in the past year. Alternatively I think it might make sense to just wrap the calls here and here with a regex check and throw an error just like the package would in the event of an ascii character in the ip address.

Make multiaddr extensible on the fly

Currently, we have to add a protocol to protocol.js file so that it can be valid multiaddr and constructed by the module. This is ok for all of the transports that are standard (TCP, HTTP, QUIC, etc), but for new protocols that are beta, or simply used in the domain of libp2p or another, we don't have a way to extend multiaddr.

We could have a primitive for 'add new protocol', the tricky part is that multiaddr is used in several points and comparing to go-multiaddr, js-multiaddr gets scoped per module. A typical solution for this would be to Inject the multiaddr dependency, however, that would be very cumbersome to have to DI the DI each time a different part in the code adds another multiaddr.

Several options to solve this have crossed my mind, but I couldn't really figure out a clean and elegant way that would work in the browser and in Node.js.

The intermediate solution is to update this module with any protocol that we need to use in our application.

Support .nodeAddress() for /dnsaddr

@jacobheun Are there any plans to support conversion to a node address from a dns addr? If so, I can take a stab at it and open a PR. If not, why? Should it be done in some other package?

I also wonder since we would need to check the DNS records if it would need to be async or not. Surely we could keep the API sync.

[ERR_MODULE_NOT_FOUND]: Cannot find package 'dns' imported from /Users/javaspeak/workspace3/symbiont/permanent_node/server/node_modules/@multiformats/multiaddr/dist/src/resolvers/dns.js

Am running ipfs-js and get this error:

[ERR_MODULE_NOT_FOUND]: Cannot find package 'dns' imported from
/Users/javaspeak/workspace3/symbiont/permanent_node/server/node_modules/@multiformats/multiaddr/dist/src/resolvers/dns.js

See:

ipfs/js-ipfs#4161

Not sure what the issue is about.

Any guidance much appreciated.

Thank you

Cannot encode onion address

When I try to call multiaddress() on a onion address like /onion/3g2upl4pq6kufc4m I get an error in codec.bufferToTuples:
Error: Error parsing address: Invalid address buffer: bc03

Any idea how to solve this? Are onion addresses already implemented?

bug: new kubo/ipfs/libp2p protocols break JS ecosystem

Describe the bug
Multiple issues across the JS ecosystem when new protocols are added.

export const names: Record<string, Protocol> = {}
export const codes: Record<number, Protocol> = {}
export const table: Array<[number, number, string, boolean?, boolean?]> = [
[4, 32, 'ip4'],
[6, 16, 'tcp'],
[33, 16, 'dccp'],
[41, 128, 'ip6'],
[42, V, 'ip6zone'],
[43, 8, 'ipcidr'],
[53, V, 'dns', true],
[54, V, 'dns4', true],
[55, V, 'dns6', true],
[56, V, 'dnsaddr', true],
[132, 16, 'sctp'],
[273, 16, 'udp'],
[275, 0, 'p2p-webrtc-star'],
[276, 0, 'p2p-webrtc-direct'],
[277, 0, 'p2p-stardust'],
[280, 0, 'webrtc'],
[290, 0, 'p2p-circuit'],
[301, 0, 'udt'],
[302, 0, 'utp'],
[400, V, 'unix', false, true],
// `ipfs` is added before `p2p` for legacy support.
// All text representations will default to `p2p`, but `ipfs` will
// still be supported
[421, V, 'ipfs'],
// `p2p` is the preferred name for 421, and is now the default
[421, V, 'p2p'],
[443, 0, 'https'],
[444, 96, 'onion'],
[445, 296, 'onion3'],
[446, V, 'garlic64'],
[448, 0, 'tls'],
[460, 0, 'quic'],
[461, 0, 'quic-v1'],
[465, 0, 'webtransport'],
[466, V, 'certhash'],
[477, 0, 'ws'],
[478, 0, 'wss'],
[479, 0, 'p2p-websocket-star'],
[480, 0, 'http'],
[777, V, 'memory']
]
// populate tables
table.forEach(row => {
const proto = createProtocol(...row)
codes[proto.code] = proto
names[proto.name] = proto
})

To Reproduce
Steps to reproduce the behavior:

  1. pull down repo ipfs/ipfs-webui
  2. git checkout ea89e7f
  3. rm patches/multiaddr+8.1.2.patch
  4. npm install
  5. start ipfs daemon using kubo 0.18.1 or later in another terminal
    • Note the port number in the line API server listening on /ip4/127.0.0.1/tcp/<kuboPort>
  6. run KUBO_PORT_2033_TEST=<kuboPort> npm run test:unit -- src/bundles/identity.test.js
  7. Note the error "no protocol with name: quic-v1"

Expected behavior
Looking up unknown protocols does not propagate errors, nor cause requests to fail. We should fallback to supported/known protocols

Additional context

Potential Solutions

  1. Pull out protocols-table.js into it's own package. Keep it at v1.0.x, there are NO breaking changes, only protocols added. Any JS package stays up to date by depending directly on the table
  2. Stop throwing errors from
    export function getProtocol (proto: number | string): Protocol {
    if (typeof proto === 'number') {
    if (codes[proto] != null) {
    return codes[proto]
    }
    throw new Error(`no protocol with code: ${proto}`)
    } else if (typeof proto === 'string') {
    if (names[proto] != null) {
    return names[proto]
    }
    throw new Error(`no protocol with name: ${proto}`)
    }
    throw new Error(`invalid protocol id type: ${typeof proto}`)
    }
    , because different packages in the ecosystem are not handling this properly.
  3. backport any protocol-table changes for all multiaddr versions (No one wants to do this)

Protocol p2p missing from list

Canonical CSV states "p2p preferred over ipfs" -

https://github.com/multiformats/multiaddr/blob/master/protocols.csv#L15

JS implementation is currently missing this new name/"alias" -

https://github.com/multiformats/js-multiaddr/blob/master/src/protocols-table.js#L39

Not a huge issue since specifying the /ip4/127.0.0.1/tcp/30333/ipfs/QmWLtV5gpCzJCh9Eo7SxkrT3ZTApovHM1WpCY2Lp3XkaqF does work, however a bit of an annoyance when one implementation (Rust) reports the protocol with /p2p/ and there is some editing before it can be used in a JS client connecting to it.

However, it works, so not a massive issue apart from being a (small) annoyance.

Missing protocols in protocols-table.js

Hi there,

Please can you tell me why several of the protocols from protocols.csv are missing from the protocols-table.js.

I was sitting down to write a scala version multiaddr. The js version of multiaddr seems to be the canonical version from which I should copy. Just want to check I am not missing anything.

Thanks!

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.