Giter Site home page Giter Site logo

cozy / cozy-client-js Goto Github PK

View Code? Open in Web Editor NEW
11.0 18.0 12.0 8.87 MB

Javascript library to write Cozy applications

Home Page: https://docs.cozy.io/en/cozy-client-js/README/

License: MIT License

JavaScript 99.62% HTML 0.16% Shell 0.23%
cozy javascript-library cozy-v3

cozy-client-js's Introduction

Travis build status shield NPM release version shield NPM Licence shield

⚠️ This is the documentation for the old version of cozy-client. Go to the new version ✅.

Cozy Javascript Client

What's Cozy?

Cozy Logo

Cozy is a platform that brings all your web services in the same private space. With it, your webapps and your devices can share data easily, providing you with a new experience. You can install Cozy on your own hardware where no one's tracking you.

What's cozy-client-js?

cozy-client-js is a javascript library made by Cozy. It enables applications (client-side apps, konnectors, OAuth apps, etc.) to make requests to the cozy stack.

If you are getting started on cozy application development, you should follow this tutorial. The reference documentation is the place to see what you can do with this lib, and how to do it!

Contribute

If you want to work on cozy-client-js itself and submit code modifications, feel free to open pull-requests! See the contributing guide for more information about this repository structure, testing, linting and how to properly open pull-requests.

Community

Get in touch

You can reach the Cozy Community by:

Licence

cozy-client-js is developed by Cozy Cloud and distributed under the MIT.

cozy-client-js's People

Contributors

aenario avatar clochix avatar cpatchane avatar crash-- avatar dependabot[bot] avatar doubleface avatar enguerran avatar goldoraf avatar gregorylegarec avatar jinroh avatar kosssi avatar lespacedunmatin avatar m4dz avatar narkfr avatar nono avatar paultranvan avatar pierrevdk avatar ptbrowne avatar sblaisot avatar sebn avatar taratatach avatar trollepierre avatar y-lohse avatar

Stargazers

 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  avatar

cozy-client-js's Issues

[files] some methods “by path” are missing

Some methods allow to manipulate files either by path or id (or example, updateAttributesById and updateAttributesByPath), others only by id (updateById). It would be more coherent to be able to use both methods everywhere it's possible.

No simple way to get all the documents for a given doctype

After reviewing the doc and the code, the only way I found to get all the document for a given doctype is :

cozy.defineIndex("doctype", ["_id"])
.then(index => cozy.query(index, {
    selector: {
        "_id": {
          "$gt": 0
          }
        }
    }
));

since all docs have an id.
Please tell me there is a better way...

Default content-type depending on extension

In application code (ACH), I see :

  switch (fileJSON.extension) {
    case '.jpg':
    case '.jpeg':
    case '.gif':
    case '.png':
    case '.tiff':
      contentType = `image/${fileJSON.extension.substring(1)}`
      break
    case '.pdf':
      contentType = `application/pdf`
      break
    default:
      contentType = ''
      break
  }
...
client.files.create(

I think it should be the responsibility of client.files.create to do that.

Error on invalid query should be more explicit

Summary

Calling cozy.client.data.query with invalid parameters should return an explicit error message

STR

cozy.client.data.query(myIndex, {}).then().catch((err) => { console.error(err);})

Expected result

The full error returned by the server: {"error":"missing_required_key","ok":false,"reason":"Missing required key: selector","status":"400"}

Actual result

Only an Error object, without name nor message.

Version of CozyClientJs

0.1.7

Client-level default `fetch` options.

In cozy-desktop, to support proxies, we need to setup an http.agent for every request.

It will be cool to have a quick way to do it at cozy-client level, like
cozy.baseFetchOptions = {agent: myAgent}

Check if we need babel-polyfill

Following cozy/cozy-bar#113 where we had a problem importing twice babel-polyfill in the context of an app (1st via cozy-client, 2nd via cozy-bar), we removed babel-polyfill from the cozy-bar. Do we need to do the same in cozy-client ? Would it be better to import polyfills via babel-preset-env (in our case via babel-preset-cozy-app) ?

I post this issue here so I do not forget, this is not an immediate bug. ping @CPatchane

Babel-polyfill?

Babel-polyfill is used to give polyfills for browsers that have not yet implemented the support of ES2015 features. It's pretty heavy and I don't think we aim support for browsers that have bad support of ES2015. So, it's probably a good idea to not include it in our build. Someone who wants to support these old browsers can include herself the polyfills.

Upgrading pouchdb

This package currently uses pouchdb v6, and we should upgrade to pouch v7. v6 is not maintained and has some vulnerabilities.

The main change is that the websql driver is not packaged by default anymore. We shouldn't need it — the only known use case for it is a page running in an iframe on safari mobile, so an intent for example. But no app does this at the moment.
That said, the websql driver can be added as a separate dependency, and that would probably be the safest way to upgrade.

When we do this, we should also switch to the browser-only version of pouch — it's significantly lighter.

Evolving intents

Lately, we have discovered new use cases for intents, and in the past we've had to add things to the Intent API that weren't part of the initial plan. We should start thinking about the next version of the intent specs.

Before we start, two strongly recomended reads:

A) Things that are not in the spec but are in the API

  1. A hook for the client to know when the iframe is loaded — See #189, used to wait until the service is loaded to display it.
  2. A hook for the client to remove the iframe manually — See #189, used to animate the iframe closing.
  3. The service tells the client to change the size of the service's frame — See #175 and #194, used when a service wants to be displayed at a specific size and the client couldn't predict it. Can happen after the service is initialized or when the user interacts with the service (eg. expanding Claudy).

B) Things that we need but are not in the spec

1. Linking to a specific part of an app

The most common example for this is wanting to link to a certain document inside cozy-drive. Except cozy-drive, no one has any clue what the exact URL is — in fact, even the URL for the drive app is mostly unknown for apps.

The solution here is to use intents. The client will express that it wants a redirection (maybe through a dedicated method like cozy.intents.redirect(), or maybe by adding a disposition parameter).

The service can indicate in it's manifest that it handles redirections, as well as what parameters the new URL accepts (see this comment).

2. Complex communication

The current model specifies that the client sends some data at the start of the intent, and the service replies with some data at the end, and nothing in between. It would be good to have the ability for the service to send intermediate messages as well.

  • What are some concrete use cases for this?
  • Should the reverse be possible as well, ie. the client can send data to the service after the creation?

3. Silent Communication

Kinda vague at this point, but a client might need access to some data from another app, but without showing the service's UI. This could be because the client itself will show that data, aggregated with dat from other sources. Or it could be because there's just no need for a UI.

This has some implications in terms of security that need to be considered.

???

You tell me. I'll try to keep this post updated.

File is not file, Blob is not blob, that is the question

I faced an issue when uploading an image file.

On my desktop and my mobile chrome browser, the line

const isFile = (typeof File !== 'undefined' && data instanceof File)
return true.
But on Cordova, it returns false.

So the file is sent with a generic application/octet-stream instead of the specific data.type given by the client.

See this screenshot

files.create with string : bad contentType,

In MyAccount, I've got a file as a base64 string (extracted froma XML field from an API), and I wish to create a File with it, using nodeJS.
I use the "contentType" option, with value application/pdf, but, the created file isn't readable, my pdf reader complaining that the contentType is text/plain : https://github.com/jacquarg/cozy-konnector-libs/blob/83b44bc935910f82707c7cb3bed1360f993ebaa4/models/file.js#L39

I can give you easily some code to reproduce if you want.

Hacking with npm

It looks like it's not currently possible to build the lib with npm 2:

$ npm -v
2.15.4
$ npm run build

> [email protected] build /home/nono/cc/client-js
> NODE_ENV=production webpack

Hash: 75d19d4238bfe0a779b7
Version: webpack 1.13.3
Time: 528ms
             Asset     Size  Chunks             Chunk Names
    cozy-client.js  14.2 kB       0  [emitted]  main
cozy-client.js.map  16.3 kB       0  [emitted]  main
   [0] multi main 52 bytes {0} [built] [2 errors]
    + 2 hidden modules

ERROR in multi main
Module not found: Error: Cannot resolve module 'regenerator-runtime/runtime' in /home/nono/cc/client-js
 @ multi main

ERROR in ./src/index.js
Module build failed: Error: Failed to load plugin react: Cannot find module 'eslint-plugin-react'
Referenced from: /home/nono/cc/client-js/node_modules/standard/eslintrc.json
    at Function.Module._resolveFilename (module.js:326:15)
    at Function.Module._load (module.js:277:25)
    at Module.require (module.js:354:17)
    at require (internal/module.js:12:17)
    at Object.load (/home/nono/cc/client-js/node_modules/eslint/lib/config/plugins.js:129:26)
    at Array.forEach (native)
    at Object.loadAll (/home/nono/cc/client-js/node_modules/eslint/lib/config/plugins.js:151:21)
    at load (/home/nono/cc/client-js/node_modules/eslint/lib/config/config-file.js:504:21)
    at /home/nono/cc/client-js/node_modules/eslint/lib/config/config-file.js:391:36
    at Array.reduceRight (native)
    at applyExtends (/home/nono/cc/client-js/node_modules/eslint/lib/config/config-file.js:362:28)
    at Object.load (/home/nono/cc/client-js/node_modules/eslint/lib/config/config-file.js:529:22)
    at loadConfig (/home/nono/cc/client-js/node_modules/eslint/lib/config.js:63:33)
    at new Config (/home/nono/cc/client-js/node_modules/eslint/lib/config.js:226:38)
    at CLIEngine.executeOnText (/home/nono/cc/client-js/node_modules/eslint/lib/cli-engine.js:743:28)
    at Linter.lintText (/home/nono/cc/client-js/node_modules/standard/node_modules/standard-engine/index.js:65:59)
    at Object.standardLoader (/home/nono/cc/client-js/node_modules/standard-loader/index.js:20:12)
 @ multi main

Installing for node does not work directly

Some dependencies are missing if you want to develop a CLI app with cozy-client-js

$ yarn add cozy-client-js
$ node
> require('cozy-client-js')
module.js:491
    throw err;
    ^

Error: Cannot find module 'isomorphic-fetch'
    at Function.Module._resolveFilename (module.js:489:15)
    at Function.Module._load (module.js:439:25)
    at Module.require (module.js:517:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/pbrowne/code/cozy/cozy-match-operations-bills/node_modules/cozy-client-js/dist/cozy-client.node.js:55:19)
    at __webpack_require__ (/Users/pbrowne/code/cozy/cozy-match-operations-bills/node_modules/cozy-client-js/dist/cozy-client.node.js:20:30)
    at Object.<anonymous> (/Users/pbrowne/code/cozy/cozy-match-operations-bills/node_modules/cozy-client-js/dist/cozy-client.node.js:47:2)
    at __webpack_require__ (/Users/pbrowne/code/cozy/cozy-match-operations-bills/node_modules/cozy-client-js/dist/cozy-client.node.js:20:30)
    at /Users/pbrowne/code/cozy/cozy-match-operations-bills/node_modules/cozy-client-js/dist/cozy-client.node.js:40:18
    at Object.<anonymous> (/Users/pbrowne/code/cozy/cozy-match-operations-bills/node_modules/cozy-client-js/dist/cozy-client.node.js:43:10)

Here's how to add them :

$ yarn add isomorphic-fetch core-js regenerator-runtime btoa

Utilisation des intents sur application Cordova

J'ouvre cette issue pour démarrer une discussion sur comment va-t-on faire pour faire marcher les intents sur mobile. J'ai essayé de proposer quelques pistes et aimerait avoir vos retours là-dessus.

Cas d'usages d'intent

  • Ouverture d'un fichier dans drive (pour le moment implémentée en redirigeant l'utilisateur sur une URL spécifique de Drive https://mycozy-drive/#files/{factureID})
  • Récupération de l'URL de téléchargement d'un fichier (pour le moment fonctionnalité non implémentée car EDF n'est pas une application mobile native)
  • Recherche

Intent via inAppBrowser au lieu d'une iframe

L'utilisation de inAppBrowser pose le problème de la communication entre l'application et le service. Sur mobile nous ne pouvons pas utiliser les iframes à cause des politiques de sécurité de Cordova.
En effet, pour pouvoir ouvrir une iframe il faut inscrire son domain dans la whitelist et
étant donné que nous ne connaissons pas le domaine en avance, nous ne pouvons pas le faire.

Nous pouvons cependant utiliser inAppBrowser qui utilise une véritable fenêtre pour ouvrir
la page demandée.

Via postMessage, executeScript

const w = window.open('[Adresse de l'intent]', '_blank')

La communication entre les deux fenêtres semble difficile (surtout de l'inappbrowser vers l'app).

J'ai essayé (comme préconisé sur https://www.telerik.com/blogs/cross-window-communication-with-cordova's-inappbrowser) :

w.executeScript({ code: 'localStorage.setItem("hello", "world")' })
w.executeScript({ code: 'localStorage.getItem("hello")' }, function (values) { console.log(values) })

La valeur dans localStorage est bien inscrite mais on ne peut pas la récupérer ☹️. Cela semble un
problème qu'on plusieurs personnes : https://www.google.fr/search?q=inappbrowser+callback+not+firing&oq=inappbrowser+callback+not+firing&aqs=chrome..69i57j69i60l3.4359j0j4&sourceid=chrome&ie=UTF-8. Avec les politiques
de CSP strictes que l'on a, je doute que cela ne marche.

✅ On peut cependant écouter sur l'évenement "exit" de la fenêtre.

w.addEventListener('exit', () => { checkIfTheUserHasCompletedTheIntent() })

Stocker valeur de retour dans l'intent

Stocker une valeur de retour dans l'intent (via un HTTP POST par leur service et un HTTP GET par l'application) permettrait sa lecture par l'application à la fermeture de l'inAppBrowser.

⚠️ Nécessite une route PUT sur l'intent pour le modifier (seulement la valeur de retour doit être modifiable, juste une fois).

Websocket pour communication permanente

Idée pour communiquer des valeurs : passer par une websocket. Le service et l'application
recevrait de la stack un id + token ou ils pourraient communiquer. Inconvénients:
complexité chez la stack, latence, 2 connexions en plus par intent. Avantage : assez générique et
niveau de confiance plutôt élevé sur le fait que ca marche.

Abstraction du channel de communication app/service

Ces 2 possibilités d'ouverture/communication entre l'application et le service (via une iframe/postMessage, inAppBrowser/HTTP GET intents/id/returnValue) nécessiterait une abstraction niveau cozy-intent pour que l'utilisateur n'ait pas à se préoccuper de ces détails bas-niveaux, idéalement juste utiliser une option { mobile: true } ?

Possibles améliorations

Login automatique sur la stack

L'inAppBrowser ne partage pas ses cookies avec la webview Cordova, à l'ouverture de l'intent, l'utilisateur devrait donc se logguer. Pour améliorer l'expérience utilisateur, il pourrait être intéressant de le logguer directement dans l'inappbrowser, est ce que ce serait possible de demander à la stack un token d'authentification à n'utiliser qu'une fois et qui permettrait à l'utilisateur de ne pas avoir à retaper son mot de passe ?

w = window.open('https://mydomain.cozy.cloud/loginViaToken={token}&redirect={intentURL}', '_blank')

Nettoyage des intents

Le nettoyage des intents n'a pas été implémenté, l'idée étant de les supprimer juste après leur lecture par le service. Si l'on souhaitere stocker une valeur de retour dans l'intent pour lecture par l'application mobile, il faudrait le supprimer après lecture de la valeur de retour. Cela pourrait être configuré au lancement de l'intent avec une option spécifique { deleteAfter: 'readByService' }, { deleteAfter: 'readByApp' }. Autre possibilité : l'option {mobile:true} évoquée plus haut pourrait abstraire ce détail.

Check URL sheme of CozyURL

Related to #150
Forgetting URL sheme when calling the init method make requests fail, due to CSP:

// Wrong
cozy.client.init({ cozyURL: app.dataset.cozyStack, token: app.dataset.token})
// Right
cozy.client.init({ cozyURL: '//' + app.dataset.cozyStack, token: app.dataset.token})

It would be nice if the library checked the URL to prevent such sort of mistake :-S

No way to get the list of doctypes

V2 allows that. I have heard this is more complicated for the V3 at the moment an it is needed by the databrowser. It even needs to get the number of documents for each doctype.

I have a workaround for V2, but obviously, not compatible with v3.
Can you do something about that?

Pouchdb as a dependency

We are using pouch in the offline module, but it's declared as a dev dep, so it's not always installed. I believe it should be declared as a regular dependency.

I'd be happy to supply a PR but I'm not sure how we should declare pouchdb-find and pouchdb-adapter-memory, as normal deps or as peer deps?

Ping @kosssi and @enguerran

Not possible to do multiple delete

The databrowser application needs to be able to delete all the documents associated to a given doctype (to be compliant with the previous version).

I do not see (in the docs and in the code) any possibility to do that, even multiple deletion actually.
Is it forcasted to implement this or should I implement a chain of promises which deletes all the items one by one (which is not very satisfying) ?

Am I missing something ?

cozy.client.init() for client-side apps

Hi,
I'm developing a client-side app for cozy V3 using cozy-client-js.

In the doc, cozy.client.init() use OAuth 2 but i have read in the Auth doc's, that for client-side apps cozy don't use OAuth 2 so I'm a bit lost.

In https://github.com/cozy/cozy-stack/blob/master/docs/client-app-dev.md cozy.init() only use the cozyURL and the token but how I can do it with cozy.client.init().

I don't know if I'm clear, but if someone can help me. Thank you in advance for your answers.

👋 Say goodbye to intents

Nous allons être amenés dans nos prochain sprints à implémenter quelques évolutions au sein des intents. Comme le code est déjà dupliqué entre cozy-bar et cozy-client et que nous nous posons la question de l'extraire de cozy-client de longue date, nous pensons que le moment est venu.

L'idée serait je pense de proposer les intents au sein d'une lib indépendante, que nous appellerions soit cozy-intents ou soit cozy-interapp, cette dernière ayant ma préférence puisqu'il est probable que nous ajoutions d'autres fonctionnalités autres que les intents et liées à l'inter-app.

Dernier point, et j'aimerais avoir votre avis, nous pouvons créer un nouveau repo et ou bien intégrer la lib à cozy-drive et son mono-repo, nous avons par contre pour cela besoin d'être capables de la tester et la publier.

Commentaires et remarques bienvenus.

[feature] Allow to manage permissions

It may be useful to add some methods to deal with permissions API. For exemple, user may want to:

  • list current permissions of the application
    GET /permissions/self
  • get permissions on a document
    POST /permissions/exists
  • create tokens for reduced set of permissions
    POST /permissions
  • update permission set
    PATCH /permissions/:id

[feat] Query all documents

It can be useful (for example for ACH) to be able to query all documents.

What do you think of a queryAll function on cozyClient.data ?

I had to code one for ACH so here is an implementation example.

The drawback would be that since it will be available, it will be used, sometimes in lieu of a proper pagination.

const queryAll = function (cozyClient, mangoIndex, options) {
  return new Promise((resolve, reject) => {
    const documents = []
    var skip = options.skip || 0
    var fetch = function () {
      return cozyClient.data.query(
          mangoIndex, Object.assign({}, options, {
            wholeResponse: true,
            skip: skip
          }))
        .then(onSuccess)
         .catch(reject)
    }
    var onSuccess = function (response) {
      const docs = response.docs
      skip = skip + docs.length
      documents.push.apply(documents, docs)
      if (response.next) {
        fetch()
      } else {
        resolve(documents)
      }
    }
    fetch()
  })
}

The Plan

Nous sommes plusieurs à nous poser la question de l'avenir de notre bibliothèque de connexion à la stack gozy.
Quel est le plan ?

[EDIT 19-10-2017]]

Je reprends les informations données par @goldoraf :

objectif

Une bibliothèque d'accès à la stack composée de 3 étages :

  • étage 1 : gestion de token, API stack
  • étage 2 : persistence, normalisation
  • étage 3 : Higher-Order Component pour (p)react et autres

feuille de route

  • conserver cozy-client-js le temps de sortir une première release complète
  • renommer redux-cozy-client en cozy-client
  • identifier et isoler les 3 couches pour permettre des releases ou pas incluant l'étage voulu (et les étages sous-jacents)
  • sortir une release avec semver, changelog et CI (donc tests)

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.