-
Notifications
You must be signed in to change notification settings - Fork 17
Update typings. Add typescript example. Cleanup package.json #41
base: master
Are you sure you want to change the base?
Conversation
@@ -0,0 +1,11 @@ | |||
# Tells the .editorconfg plugin to stop searching once it finds this file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should help keep things more standardised across folks machines.
.travis.yml
Outdated
- "4.4.3" | ||
- "6" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be testing against recent versions of Node.js. I kept 4.4.3 since I believe we have some requirements around supporting that explicit version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good spot! Let's remove 0.10 and 4 - it's gone for long time.
services: | ||
- docker | ||
before_install: | ||
- sudo apt-get update | ||
- sudo apt-get install --assume-yes apache2-utils | ||
- npm install -g [email protected] | ||
- npm install -g grunt-cli |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this since it's now in "devDependencies"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👎 it is for the CI process to run the script and test the project to allow the PR is required the grunt-cli
/** | ||
* Options that can be passed to sync.invoke | ||
*/ | ||
interface InvokeOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this so we can add better typings to the sync.invoke
func
/** | ||
* Valid actions (the "fn" param) that can be passed to sync.invoke | ||
*/ | ||
type InvokeAction = 'sync'|'syncRecords'|'listCollisions'|'removeCollision' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using this will allow TS to flag if someone has a typo or wrong action in their sync.invoke
options
/** | ||
* Interfaces that describe how sync responses should be structured | ||
*/ | ||
namespace HandlerResults { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By having these defined and used by the callbacks for handlers we can have TS notify a developer that they're returning the correct/incorrect data structure.
For example:
sync.handleList('items', (dataset, query, meta, done) => {
done(null, [1,2,3]) // this will not compile with the new changes
done(null, { 431321: { /* data goes here */ } }) // this will compile since it's a hash as required
})
"description": "FeedHenry Data Synchronization Server", | ||
"main": "index.js", | ||
"main": "fh-sync.js", | ||
"files": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reduces installation size by removing examples, Gruntfile, etc. and only including essentials
package.json
Outdated
"grunt-cli": "^1.2.0", | ||
"grunt-fh-build": "^0.5.0", | ||
"grunt-mocha-test": "^0.13.2", | ||
"grunt": "~0.4.5", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~
is safer than ^
in most cases so I locked these down a little
fh-sync.d.ts
Outdated
* Can be used by other modules to create pre-built sync compliant handlers. | ||
*/ | ||
namespace HandlerFunctions { | ||
type Create = (dataset: string, data: Object, metaData: Object, done: StandardCb<HandlerResults.Create>) => void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This the format express typings use for middleware. It's useful since it allows creation of other libraries that can implement these types correctly, e.g sync adapters for specific services
import * from sync as 'fh-sync'
import * from http as 'http-lib'
const list: sync.HandlerFunctions.List = (dataset, query, meta, done) => {
http.get(`http://myservice.acme.com/${dataset}`)
.then(res => done(null, res))
.catch(done)
}
export = {
list
}
Then use like so
import * from sync as 'fh-sync'
import * from acme as 'acme-sync-wrapper'
sync.handleList('items', acme.list)
Up for debate if this is useful or not, but it cleans the file up a little too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can dig it. Being able to reference the types of inner things has always been a pain point, especially when it's the type of an argument. (I think there was actually an active issue in Typescript's repo about how to reference the type of an argument to a function.)
/** | ||
* Connect sync server to mongo and redis. Returns the MongoDB and Redis clients being used internally. | ||
* | ||
* @param mongoDBConnectionUrl - Unique id of the dataset (usually collection, table in your database) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function comments are now uniform and display a little more consistently. Should we add more detail in comments?
"valid-url": "1.0.9" | ||
}, | ||
"types": "./types/fh-sync.d.ts", | ||
"types": "fh-sync.d.ts", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this due to trouble when making my example. I can move back and try again if we'd prefer to keep it in a subfolder.
.travis.yml
Outdated
- "4.4.3" | ||
- "6" | ||
- "8" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lts/* will be better here. It my suggest that we support 8 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wtrocki not sure I follow, do you mean we can put "*" instead of "8"?
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "tsc && node server.js" | ||
}, | ||
"author": "Evan Shortiss <[email protected]> (http://evanshortiss.com/)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not against that, but having personalized author in organization code seems to be antipatern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wtrocki that's a mistake. npm init
filled this in with my default and I forgot to remove 😊
// Project: https://github.com/feedhenry/fh-sync | ||
// Maintainer [email protected] | ||
|
||
declare module SyncCloud { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to check if all dependent projects compile after this change.
We may also bump minor version.
package.json
Outdated
@@ -1,8 +1,14 @@ | |||
{ | |||
"name": "fh-sync", | |||
"version": "1.0.13", | |||
"version": "1.0.14", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeScript community recommends to make minor patches for all non trivial changes in types.
Many people may have patch version classifiers for types and suddenly their project will stop compiling on master. It happened couple times for us. Best to do minor bump.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Good call, will do!
Build is failing on node8. Let's remove it. I will need time to get that tested with RainCatcher and I think we can merge it then. |
- "4.4.3" | ||
- "6" | ||
- "8" | ||
services: | ||
- docker | ||
before_install: | ||
- sudo apt-get update | ||
- sudo apt-get install --assume-yes apache2-utils | ||
- npm install -g [email protected] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we still be using npm 2.x, even when running on node 6/8?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a fair question. Perhaps @wtrocki can confirm if there's a requirement from some users?
import * as cors from 'cors' | ||
import * as sync from '../../fh-sync' | ||
|
||
const router = express.Router() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No semis? Daring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying it out here too 😂
"removeComments": true, | ||
"preserveConstEnums": true, | ||
"sourceMap": true, | ||
"target": "es5" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"strict": true
by any chance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will take a look at that 👍
fh-sync.d.ts
Outdated
* Can be used by other modules to create pre-built sync compliant handlers. | ||
*/ | ||
namespace HandlerFunctions { | ||
type Create = (dataset: string, data: Object, metaData: Object, done: StandardCb<HandlerResults.Create>) => void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can dig it. Being able to reference the types of inner things has always been a pain point, especially when it's the type of an argument. (I think there was actually an active issue in Typescript's repo about how to reference the type of an argument to a function.)
fh-sync.d.ts
Outdated
* Example: {strategy: 'exp', max: 60*1000}, | ||
*/ | ||
interface PendingWorkerBackoff { | ||
strategy: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the strategies for this also be a literal string type, like what we have for InvokeAction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I'd need to read the source code, perhaps @david-martin can share some insight?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MikeyBurkman do you have an example of what you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example type InvokeAction = 'sync'|'syncRecords'|'listCollisions'|'removeCollision'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @wtrocki
Looks like either 'fib' or 'exp' are possible
Lines 8 to 25 in 7ca3e60
var bo; | |
if (backOffOpts.strategy && backOffOpts.strategy.toLowerCase() === 'exp') { | |
bo = new backoff.ExponentialStrategy({initialDelay: backOffOpts.min, maxDelay: backOffOpts.max}); | |
} else if (backOffOpts.strategy && backOffOpts.strategy.toLowerCase() === 'fib') { | |
bo = new backoff.FibonacciStrategy({initialDelay: backOffOpts.min, maxDelay: backOffOpts.max}); | |
} else { | |
//if no valid value is given, just return the default minimum delay. Can be used to turn off backoff. | |
console.log('[info] no valid sync strategy found in the backoff options. Turning off backoff', backOffOpts); | |
bo = { | |
next: function() { | |
return backOffOpts.min; | |
}, | |
reset: function() { | |
} | |
}; | |
} | |
return bo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it looks like there's technically three values: strategy: 'fib'|'exp'|undefined;
* @param redisUrl - Redis connection URL | ||
* @param callback - Callback that will be invoked once connections are setup | ||
*/ | ||
function connect(mongoDBConnectionUrl: string, mongoDBConnectionOption: any, redisUrl: string, callback: (err: any, mongoDbClient?: any, redisClient?: any) => void): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be awesome if we could get typings for mongoDbClient and redisClient :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about that too, but passed on it. I suppose there's nothing to stop us adding @types/mongodb
and @types/redis
and referencing those?
fh-sync.d.ts
Outdated
* @param options - Specific options to apply to this dataset | ||
* @param callback - Callback that will be invoked once initialisation is complete | ||
*/ | ||
function init(datasetId: string, options: SyncInitOptions, callback: StandardCb<void>): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be NoRespCb
I think
fh-sync.d.ts
Outdated
* @param options - Options to pass to the invocation | ||
* @param callback - Function that will receive the invocation results | ||
*/ | ||
function invoke(datasetId: string, options: InvokeOptions, callback: (err: any, result: any) => void): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should be StandardCb<any>
for consistency, though it doesn't matter too much here. Mostly just narrows the type of err a little bit.
@evanshortiss Reviewed locally. Great contribution. |
…pdate invoke and init callback types. add backoff strategy types. add strict mode to example
@wtrocki updated to remove Node.js 0.10 and 8 (temporarily) from CI 👍 |
@evanshortiss Thanks for contribution.
Added 2 commits to fix minor issues. If you are ok with all I think we can merge it and publish your changes to npm. |
"@types/body-parser": "~1.16.8", | ||
"@types/cors": "~2.8.3", | ||
"@types/express": "~4.0.39", | ||
"ts-node": "^3.3.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wtrocki You don't want to make this change to ts-node. Or at least you definitely don't want to remove typescript as a dependency. Right now, ts-node will use whatever version of typescript is installed globally, and there's no guarantee that it's a compatible version, if it's installed at all. (Also, I don't think it's common to use ts-node on prod apps, so this wouldn't be ideal as a starting point.)
As an update, I found this regarding ts-node in production. Using ts-node in prod isn't too bad, but it's a bit slower to restart the app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Reason why this worked for me is that I had typescript installed from previous npm install. I forgot that ts-node requires typescript to be available globally.
I made that change as original change failed to start: tsc compiler is not available
.
Before making any change - @evanshortiss What aproach do you prefer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have typescript installed locally so npm start
failed for me. I installed it locally via package.json (like what Evan had) and npm start
worked fine, so pretty sure that's all that's necessary.
What version do you have installed globally? I think the missing types issue that my other comment was about might have to do with that, as I was able to revert your changes and it compiled fine. (And intellisense was correct.)
// All sync requests are performed using a HTTP POST | ||
router.post('/:datasetId', (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
// Invoke action in sync for specific dataset | ||
sync.invoke(req.params.datasetId, req.body, function(err: any, result: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wtrocki Any reason you changed the types of the callback parameters to any
? The types seem to get inferred correctly, and in fact, any
is a wider type than err
is, which is string|Error|null
in the typings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not compile for me - were complaining about missing types :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this might be a noImplicitAny
issue? In any case, does it mean we need better typings for result
here? It should always be Object
right?
@wtrocki looks good, the only thing is I might remove |
fh-sync.d.ts
Outdated
* Can be used by other modules to create pre-built sync compliant handlers. | ||
*/ | ||
namespace HandlerFunctions { | ||
type Create = (dataset: string, data: Object, metaData: any, done: StandardCb<HandlerResults.Create>) => void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticed a slight inconsistency with these handler functions. The first argument for half of them is dataset
and the other half have datasetId
but I think they're all the same thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. They should be consistent.
type ListCollisions = (datasetId: string, metaData: any, callback: StandardCb<{ [hash: string]: Object }>) => void | ||
type RemoveCollision = (datasetId: string, collision_hash: string, metaData: any, callback: StandardCb<any>) => void | ||
type Interceptor = (datasetId: string, interceptorParams: SyncInterceptParams, callback: NoRespCb) => void | ||
type Hash = (data: any) => string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two types of hash function callbacks. The record one gets (datasetId: string, record: any)
and the global hash one gets Array<any>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oooh, well spotted! Will fix that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MikeyBurkman I think the (datasetId: string, record: any)
is no longer valid. I have some TS code now like this that is working with these types:
const hashHandler: sync.HandlerFunctions.Hash = (t: Item) => {
return `${t.name}${t.lastUpdated}`
}
Our documentation states the signature is:
$fh.sync.setRecordHashFn(dataset_id, function generateHash(dataset_id,
record){});
Based on this code the implementation I have is correct, so the docs might need updating.
Take a look at the code I'll push shortly
Triggering build again. It's failing due to npm issues. |
See notes in the PR for more information. This is aimed at making some improvements to TS support/docs/typings.