fortunejs / fortune Goto Github PK
View Code? Open in Web Editor NEWNon-native graph database abstraction layer for Node.js and web browsers.
Home Page: http://fortune.js.org
License: MIT License
Non-native graph database abstraction layer for Node.js and web browsers.
Home Page: http://fortune.js.org
License: MIT License
In the Guide you have
app.resource('person', {
name: String,
spouse: {ref: 'person', inverse: 'spouse'},
lovers: [{ref: 'person', inverse: 'lovers'}]
});
app.after('person', function(request, response) {
delete this.links.lovers;
return this;
});
Shouldn't that be
delete this.lovers;
(i.e. no ".links")?
Thanks.
-Shaun
Resources could really use a way of getting all of the data at once. findMany is a bit confusing to use, I can't figure out how to get all the data for a specific resource.
myResource.adapter.toJSON()
would work nicely.
Hi All,
Is it possible to change the adapter during runtime? For example having a resource available at ~/resource1, but after calling a function change for the adapter to point at ~/resource2.
Is this possible or would a new instance of Fortune need to be created?
Cheers
Scott
I am looking to be involved in rewrite. Is there anything I can do to help fortune move faster?
I'm trying to do a post via postman and if the form-data tab in postman is selected fortune crashes and I get this in the terminal TypeError: Cannot read property 'split' of undefined
.
My app looks like this.
var fortune = require('fortune');
options = {
adapter: 'nedb',
host: 'localhost',
flags: {
inMemoryOnly: false,
filename: 'data.db',
autoload: true
}
};
var app = fortune(options);
app.resource('item',{
name: String
});
app.listen(1337);
The database is being created when I post.
What am I doing wrong and how would I do a post in postman?
Thanks.
Hi,
I tried to perform an "add" operation using PATCH, does not seem to work. Nothing is added.
"replace" an existing field works perfectly.
I did try to "replace" a non existing field, and it added as expected for the "add" operation.
Syntax that I used:
[{"op":"add","path":"/cells/0/title","value":"My cell"}]
Thanks for your help
I used Postman to try the request
Hello,
while using this software with an empty repo, copied your basic example with these dependencies:
"dependencies": {
"fortune": "^0.2.4",
"fortune-mongodb": "^0.2.2"
}
app.js
var fortune = require('fortune')
, app = fortune({
adapter: 'mongodb',
db: 'petstore'
})
.resource('person', {
name: String,
age: Number,
pets: ['pet'] // "has many" relationship to pets
})
.resource('pet', {
name: String,
age: Number,
owner: 'person' // "belongs to" relationship to a person
})
.listen(1337);
I'm trying to creating a resource, with this json:
{"pets":
{
"name": "Dog",
"age": 18
}
}
The response is the following a 400 with this:
{
"error": "Request was malformed.",
"detail": "TypeError: Object #<Object> has no method 'forEach'"
}
And this is the trace on console:
Trace: [TypeError: Cannot call method 'forEach' of undefined]
at sendError (/Users/<user>/Projects/PetExample/node_modules/fortune/lib/route.js:43:26)
at createResources (/Users/<user>/Projects/PetExample/node_modules/fortune/lib/route.js:238:16)
at /Users/<user>/Projects/PetExample/node_modules/fortune/lib/route.js:136:5
at Layer.handle [as handle_request] (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/layer.js:76:5)
at next (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/route.js:100:13)
at Route.dispatch (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/route.js:81:3)
at Layer.handle [as handle_request] (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/layer.js:76:5)
at /Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:227:24
at Function.proto.process_params (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:305:12)
at /Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:221:12
TypeError: Cannot call method 'then' of undefined
at /Users/<user>/Projects/PetExample/node_modules/fortune/lib/route.js:139:6
at Layer.handle [as handle_request] (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/layer.js:76:5)
at next (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/route.js:100:13)
at Route.dispatch (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/route.js:81:3)
at Layer.handle [as handle_request] (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/layer.js:76:5)
at /Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:227:24
at Function.proto.process_params (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:305:12)
at /Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:221:12
at Function.match_layer (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:288:3)
at next (/Users/<user>/Projects/PetExample/node_modules/fortune/node_modules/express/lib/router/index.js:182:10)
What's I'm doing wrong?
Ever thought about such support? Similar to how SailsJs provides Socket support to the resources/models.
Principals defined here:
http://rocket.github.io
Right now the package needs mongoose
and orm
in order to work, but if you are using the default adapter you don't need orm
support and vice versa. And for someone like me who doesn't have any of them the module just fails to start:
events.js:71
throw arguments[1]; // Unhandled 'error' event
^
Error: failed to connect to [localhost:27017]
at Server.connect.connectionPool.on.server._serverState (/home/alejandro/code/fnz/node_modules/fortune/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:540:74)
at EventEmitter.emit (events.js:126:20)
at connection.on._self._poolState (/home/alejandro/code/fnz/node_modules/fortune/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:140:15)
at EventEmitter.emit (events.js:99:17)
at Socket.errorHandler (/home/alejandro/code/fnz/node_modules/fortune/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:478:10)
at Socket.EventEmitter.emit (events.js:96:17)
at Socket._destroy.self.errorEmitted (net.js:329:14)
at process.startup.processNextTick.process._tickCallback (node.js:245:9)
So, I think is a good idea to modularize the custom adapters and with this you can let the user to choose whatever he/she wants. Also with this we'll be able to create custom adapters for more databases or clients. e.g:
var fortune = require('fortune');
var couch = require('fortune-couch');
var driver = fortune({
adapter: couch
});
cheers
Is there a publicly supported manner of getting access to a given request's headers somewhere such that I can access them or pass them along to a custom adapter?
My use case is that I have an adapter that will be talking to another web service rather than a database directly. To support that, I'll need to pass along authentication data for the current request to that web service
*Edit I should mention that I'm working against the rewrite
branch
If I want to serve my posts form myapp.com/posts
, then shouldn't I be able to serve the API from myapp.com/posts.json
?
Is this frowned upon? Does this go against the spirit of Fortune.js?
decoupling fortune from being only a server to middleware means it will be usable across far more scenarios.
As it is now, I can't use fortune since I'm forced to use an existing http.Server
Loving FortuneJS so far. <3
I'm trying to write a repeatable test scenario, so engaging NeDB's memory-only mode would be perfect. I've tried something like this:
options = {
adapter: 'nedb',
host: 'localhost',
namespace: '/api/v1',
flags: {
inMemoryOnly: true,
filename: '',
autoload: false
}
};
app = fortune(options);
Even though I'm not setting options.db
, nothing seems to stop the default NeDB adapter from setting a location on disk. Is there something else I can try?
Is there a reason why only the "replace" operation of RFC 6902 was implemented in Fortune? The lack of add is preventing many-to-many operations from being possible.
If I have two users and one group and add both users to the group, the users each belong to one group and the group has two users. This is one-to-many.
If I create another group and try to add that group to one of the users, the new group should be added to to the specified user. Basically, we'd end up with the following: many-to-many relationship:
User A
....Group A
....Group B
User B
....Group A
Group A
....User A
....User B
Group B
....User A
Instead, with only "replace", the PATCH will replace the old group for that user and each user will end up belonging to one group (different groups) and each group has one user. i.e.
User A
....Group B
User B
....Group A
Group A
....User B
Group B
....User A
What I need to be able to do is PATCH add.
At this very moment I am looking at the code trying to determine the best way to create support for the "add" and "remove" operations of RFC 6902. If you or anyone else has already looked into this, I'd sincerely appreciate knowing about any gotchas or algorithmic limitations sooner than later. Thanks!
At the moment, if you change a field name in the API schema, the old field is ignored in new API requests.
It might be a better approach to just return the entire document, instead of only what's in the schema.
Just trying to get fortune up and running with a simple test, with this:
var fortune = require('fortune');
fortune()
.resource('book', {
title: String
})
.listen('3000');
Which is working fine listening, and /books returns { "books": [ ] }
as expected. But when I try to POST to create a new book, like this:
$ curl -X POST -H "Content-Type: application/json" -d '{"title":"A Storm of Swords"}' http://localhost:3000/books
I get the following, somewhat unspecific error.
{
"error": "Request was malformed.",
"detail": "TypeError: Cannot call method 'forEach' of undefined"
}
Thanks!
I was going to submit a PR to fix one instance of this but thought it might be good to have a discussion about whether this is something you want to "fix" first, and how to best do it across the board.
In issue #41, I mentioned that I was receiving an error on POST that looks like this:
{
"error": "Request was malformed.",
"detail": "TypeError: Cannot call method 'forEach' of undefined"
}
I tracked it down to the sendError method, then to the fact that I had sent my POST request as one single JSON object instead of a hash with a key of "books" and a value containing an array of book objects to create. That functionality itself is kind of weird but it's being debated at the json-api level (json-api/json-api#131).
But here, since the try/catch block returns an error object that just gets sent along to the sendError method, Fortune is usually returning a standard JavaScript exception error to the user. Shouldn't API end users receive error messages that pertain to the formatting error that they made in their request, and not the specific code error that triggered the exception?
A fix for that block of code might look something like this:
try {
req.body[collection].forEach(function(resource) {
before.push(beforeTransform(resource, req, res));
});
} catch(error) {
console.error(error);
return sendError(req, res, 400, "Resource definitions must be enclosed in a hash/array, e.g. { '" + collection + "': [ { resource definition } ] }");
}
Hey there! I just wanted to let you know that JSON API has hit RC3, and we'd like client libraries to start implementing it like it was 1.0, as a final check that we're good for 1.0. I wanted to make this issue to let you know!
this allows related resources to be sideloaded by clients such as ember data.
The adapter.find
and adapter.findMany
methods should have the same public interface for arbitrary queries.
Any of them should be customizable, but specifically I need to customize headers to pass additional authorization credentials. I'm thinking of implementing something like this:
fortune({
db: "...",
host: "...",
cors: {
headers: ["X-SignedInAs"],
origins: ["localhost:3000"/*, ... */],
methods: ["POST", "PUT"],
credentials: false
}
})
//...
If a user chooses not to customize any of these options, they could just pass "true" or "false" as they can today. The headers would default to the same values currently hardcoded in the allowCrossDomain
middleware.
What do you think of this? Would you accept a PR for such customization?
Query-string syntax to filter, sort, and paginate. Example:
?filter={"name":"daliwali"}&sort={"age":1}&page=1
The findMany
method in the adapter already supports finding resources by arbitrary queries, but pagination might be tricky.
I'm trying to golf a blog with fortune, and need to serve a homepage.
How can I, entirely using the fortune namespace, serve static assets from a directory?
Have you thought about this? I was thinking about a PR, but wanted to see if there were any specific reasons why you'd not implemented this.
Would be nice to apple filters like so:
app.resource('user', {
name: String,
createdAt: Date,
updatedAt: Date,
password: String,
salt: Buffer,
tokens: ['token']
})
.before(timestamp)
.before(defaults)
.before(createOrUpdate.before)
.after(createOrUpdate.after);
Hi all
Is it possible to generate an owner and his child in one post request?
Let's assume you use fortune.js for a customer db and you want to create a customer that owns an address. How can you accomplish this in one request so you do not have to wait for the callback of the newly generated customer id?
Thanks,
Das Einhorn
current the api is as follows:
function(resolve, reject, request) {
var authorization = request.get('Authorization');
if(!authorization) return reject();
this.authorization = authorization;
resolve(this);
}
Proposed api:
function(request) {
var authorization = request.get('Authorization');
if(!authorization) throw new Error('Authorization Failed');
this.authorization = authorization;
return this;
}
callback callsite:
new RSVP.Promise(function(resolve){
resolve(callback(args));
});
Why this proposal?
I miss the doc site + hate having to go to webarchive :(
http://web.archive.org/web/20141124092832/http://fortunejs.com/docs/
There doesn't seem to be a way to get access to the http.Server object for a given Fortune instance. This can be handy when access to the methods for http.Server or net.Server is desired.
A comment in the Express code explains how you might gain access to the server object (in a pure-Express app):
var http = require('http')
, https = require('https')
, express = require('express')
, app = express();
http.createServer(app).listen(80);
https.createServer({ ... }, app).listen(443);
The listen method on a pure-Express app also returns the http.Server object, for convenience.
Fortune's listen method is chainable (returning this
) so this probably wouldn't be the approach for this project.
Perhaps the http.Server object could be saved to app.server
, just as app.router
stores a reference to the Express instance?
In the meantime, we could explicitly call server = app.router.listen(80)
, but it would be nice if there was convenient and official access to it somewhere.
Definitely loving Fortune so far. I think Node.JS has needed something like Fortune for a long time. <3
Hi, I have this resources definition:
/**
* Created by aldo on 5/4/14.
*/
var fortune = require('fortune')
, express = fortune.express;
var container = express()
, port = process.argv[2] || 1337;
var app = fortune({
db: 'fortune-admin',
adapter: 'mongodb',
namespace: '/api/v1'
})
.resource('user', {
title : String,
firstName : String,
lastName : String,
role : String,
email : String,
nationality: String,
languageCode: String,
addresses: ['address']
}).transform(
function (request) {
console.log(request.body);
}
)
.resource('address', {
type: String,
addressLine1: String,
addressLine2: String,
addressLine3: String,
addressLine4: String,
city: String,
region: String,
postCode: String,
country: String,
dateDeleted: Date,
user: { ref: "user", inverse: "addresses" }
});
container
.use(express.static(__dirname + '/public/app'))
.use(express.static(__dirname + '/public/app/scripts'))
.get('*', function(req, res) {
res.send('Hello, you have reached the API.');
})
.use(app.router)
.listen(port);
console.log('Listening on port ' + port + '...');
and I'm getting an error making a POST
Listening on port 1337...
{ users:
[ { title: 1,
firstName: 'Foo',
lastName: 'Bar',
role: 2,
email: 'foo@bar.com',
languageCode: 'en',
_id: 1 } ] }
Trace: [TypeError: Cannot call method 'map' of undefined]
at sendError (/Users/aldo/Satio/Desarrollo/node/fortune-admin/node_modules/fortune/lib/route.js:43:26)
at createResources.then.then.body (/Users/aldo/Satio/Desarrollo/node/fortune-admin/node_modules/fortune/lib/route.js:180:7)
at invokeCallback (/Users/aldo/Satio/Desarrollo/node/fortune-admin/node_modules/fortune/node_modules/rsvp/dist/commonjs/rsvp/promise.js:228:21)
Thanks.
POSTs with the Content-Type application/vnd.api+json
fail because body-parser only accepts application/json
. To fix this just add another body-parser:
router.use(bodyParser.json({ type: 'application/*+json' }));
router.use(bodyParser.json());
Not sure if I am doing something wrong, but I can't seem to enable CORS.
My fortune API looks like this (CoffeeScript/Node.JS):
argv = require("minimist")(process.argv.slice(2))
API = require("fortune")
if argv._.length == 0
console.log "Usage: node API.js <port>"
else
port = argv['_'][0]
app = API(db: "user-event-log", cors:true).resource("event",
time: Date
subject_id: String
user_id: String
type: String
).listen(port)
exports.API = API
My dependencies from package.json
are:
"dependencies": {
"coffee-script": "^1.8.0",
"fortune": "^0.2.4",
"i": "^0.3.2",
"minimist": "^1.1.0"
},
When I launch with node API.js 8080
and GET http://localhost:8090/events
, I do not see the Access-Control-Allow-Origin:*
header in the response:
Date: Fri, 30 Jan 2015 16:22:02 GMT
Content-Type: application/vnd.api+json; charset=utf-8
Content-Length: 378
ETag: W/"17a-679725808"
Am I doing something wrong or is this a bug?
Currently, a join table is created for a bi-directional many-to-one relationship, which is not necessary or compatible with most ORMs.
Also, a one-to-one relationship maintains a foreign key on both objects, which may not be necessary on most ORMs.
Consider the following application:
var fortune = require('fortune');
var app = fortune({
db: 'phonebook'
});
app.resource('entry',{
name: String,
telephone: String
})
.noIndex()
.listen(process.env.PORT);
The /entries
endpoint is working. According the docs, it shouldn't.
Tried .noIndex('entry')
, still the same.
Is this on the roadmap, or against your philosophy?
something like
app.resource('person', {
email: {type: String, validates: 'email'}
});
where one could register validation extensions to Fortune via fortune.addValidation('email', function(before, after) { .. })
or something similar?
Is there a reason why the ID style is not showing my one-to-many links? I realize the specs say the links MAY be shown, but how else does one get those relations; exposing them manually in the after transform?
Me again for a silly question.
I am trying to build a maze using hypermedia API.
That's my resources
app.resource('maze',{
name: String,
cells: ['cell'],
start: {ref: 'cell'}
});
app.resource('cell',{
name: String,
north: {ref:'cell'},
east: {ref:'cell'},
south: {ref:'cell'},
west: {ref:'cell'},
maze: {ref: 'maze'},
});
When I do a patch with (replace) on one cell
to tell which other cell
is at north it works great.
I got as expected
{
"id": "Ol4MkfL75QFcweUR",
"name": "Spoon Storage",
"links": {
"north": "KcicJj811BQuF0dF",
"maze": "1gtV4qx4qdiKvVE3"
}
},
But the one that was north, and where nothing should have happened is getting updated too..
{
"id": "KcicJj811BQuF0dF",
"name": "Banquet Hall",
"links": {
"north": "Ol4MkfL75QFcweUR",
"east": "Ol4MkfL75QFcweUR",
"south": "Ol4MkfL75QFcweUR",
"west": "Ol4MkfL75QFcweUR",
"maze": "1gtV4qx4qdiKvVE3"
}
},
How could I say that north, east,south,west are links to a cell object, but to different cell objects ?
Thanks :)
Is this possible?
It would be fantastic if fortune allowed for a stored procedure to be accessed in addition to direct table access.
For instance I have databases that I can run a function like:
SELECT column1, column2 FROM my_db_side_function('value1', 'value2);
The function could return a dataset like a table, or a return value. I am not sure how this would be implemented, but if fortune could handle this it would be my ideal situation.
Is it possible to specify an ID when POSTing a new entry to the DB? The potential usecase is loading sample data for testing to the DB via the web services themselves.
I'm using Ember with @daliwali's ember-data JSON-API adapter. I have a very simple resource with 3 string fields, connecting to Mongo instance on mongohq.com. When I create a record from Ember, the request body contains a "displayName" field, and the record shows up in the Mongo collection, but it's missing the "displayName" field. Is there any reason this should be excluded?
I am trying out Fortune.js for the first time and I wrote a very simple app that doesn't seem to work.
The server:
var fortune = require('fortune');
var options = {
db: 'demo_app'
};
server = fortune(options).
resource("project", {
name: String
});
The client (ember):
App.Project = DS.Model.extend({
name: DS.attr("string")
});
var project = this.store.createRecord("project", {
name: "This is a test project!"
});
project.save();
The request payload:
{"project":{"name":"This is a test project!"}}
The server exception:
[TypeError: Cannot call method 'forEach' of undefined]
at sendError (d:\repos\openquip\node_modules\fortune\lib\route.js:43:26)
at createResources (d:\repos\openquip\node_modules\fortune\lib\route.js:238:
What did I do wrong here?
Just a suggestion, I noticed that you defined the same layout for each target in the assemble task (https://github.com/daliwali/fortune/blob/gh-pages/Gruntfile.js#L74-L76).
you can specify a layout at the task-level as well:
assemble: {
options: {
assets: 'dist',
helpers: 'helpers/*.js',
layout: 'main.hbs'
layoutdir: 'templates/layouts',
partials: ['templates/partials/**/*.hbs'],
data: ['docs/**/*.json'],
marked: {
sanitize: false,
gfm: true,
breaks: true
}
},
home: {
src: ['templates/index.hbs'],
dest: 'index.html'
},
docs: {
src: ['templates/docs.hbs'],
dest: 'docs/index.html'
},
guide: {
src: ['templates/guide.hbs'],
dest: 'guide/index.html'
},
404: {
src: ['templates/404.hbs'],
dest: '404.html'
}
},
or even just layout: 'templates/layouts/main.hbs'
and get rid of layoutdir
if you only intend to have one layout.
A method to get the current list of valid routes would be useful for documentation purposes, especially when the API is to be exposed to a public audience.
This would also allow users to build documentation such as Swagger or RestDoc around the API.
I have a simple resource defined as follows:
...
.resource('event', {
time: Date,
subject_id:String,
user_id:String,
type: String
})
...
I can GET
http://localhost:8090/events
but filtering does not seem to be happening:
http://localhost:8090/events?type=typeA
http://localhost:8090/events?subject_id=2
http://localhost:8090/events?user_id=abc
These all return the full list of events, even though these attribute values only apply to a subset of the data.
How is filtering supposed to work with fortune? Or is it broken/not implemented? I notice JSON API spec says it is optional.
Options on a field in the schema should work the same in NoSQL and relational databases.
Would you accept a pull request that transitioned the stuff that's currently done in the Makefile
to use Gulp? Alternatively, I could write a node script that would execute the same commands as make, but in a cross platform manner.
Currently you can't actually build the project on Windows easily due to command and path separator differences. In order to get it working, I ended up installing a bunch of GnuWin32 utilities and modifying the Makefile
I was experiencing some issues with the MongoDB adapter, where if I put in the wrong credentials, Mongoose would give an error, but it wasn't handled anywhere in Fortune. It seemed that adding connection errors to the awaitConnection
promise was the logical thing to do, but in doing so I found that rejecting the awaitConnection
promise doesn't have any effect on Fortune, and in fact doesn't even show up in the console.
I think this may be something to do with the RSVP module silencing thrown errors, but in any event it is a big problem to have no connection error handling in Fortune at all.
As an illustration of this problem, you can replace the awaitConnection
method in the stub adapter with this one:
Adapter.prototype.awaitConnection = function() { return new RSVP.Promise(function (resolve, reject) { reject(new Error("some error")); }); };
And it never causes a hiccup.
The precise MIME types like application/vnd.api+json are really nice, but not all tools are too advanced. For example I have tried 3 Chrome extensions to visualize JSON responses and none of those were able to recognize it. Therefore I suggest an option to set the response MIME type.
Hi,
I am trying to use the Adapter.find()
function to retrieve a particular object in my database.
in my code I do
var result = app.adapter.find('cell',"ZnqcWstX5rx9rKMT");
console.log("RESULT",result);
but I got
{ _id: 4,
_label: undefined,
_subscribers: [],
_state: 0,
_detail: [TypeError: Cannot call method 'findOne' of undefined] }
and when I do a console.log(app.adapter)
before it seems defined.
Any idea how to solve this or what I am doing wrong?
Thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.