From 960fe82b2fd649a1b653a4a047f45c24e9831b78 Mon Sep 17 00:00:00 2001 From: Travis CI User Date: Fri, 12 Jul 2024 02:02:01 +0000 Subject: [PATCH] publish: Add Ubuntu 24.04 cozy-stack packages generated from commit b2d4b2f747ce7c82f255e97a232f142b1a768c58 --- en/cozy-flags/CHANGELOG/index.html | 102 +- en/cozy-flags/package.json | 2 +- en/cozy-flags/src/flag.js | 15 +- en/cozy-home/manifest.webapp | 2 +- en/cozy-home/package.json | 13 +- .../src/assets/images/default-wallpaper.svg | 49 + .../src/components/AddServiceTile.jsx | 8 + .../src/components/AnimatedWrapper.jsx | 11 +- en/cozy-home/src/components/AppWrapper.jsx | 24 +- .../src/components/AppWrapper.spec.jsx | 11 +- .../src/components/BackgroundContainer.tsx | 48 +- .../Sections/GroupedSectionTile.tsx | 56 ++ .../Sections/GroupedSectionsView.tsx | 50 +- .../src/components/Sections/SectionsTypes.ts | 4 + en/cozy-home/src/containers/App.spec.jsx | 10 +- .../src/hooks/useCustomWallpaperContext.tsx | 39 - en/cozy-home/src/hooks/usePreferedTheme.ts | 33 - ...seCustomWallpaper.jsx => useWallpaper.jsx} | 4 +- .../src/hooks/useWallpaperContext.tsx | 38 + en/cozy-home/src/styles/app.styl | 35 +- .../src/styles/backgroundContainer.styl | 32 +- en/cozy-home/yarn.lock | 38 +- en/search/search_index.json | 2 +- en/sitemap.xml | 896 +++++++++--------- en/sitemap.xml.gz | Bin 3475 -> 3475 bytes 25 files changed, 763 insertions(+), 759 deletions(-) create mode 100644 en/cozy-home/src/assets/images/default-wallpaper.svg create mode 100644 en/cozy-home/src/components/Sections/GroupedSectionTile.tsx delete mode 100644 en/cozy-home/src/hooks/useCustomWallpaperContext.tsx delete mode 100644 en/cozy-home/src/hooks/usePreferedTheme.ts rename en/cozy-home/src/hooks/{useCustomWallpaper.jsx => useWallpaper.jsx} (96%) create mode 100644 en/cozy-home/src/hooks/useWallpaperContext.tsx diff --git a/en/cozy-flags/CHANGELOG/index.html b/en/cozy-flags/CHANGELOG/index.html index 6cfadbb9d..4fa68c06e 100644 --- a/en/cozy-flags/CHANGELOG/index.html +++ b/en/cozy-flags/CHANGELOG/index.html @@ -3218,42 +3218,6 @@ - - - @@ -3270,6 +3234,16 @@

Change Log

All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.

+

4.0.0 (2024-07-11)

+

Features

+ +

BREAKING CHANGES

+

3.2.2 (2024-01-05)

Bug Fixes

-

Features

+

Features

3.1.0 (2023-10-31)

-

Features

+

Features

@@ -3301,21 +3275,21 @@

Bug Fixesc27806f) -

Features

+

Features

-

BREAKING CHANGES

+

BREAKING CHANGES

2.12.0 (2023-03-21)

-

Features

+

Features

2.11.0 (2023-01-31)

-

Features

+

Features

@@ -3324,7 +3298,7 @@

2.10.2 (2022-10-03)2.10.1 (2022-08-01)

Note: Version bump only for package cozy-flags

2.10.0 (2022-07-05)

-

Features

+

Features

-

Features

+

Features

@@ -3369,7 +3343,7 @@

Bug Fixesea517de)

2.8.0 (2021-10-22)

-

Features

+

Features

@@ -3385,7 +3359,7 @@

Bug FixesFlags should install cozy-client (b1ca8e6)

2.7.0 (2021-04-09)

-

Features

+

Features

@@ -3395,7 +3369,7 @@

Bug FixesImport in FlagSwitcher (5ccc780)
  • Remove useless block for node (fb15094)
  • -

    Features

    +

    Features

    @@ -3414,14 +3388,14 @@

    Bug Fixes2.5.1 (2021-02-02)

    Note: Version bump only for package cozy-flags

    2.5.0 (2020-11-23)

    -

    Features

    +

    Features

    2.4.1 (2020-10-16)

    Note: Version bump only for package cozy-flags

    2.4.0 (2020-10-01)

    -

    Features

    +

    Features

    @@ -3439,7 +3413,7 @@

    Bug FixesMake sure the initializing promise is reset on logout (673029b)

    2.3.0 (2020-07-08)

    -

    Features

    +

    Features

    @@ -3467,7 +3441,7 @@

    Bug Fixes
  • Use useEffect to clean up event handlers on unmount (3cdf5be)
  • -

    Features

    +

    Features

    2.1.0 (2020-01-24)

    -

    Features

    +

    Features

    2.0.0 (2019-12-09)

    -

    Features

    +

    Features

    -

    BREAKING CHANGES

    +

    BREAKING CHANGES

    -

    Features

    +

    Features

    1.10.0 (2019-09-05)

    -

    Features

    +

    Features

    @@ -3520,19 +3494,19 @@

    Bug FixesDo not remove import with no specifiers (side-effect imports) (4d0ad6c)
  • Topbar back button (100ffb9)
  • -

    Features

    +

    Features

    1.8.0 (2019-06-10)

    -

    Features

    +

    Features

    1.7.0 (2019-05-23)

    -

    Features

    +

    Features

    @@ -3545,7 +3519,7 @@

    Bug Fixes

    1.6.0 (2019-03-29)

    -

    Features

    +

    Features

    -

    Features

    +

    Features

    1.4.0 (2019-01-03)

    -

    Features

    +

    Features

    @@ -3625,7 +3599,7 @@

    Bug Fixes

    1.3.0 (2018-12-06)

    -

    Features

    +

    Features

    @@ -3677,7 +3651,7 @@

    Bug Fixes
  • remove unused dependency 🔥 (5fd7f1e)
  • -

    Features

    +

    Features

    diff --git a/en/cozy-flags/package.json b/en/cozy-flags/package.json index 83102f008..f78fb0f77 100644 --- a/en/cozy-flags/package.json +++ b/en/cozy-flags/package.json @@ -1,6 +1,6 @@ { "name": "cozy-flags", - "version": "3.2.2", + "version": "4.0.0", "description": "Flag library used in Cozy", "main": "dist/index.js", "browser": "dist/index.browser.js", diff --git a/en/cozy-flags/src/flag.js b/en/cozy-flags/src/flag.js index f1bfd474c..1fe1ea31d 100644 --- a/en/cozy-flags/src/flag.js +++ b/en/cozy-flags/src/flag.js @@ -6,14 +6,17 @@ const store = new FlagStore() /** * Public API to use flags + * @template T + * @param {string} key - The flag key to get or set. + * @param {T} [value] - The value to set for the flag key. If not provided, the function will return the value of the key. + * @returns {T} The value of the flag key when getting, or the set value when setting. */ -const flag = function () { - const args = [].slice.call(arguments) - if (args.length === 1) { - return store.get(args[0]) +const flag = function (key, value) { + if (arguments.length === 1) { + return store.get(key) } else { - store.set(args[0], args[1]) - return args[1] + store.set(key, value) + return value } } diff --git a/en/cozy-home/manifest.webapp b/en/cozy-home/manifest.webapp index e7ca0f6b9..e75922752 100644 --- a/en/cozy-home/manifest.webapp +++ b/en/cozy-home/manifest.webapp @@ -11,7 +11,7 @@ "name": "Cozy Cloud", "url": "https://cozy.io" }, - "version": "1.78.0", + "version": "1.79.0", "licence": "AGPL-3.0", "permissions": { "home": { diff --git a/en/cozy-home/package.json b/en/cozy-home/package.json index 5a571677b..98a983e08 100644 --- a/en/cozy-home/package.json +++ b/en/cozy-home/package.json @@ -1,6 +1,6 @@ { "name": "cozy-home", - "version": "1.78.0", + "version": "1.79.0", "main": "src/index.jsx", "scripts": { "tx": "tx pull --all || true", @@ -89,7 +89,6 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-import-alias": "^1.2.0", "git-directory-deploy": "1.5.1", - "husky": "1.3.1", "ignore-not-found-export-webpack-plugin": "1.0.2", "jest": "28.1.3", "jest-environment-jsdom": "28.1.3", @@ -103,15 +102,5 @@ "stylint": "2.0.0", "stylus": "0.55.0", "url-search-params-polyfill": "8.1.1" - }, - "lint-staged": { - "{src,test}/**/*.{js,jsx}": [ - "eslint" - ] - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } } } diff --git a/en/cozy-home/src/assets/images/default-wallpaper.svg b/en/cozy-home/src/assets/images/default-wallpaper.svg new file mode 100644 index 000000000..c6006d82e --- /dev/null +++ b/en/cozy-home/src/assets/images/default-wallpaper.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/cozy-home/src/components/AddServiceTile.jsx b/en/cozy-home/src/components/AddServiceTile.jsx index 745d063a7..aecbf6e4c 100644 --- a/en/cozy-home/src/components/AddServiceTile.jsx +++ b/en/cozy-home/src/components/AddServiceTile.jsx @@ -4,6 +4,14 @@ import AppLinker from 'cozy-ui/transpiled/react/AppLinker' import SquareAppIcon from 'cozy-ui/transpiled/react/SquareAppIcon' +/** + * AddServiceTile component. + * + * @param {Object} props - The component props. + * @param {string} props.label - The label for the service tile. + * @param {string} [props.category] - The category of the service tile. + * @returns {JSX.Element} The rendered AddServiceTile component. + */ const AddServiceTile = ({ label, category }) => { const client = useClient() const nativePath = `/discover/?type=konnector${ diff --git a/en/cozy-home/src/components/AnimatedWrapper.jsx b/en/cozy-home/src/components/AnimatedWrapper.jsx index 8ce549acb..68ef9da90 100644 --- a/en/cozy-home/src/components/AnimatedWrapper.jsx +++ b/en/cozy-home/src/components/AnimatedWrapper.jsx @@ -3,6 +3,8 @@ import { isFlagshipApp } from 'cozy-device-helper' import homeConfig from 'config/home.json' import { useOpenApp } from 'hooks/useOpenApp' import { RemoveScroll } from 'react-remove-scroll' +import { useWallpaperContext } from 'hooks/useWallpaperContext' +import cx from 'classnames' import App from 'containers/App' @@ -16,6 +18,9 @@ const RemoveScrollOnFlaghsip = ({ children }) => { const AnimatedWrapper = () => { const { getAppState } = useOpenApp() + const { + data: { isCustomWallpaper } + } = useWallpaperContext() const mainStyle = isFlagshipApp() ? { @@ -27,7 +32,11 @@ const AnimatedWrapper = () => { return (
    diff --git a/en/cozy-home/src/components/AppWrapper.jsx b/en/cozy-home/src/components/AppWrapper.jsx index a2f53cb3a..dac323112 100644 --- a/en/cozy-home/src/components/AppWrapper.jsx +++ b/en/cozy-home/src/components/AppWrapper.jsx @@ -10,16 +10,17 @@ import CozyTheme from 'cozy-ui/transpiled/react/providers/CozyTheme' import { BreakpointsProvider } from 'cozy-ui/transpiled/react/providers/Breakpoints' import { PersistGate } from 'redux-persist/integration/react' import AlertProvider from 'cozy-ui/transpiled/react/providers/Alert' +import { useCozyTheme } from 'cozy-ui/transpiled/react/providers/CozyTheme' import configureStore from 'store/configureStore' import { RealtimePlugin } from 'cozy-realtime' // import { isFlagshipApp } from 'cozy-device-helper' -import { usePreferedTheme } from 'hooks/usePreferedTheme' +import { useWallpaperContext } from 'hooks/useWallpaperContext' import schema from '../schema' import { ConditionalWrapper } from './ConditionalWrapper' -import { CustomWallPaperProvider } from 'hooks/useCustomWallpaperContext' +import { WallPaperProvider } from 'hooks/useWallpaperContext' import { SectionsProvider } from './Sections/SectionsContext' const dictRequire = lang => require(`locales/${lang}.json`) @@ -73,11 +74,20 @@ const Inner = ({ children, lang, context }) => ( ) const ThemeProvider = ({ children }) => { - const preferedTheme = usePreferedTheme() + const { + data: { isCustomWallpaper } + } = useWallpaperContext() + const { type } = useCozyTheme() + + const variant = isCustomWallpaper + ? type === 'light' + ? 'inverted' + : 'normal' + : 'normal' return ( {children} @@ -97,8 +107,8 @@ const AppWrapper = ({ children }) => { - - + + @@ -118,7 +128,7 @@ const AppWrapper = ({ children }) => { - + diff --git a/en/cozy-home/src/components/AppWrapper.spec.jsx b/en/cozy-home/src/components/AppWrapper.spec.jsx index f18e6d58c..1703d647d 100644 --- a/en/cozy-home/src/components/AppWrapper.spec.jsx +++ b/en/cozy-home/src/components/AppWrapper.spec.jsx @@ -5,7 +5,7 @@ import AppWrapper, { setupAppContext } from './AppWrapper' import { render } from '@testing-library/react' import React from 'react' import AppLike from 'test/AppLike' -import { CustomWallPaperProvider } from 'hooks/useCustomWallpaperContext' +import { WallPaperProvider } from 'hooks/useWallpaperContext' import { act } from 'react-dom/test-utils' const mockClient = { @@ -44,9 +44,6 @@ jest.mock('redux-persist/integration/react', () => ({ })) const AddButtonMock = () => <> jest.mock('./AddButton/AddButton', () => AddButtonMock) -jest.mock('hooks/usePreferedTheme', () => ({ - usePreferedTheme: jest.fn().mockReturnValue('inverted') -})) describe('AppWrapper.jsx', () => { beforeEach(() => { @@ -80,9 +77,9 @@ describe('AppWrapper.jsx', () => { // When const { getByText } = render( - + children - + ) await act(async () => {}) @@ -99,7 +96,7 @@ describe('AppWrapper.jsx', () => { // When const { getAllByTestId } = render( - children + children ) await act(async () => {}) diff --git a/en/cozy-home/src/components/BackgroundContainer.tsx b/en/cozy-home/src/components/BackgroundContainer.tsx index 575cd125b..053fe2eb0 100644 --- a/en/cozy-home/src/components/BackgroundContainer.tsx +++ b/en/cozy-home/src/components/BackgroundContainer.tsx @@ -1,42 +1,30 @@ import React from 'react' import cx from 'classnames' -import { useCustomWallpaperContext } from 'hooks/useCustomWallpaperContext' -import { getHomeThemeCssVariable } from 'hooks/usePreferedTheme' - -type BackgroundContainerComputedProps = { - className: string - style?: { backgroundImage: string } -} - -const makeProps = ( - backgroundURL: string | null, - isCustomWallpaper: boolean, - binaryCustomWallpaper: string | null -): BackgroundContainerComputedProps => ({ - className: cx('background-container', { - 'background-container-darken': - isCustomWallpaper || getHomeThemeCssVariable() !== 'normal', - 'home-default-partner-background': - !isCustomWallpaper && getHomeThemeCssVariable() === 'normal' - }), - ...(binaryCustomWallpaper && { - style: { backgroundImage: `url(${binaryCustomWallpaper})` } - }), - ...(!binaryCustomWallpaper && - backgroundURL && { - style: { backgroundImage: `url(${backgroundURL})` } - }) -}) +import { useWallpaperContext } from 'hooks/useWallpaperContext' +import { useCozyTheme } from 'cozy-ui/transpiled/react/providers/CozyTheme' export const BackgroundContainer = (): JSX.Element => { const { - data: { wallpaperLink, binaryCustomWallpaper, isCustomWallpaper } - } = useCustomWallpaperContext() + data: { binaryCustomWallpaper, isCustomWallpaper } + } = useWallpaperContext() + const { type } = useCozyTheme() return (
    diff --git a/en/cozy-home/src/components/Sections/GroupedSectionTile.tsx b/en/cozy-home/src/components/Sections/GroupedSectionTile.tsx new file mode 100644 index 000000000..615cb2160 --- /dev/null +++ b/en/cozy-home/src/components/Sections/GroupedSectionTile.tsx @@ -0,0 +1,56 @@ +import React from 'react' +import { useNavigate } from 'react-router-dom' + +import SquareAppIcon from 'cozy-ui/transpiled/react/SquareAppIcon' +import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n' + +import SectionAppGroup from 'components/Sections/SectionAppGroup' +import { get4FirstItems } from 'components/Sections/utils' +import { GroupedSectionTileProps } from 'components/Sections/SectionsTypes' + +const GroupedSectionTile = ({ + section +}: GroupedSectionTileProps): JSX.Element | null => { + const navigate = useNavigate() + const { t } = useI18n() + + const handleNavigation = ( + name: string, + type: 'konnectors' | 'shortcuts' + ): void => { + navigate(`categories/${type}/${name}`) + } + + // We add a failsafe in the view to avoid rendering an empty section + // This case appeared in prod environment but wasn't expected to be possible + if (section.items.length === 0) return null + + return ( + + handleNavigation( + section.id, + section.type === 'category' ? 'konnectors' : 'shortcuts' + ) + } + className="scale-hover u-c-pointer" + > + } + variant={section.pristine ? 'ghost' : 'normal'} + style={{ + alignItems: 'flex-start', + justifyContent: 'flex-start' + }} + /> + + ) +} + +export default GroupedSectionTile diff --git a/en/cozy-home/src/components/Sections/GroupedSectionsView.tsx b/en/cozy-home/src/components/Sections/GroupedSectionsView.tsx index f253eb8ef..a96223207 100644 --- a/en/cozy-home/src/components/Sections/GroupedSectionsView.tsx +++ b/en/cozy-home/src/components/Sections/GroupedSectionsView.tsx @@ -1,13 +1,11 @@ import React, { useRef, useState } from 'react' -import { useNavigate } from 'react-router-dom' -import SquareAppIcon from 'cozy-ui/transpiled/react/SquareAppIcon' import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n' -import SectionAppGroup from 'components/Sections/SectionAppGroup' import { GroupedSectionViewProps } from 'components/Sections/SectionsTypes' import { SectionHeader } from 'components/Sections/SectionHeader' -import { get4FirstItems } from 'components/Sections/utils' +import AddServiceTile from 'components/AddServiceTile' +import GroupedSectionTile from 'components/Sections/GroupedSectionTile' export const GroupedSectionView = ({ sections @@ -16,13 +14,8 @@ export const GroupedSectionView = ({ const anchorRef = useRef(null) const toggleMenu = (): void => setMenuState(!menuState) const { t } = useI18n() - const navigate = useNavigate() - const handleNavigation = ( - name: string, - type: 'konnectors' | 'shortcuts' - ): void => { - navigate(`categories/${type}/${name}`) - } + + const isServicesView = sections.find(section => section.type === 'category') return ( ) diff --git a/en/cozy-home/src/components/Sections/SectionsTypes.ts b/en/cozy-home/src/components/Sections/SectionsTypes.ts index 20f3f1957..215279754 100644 --- a/en/cozy-home/src/components/Sections/SectionsTypes.ts +++ b/en/cozy-home/src/components/Sections/SectionsTypes.ts @@ -43,6 +43,10 @@ export interface GroupedSectionViewProps { sections: Section[] } +export interface GroupedSectionTileProps { + section: Section +} + export interface SectionsViewProps { data?: IOCozyFile[] | IOCozyKonnector[] type: 'shortcuts' | 'konnectorCategories' diff --git a/en/cozy-home/src/containers/App.spec.jsx b/en/cozy-home/src/containers/App.spec.jsx index a6dd78448..cc7bf5c1c 100644 --- a/en/cozy-home/src/containers/App.spec.jsx +++ b/en/cozy-home/src/containers/App.spec.jsx @@ -3,7 +3,7 @@ import { isFlagshipApp } from 'cozy-device-helper' import { render } from '@testing-library/react' import App from '../components/AnimatedWrapper' import AppLike from 'test/AppLike' -import { CustomWallPaperProvider } from 'hooks/useCustomWallpaperContext' +import { WallPaperProvider } from 'hooks/useWallpaperContext' import { act } from 'react-dom/test-utils' import CozyTheme from 'cozy-ui/transpiled/react/providers/CozyTheme' @@ -50,9 +50,9 @@ describe('App', () => { const { container } = render( - + - + ) @@ -75,9 +75,9 @@ describe('App', () => { const { container } = render( - + - + ) diff --git a/en/cozy-home/src/hooks/useCustomWallpaperContext.tsx b/en/cozy-home/src/hooks/useCustomWallpaperContext.tsx deleted file mode 100644 index 56a0bfde1..000000000 --- a/en/cozy-home/src/hooks/useCustomWallpaperContext.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react' -import useCustomWallpaper from './useCustomWallpaper' - -const CustomWallPaperContext = React.createContext< - CustomWallPaperContextInterface | undefined ->(undefined) - -interface CustomWallPaperContextInterfaceData { - wallpaperLink: string | null - binaryCustomWallpaper: string | null - isCustomWallpaper: boolean -} -interface CustomWallPaperContextInterface { - data: CustomWallPaperContextInterfaceData - fetchStatus: string -} -export const CustomWallPaperProvider = ({ - children -}: { - children: JSX.Element -}): JSX.Element => { - const data = useCustomWallpaper() as CustomWallPaperContextInterface - return ( - - {children} - - ) -} - -export const useCustomWallpaperContext = - (): CustomWallPaperContextInterface => { - const context = React.useContext(CustomWallPaperContext) - if (context === undefined) { - throw new Error( - 'useCustomWallpaperContext must be used within a CustomWallpaperProvider' - ) - } - return context - } diff --git a/en/cozy-home/src/hooks/usePreferedTheme.ts b/en/cozy-home/src/hooks/usePreferedTheme.ts deleted file mode 100644 index a6452b061..000000000 --- a/en/cozy-home/src/hooks/usePreferedTheme.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { useState, useEffect, useMemo } from 'react' -import { useCustomWallpaperContext } from './useCustomWallpaperContext' -import { useCozyTheme } from 'cozy-ui/transpiled/react/providers/CozyTheme' - -export const getHomeThemeCssVariable = (): string => { - return getComputedStyle(document.getElementsByTagName('body')[0]) - .getPropertyValue('--home-theme') - .trim() -} - -export const usePreferedTheme = (): string => { - const { - data: { wallpaperLink, binaryCustomWallpaper, isCustomWallpaper } - } = useCustomWallpaperContext() - const { type } = useCozyTheme() - const defaultVariant = useMemo( - () => (type === 'dark' ? 'normal' : 'inverted'), - [type] - ) - const [preferedVariant, setPreferedVariant] = useState(defaultVariant) - - useEffect(() => { - const variantFromCSS = getHomeThemeCssVariable() - - if (isCustomWallpaper) { - setPreferedVariant(defaultVariant) - } else { - setPreferedVariant(variantFromCSS || defaultVariant) - } - }, [wallpaperLink, binaryCustomWallpaper, isCustomWallpaper, defaultVariant]) - - return preferedVariant -} diff --git a/en/cozy-home/src/hooks/useCustomWallpaper.jsx b/en/cozy-home/src/hooks/useWallpaper.jsx similarity index 96% rename from en/cozy-home/src/hooks/useCustomWallpaper.jsx rename to en/cozy-home/src/hooks/useWallpaper.jsx index c945ada20..a9ee47014 100644 --- a/en/cozy-home/src/hooks/useCustomWallpaper.jsx +++ b/en/cozy-home/src/hooks/useWallpaper.jsx @@ -3,7 +3,7 @@ import homeConfig from 'config/home.json' import { useClient } from 'cozy-client' import localForage from 'localforage' -const useCustomWallpaper = () => { +const useWallpaper = () => { const client = useClient() const [wallpaperLink, setWallpaperLink] = useState(null) const [fetchStatus, setFetchStatus] = useState('idle') @@ -61,4 +61,4 @@ const useCustomWallpaper = () => { } } -export default useCustomWallpaper +export default useWallpaper diff --git a/en/cozy-home/src/hooks/useWallpaperContext.tsx b/en/cozy-home/src/hooks/useWallpaperContext.tsx new file mode 100644 index 000000000..161e52a5d --- /dev/null +++ b/en/cozy-home/src/hooks/useWallpaperContext.tsx @@ -0,0 +1,38 @@ +import React from 'react' +import useWallpaper from './useWallpaper' + +const WallPaperContext = React.createContext< + WallPaperContextInterface | undefined +>(undefined) + +interface WallPaperContextInterfaceData { + wallpaperLink: string | null + binaryCustomWallpaper: string | null + isCustomWallpaper: boolean +} +interface WallPaperContextInterface { + data: WallPaperContextInterfaceData + fetchStatus: string +} +export const WallPaperProvider = ({ + children +}: { + children: JSX.Element +}): JSX.Element => { + const data = useWallpaper() as WallPaperContextInterface + return ( + + {children} + + ) +} + +export const useWallpaperContext = (): WallPaperContextInterface => { + const context = React.useContext(WallPaperContext) + if (context === undefined) { + throw new Error( + 'useWallpaperContext must be used within a WallpaperProvider' + ) + } + return context +} diff --git a/en/cozy-home/src/styles/app.styl b/en/cozy-home/src/styles/app.styl index 5c0448d8e..d17db78d7 100644 --- a/en/cozy-home/src/styles/app.styl +++ b/en/cozy-home/src/styles/app.styl @@ -24,44 +24,45 @@ body overflow auto .App - // Avoid mix-blend-mode from background-container to be linked to the background color of the body. + // Avoid mix-blend-mode from home-custom-background to be linked to the background color of the body. // Must not be responsive to the theme. background-color white - background-repeat no-repeat - background-size cover - background-position center overflow-y auto + + &.custom-wallpaper + // black filter effect above the custom wallpaper image + &::before + content '' + position fixed + top 0 + left 0 + width 100% + height 100% + background-color rgba(0, 0, 0, .32) + backdrop-filter saturate(124%) + .corner z-index var(--zIndex-nav) margin rem(12) 2rem rem(-44) 0 + .corner-button +small-screen() height 3rem width 3rem margin 0 + +small-screen() margin 0 0 -3rem -// black filter effect above the wallpaper image -.App::before - content '' - position fixed - top 0 - left 0 - width 100% - height 100% - background-color rgba(0, 0, 0, .32) - backdrop-filter saturate(124%) - +small-screen() - .main-view, .background-container + .main-view, .home-custom-background transition transform 200ms ease-out will-change transform .App--opened .main-view transform scale(1.3) - .background-container + .home-custom-background transform scale(1.1) diff --git a/en/cozy-home/src/styles/backgroundContainer.styl b/en/cozy-home/src/styles/backgroundContainer.styl index 4173c274b..d418da6f5 100644 --- a/en/cozy-home/src/styles/backgroundContainer.styl +++ b/en/cozy-home/src/styles/backgroundContainer.styl @@ -1,14 +1,26 @@ -.background-container - background-position center - background-repeat no-repeat - background-size cover - height 100vh +.home-background-container position fixed + height 100vh width 100% -.background-container-darken - mix-blend-mode multiply + &--light + background-color #E9F4FF -.home-default-partner-background - background-repeat repeat - background-size initial \ No newline at end of file + &--dark + background-color #142536 + +.home-default-background + &::before + content '' + position fixed + height 100% + width 100% + background-size 100% 100% + background-image url('../assets/images/default-wallpaper.svg') + opacity .24 + +.home-custom-background + mix-blend-mode multiply + background-position center + background-repeat no-repeat + background-size cover diff --git a/en/cozy-home/yarn.lock b/en/cozy-home/yarn.lock index 81033397f..09620a159 100644 --- a/en/cozy-home/yarn.lock +++ b/en/cozy-home/yarn.lock @@ -5904,7 +5904,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cosmiconfig@^5.0.0, cosmiconfig@^5.0.7, cosmiconfig@^5.2.0: +cosmiconfig@^5.0.0, cosmiconfig@^5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== @@ -9331,22 +9331,6 @@ human-size@^1.1.0: resolved "https://registry.yarnpkg.com/human-size/-/human-size-1.1.0.tgz#052562be999841c037022c20259990c56ea996f9" integrity sha1-BSVivpmYQcA3AiwgJZmQxW6plvk= -husky@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/husky/-/husky-1.3.1.tgz#26823e399300388ca2afff11cfa8a86b0033fae0" - integrity sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg== - dependencies: - cosmiconfig "^5.0.7" - execa "^1.0.0" - find-up "^3.0.0" - get-stdin "^6.0.0" - is-ci "^2.0.0" - pkg-dir "^3.0.0" - please-upgrade-node "^3.1.1" - read-pkg "^4.0.1" - run-node "^1.0.0" - slash "^2.0.0" - hyphenate-style-name@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" @@ -12275,9 +12259,9 @@ msgpack5@^4.0.2: readable-stream "^2.3.6" safe-buffer "^5.1.2" -"mui-bottom-sheet@git+https://github.com/cozy/mui-bottom-sheet.git#v1.0.9": +"mui-bottom-sheet@https://github.com/cozy/mui-bottom-sheet.git#v1.0.9": version "1.0.8" - resolved "git+https://github.com/cozy/mui-bottom-sheet.git#3dc4c2a245ab39079bc2f73546bccf80847be14c" + resolved "https://github.com/cozy/mui-bottom-sheet.git#3dc4c2a245ab39079bc2f73546bccf80847be14c" dependencies: "@juggle/resize-observer" "^3.1.3" jest-environment-jsdom-sixteen "^1.0.3" @@ -13316,7 +13300,7 @@ pkginfo@0.3.x, pkginfo@0.x.x: resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" integrity sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE= -please-upgrade-node@^3.0.2, please-upgrade-node@^3.1.1: +please-upgrade-node@^3.0.2: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== @@ -14288,15 +14272,6 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -read-pkg@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" - integrity sha1-ljYlN48+HE1IyFhytabsfV0JMjc= - dependencies: - normalize-package-data "^2.3.2" - parse-json "^4.0.0" - pify "^3.0.0" - read-pkg@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" @@ -14973,11 +14948,6 @@ run-async@^2.2.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== -run-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e" - integrity sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A== - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" diff --git a/en/search/search_index.json b/en/search/search_index.json index bca2c50a4..3e27fe2b3 100644 --- a/en/search/search_index.json +++ b/en/search/search_index.json @@ -1 +1 @@ -{"config": {"indexing": "full", "lang": ["en"], "min_search_length": 3, "prebuild_index": false, "separator": "[\\s\\-]+"}, "docs": [{"location": "", "text": "Cozy Documentation \u00b6 How-to \u00b6 Find guides for developing apps and connectors and for self-hosting. How to develop apps For Developers How to free data with connectors For Developers How to manipulate data For Developers How to install your own server For Self-Hosting Projects Documentation \u00b6 Cozy Banks Cozy Stack Cozy UI More Projects ... Get in touch \u00b6 Get help from our great community on our forum and on our IRC chat . Of course you can also write an email to our Support team: claude at cozycloud.cc.", "title": "Home"}, {"location": "#cozy-documentation", "text": "", "title": "Cozy Documentation"}, {"location": "#how-to", "text": "Find guides for developing apps and connectors and for self-hosting. How to develop apps For Developers How to free data with connectors For Developers How to manipulate data For Developers How to install your own server For Self-Hosting", "title": "How-to"}, {"location": "#projects-documentation", "text": "Cozy Banks Cozy Stack Cozy UI More Projects ...", "title": "Projects Documentation"}, {"location": "#get-in-touch", "text": "Get help from our great community on our forum and on our IRC chat . Of course you can also write an email to our Support team: claude at cozycloud.cc.", "title": "Get in touch"}, {"location": "privacy/", "text": "Privacy \u00b6 We track usage of our documentation anonymously. You can disable navigation data collection below if you don\u2019t want to participate.", "title": "Privacy"}, {"location": "privacy/#privacy", "text": "We track usage of our documentation anonymously. You can disable navigation data collection below if you don\u2019t want to participate.", "title": "Privacy"}, {"location": "ach/", "text": "ACH \u00b6 Automated Cozy Hydrater (ACH [ax] ) is a CLI that lets you request, create and remove records in your Cozy . Install Usage Examples Import data Import repositories with files Create photo albums with ACH Export data removing the ids Import data from a CSV Generate some files Generate some qualified files with referenced contacts (mespapiers) Install \u00b6 Install ACH using yarn 1 (v1.22.18 or greater) $ yarn global add cozy-ach If you cannot execute ACH after this command, it may be because you do not have the directory where yarn stores its symbolic links in your PATH . Edit it to append the result of yarn global bin . Usage \u00b6 Usage : ACH [ options ] [ command ] Options : - V , -- version output the version number - t -- token [ token ] Token file to use - y -- yes Does not ask for confirmation on sensitive operations - u -- url [ url ] URL of the cozy to use . Defaults to \"http://cozy.localhost:8080\" . ' (default: \"http://cozy.localhost:8080\") - h , -- help output usage information Commands : import < filepath > [ handlebarsOptionsFile ] The file containing the JSON data to import . Defaults to \"example-data.json\" . If the file doesn 't exist in the application, ACH will try to find it inside its data folder. Then the dummy helpers JS file (optional). importDir < directoryPath > The path to the directory content to import . Defaults to \"./DirectoriesToInject\" . generateFiles [ filesCount ] [ dirId ] Generates a given number of small files . ( optional dirId ) drop [ options ] < doctypes ...> Deletes all documents of the provided doctypes . For real . export < doctypes > [ filename ] Exports data from the doctypes ( separated by commas ) to filename downloadFile < fileid > Download the file delete < doctype > < ids ...> Delete document ( s ) updateSettings Update settings token < doctypes ...> Generate token script [ options ] < scriptName > Launch script ls - scripts Lists all built - in scripts , useful for autocompletion batch [ options ] < scriptName > < domainsFile > Launch script Examples \u00b6 Import data \u00b6 $ cat data.json { \"io.cozy.bills\" : [ { \"_id\" : \"eba16106554ca9e23012f83f9c7937c0\" , \"amount\" : 0 .71, \"beneficiary\" : \"Thyrion Lannister\" , \"date\" : \"1455-05-08T22:00:00.000Z\" , \"filename\" : \"20170508_528117465_R17125200206528395_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=34\" , \"groupAmount\" : 3 .58, \"idPrestation\" : \"528117465_R17125200206528395_412877436\" , \"idReimbursement\" : \"528117465_R17125200206528395\" , \"invoice\" : \"io.cozy.files:ff5864e01f2d20c472f2b0f6531860b7\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 2 .04, \"originalDate\" : \"2017-04-28T22:00:00.000Z\" , \"socialSecurityRefund\" : 1 .33, \"subtype\" : \"Liver transplant\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c793761\" , \"amount\" : 50 , \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"1455-05-17T22:00:00.000Z\" , \"filename\" : \"20170517_528117465_R17137202332136169_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=33\" , \"groupAmount\" : 175 , \"idPrestation\" : \"528117465_R17137202332136169_415641280\" , \"idReimbursement\" : \"528117465_R17137202332136169\" , \"invoice\" : \"io.cozy.files:c9a4b2104b4a10de543bd574ac9ff9b1\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 108 , \"originalDate\" : \"1455-05-09T22:00:00.000Z\" , \"socialSecurityRefund\" : 7 .22, \"subtype\" : \"Golden hand\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c7936fa\" , \"amount\" : 7 .5, \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"1455-05-21T22:00:00.000Z\" , \"filename\" : \"20170521_528117465_R171401014733001_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=32\" , \"groupAmount\" : 7 .5, \"idPrestation\" : \"528117465_R171401014733001_416477228\" , \"idReimbursement\" : \"528117465_R171401014733001\" , \"invoice\" : \"io.cozy.files:c9a4b2104b4a10de543bd574ac9fed3a\" , \"isRefund\" : true, \"isThirdPartyPayer\" : false, \"originalAmount\" : 25 , \"originalDate\" : \"1455-05-15T22:00:00.000Z\" , \"socialSecurityRefund\" : 17 .5, \"subtype\" : \"Chiropractor\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c7936dd\" , \"amount\" : 0 .89, \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"2017-07-30T22:00:00.000Z\" , \"filename\" : \"20170730_528117465_R17209200405325685_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=30\" , \"groupAmount\" : 5 .21, \"idPrestation\" : \"528117465_R17209200405325685_432873233\" , \"idReimbursement\" : \"528117465_R17209200405325685\" , \"invoice\" : \"io.cozy.files:ff5864e01f2d20c472f2b0f6531853ef\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 2 .54, \"originalDate\" : \"2017-07-24T22:00:00.000Z\" , \"socialSecurityRefund\" : 1 .65, \"subtype\" : \"Chemist\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c79311a\" , \"amount\" : 0 .36, \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"2017-08-06T22:00:00.000Z\" , \"filename\" : \"20170806_528117465_R17216201307522910_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=29\" , \"groupAmount\" : 7 .709999999999999, \"idPrestation\" : \"528117465_R17216201307522910_434482904\" , \"idReimbursement\" : \"528117465_R17216201307522910\" , \"invoice\" : \"io.cozy.files:ff5864e01f2d20c472f2b0f653185344\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 1 .02, \"originalDate\" : \"2017-08-01T22:00:00.000Z\" , \"socialSecurityRefund\" : 0 .66, \"subtype\" : \"Sour \" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } ] } $ ACH import data.json If the file doesn\u2019t exist in the application, ACH will try to find it inside its data folder. handlebars \u00b6 Some JSON files use handlebars helpers, for those file, you need to specify the file where the helpers are defined. $ ACH import data/bank/bankData.json data/bank/helpers/bankDummyHelpers.js You can see an example of helpers here . \u2013url param \u00b6 You can import to a remote Cozy with the --url option : $ ACH import data/bank/bankData.json data/bank/helpers/bankDummyHelpers.js --url https://recette.cozy.works serial import \u00b6 By default, ACH imports data in parallel, by batches of 25. It is possible to import serially : $ env ACH_PARALLEL = false ACH import data.json Import directories with files \u00b6 To import a directory into a Cozy, use the importDir command: $ ACH importDir myDirectoryPath # default will be ./DirectoriesToInject All your target directory content will be imported to the root of Cozy Drive following the correct repositories tree. Create photo albums with ACH \u00b6 You can create photo albums from a folder on your disk. $ python scripts/albums-from-dir.py my-photos-directory resulting-albums.json Export data removing the ids \u00b6 By default, exported data contains all _id . Sometimes, you want to strip the ids from the documents you export. Set the environment variable ACH_NO_KEEP_ID to do so : env ACH_NO_KEEP_ID = true ACH export io.cozy.bills --url https://isabelledurand.cozy.rocks ./bills.json Contrary to _id , _rev is stripped by default. To keep the _rev field, set the environment variable ACH_KEEP_REV . Import data from a CSV \u00b6 See the example . Generate some files \u00b6 To create files into a Cozy, use the generateFiles command: $ ACH generateFiles 10 # by default will be at the root of your Drive Options: - -q / --qualify : In order to have a random qualification on your files - -m / --mime : In order to change the default mime of files ( text/plain ) Generate some papers \u00b6 (usefull for MesPapiers) To create qualified files with contacts referenced in a Cozy, use the script papers/createPapers command. ACH script papers/createPapers [ numberFile ] [ folderId ] -t Parameters: - numberFile : Number of papers to create (default: 1) - folderId : ID of the folder where the files will be created. (default: \u2018io.cozy.files.root-dir\u2019) Options: - -t / --token : app/konnector token, required to view files in the MesPapiers app. (Creates the cozyMetadata.createdByApp prop)", "title": "ACH"}, {"location": "ach/#ach", "text": "Automated Cozy Hydrater (ACH [ax] ) is a CLI that lets you request, create and remove records in your Cozy . Install Usage Examples Import data Import repositories with files Create photo albums with ACH Export data removing the ids Import data from a CSV Generate some files Generate some qualified files with referenced contacts (mespapiers)", "title": "ACH"}, {"location": "ach/#install", "text": "Install ACH using yarn 1 (v1.22.18 or greater) $ yarn global add cozy-ach If you cannot execute ACH after this command, it may be because you do not have the directory where yarn stores its symbolic links in your PATH . Edit it to append the result of yarn global bin .", "title": "Install"}, {"location": "ach/#usage", "text": "Usage : ACH [ options ] [ command ] Options : - V , -- version output the version number - t -- token [ token ] Token file to use - y -- yes Does not ask for confirmation on sensitive operations - u -- url [ url ] URL of the cozy to use . Defaults to \"http://cozy.localhost:8080\" . ' (default: \"http://cozy.localhost:8080\") - h , -- help output usage information Commands : import < filepath > [ handlebarsOptionsFile ] The file containing the JSON data to import . Defaults to \"example-data.json\" . If the file doesn 't exist in the application, ACH will try to find it inside its data folder. Then the dummy helpers JS file (optional). importDir < directoryPath > The path to the directory content to import . Defaults to \"./DirectoriesToInject\" . generateFiles [ filesCount ] [ dirId ] Generates a given number of small files . ( optional dirId ) drop [ options ] < doctypes ...> Deletes all documents of the provided doctypes . For real . export < doctypes > [ filename ] Exports data from the doctypes ( separated by commas ) to filename downloadFile < fileid > Download the file delete < doctype > < ids ...> Delete document ( s ) updateSettings Update settings token < doctypes ...> Generate token script [ options ] < scriptName > Launch script ls - scripts Lists all built - in scripts , useful for autocompletion batch [ options ] < scriptName > < domainsFile > Launch script", "title": "Usage"}, {"location": "ach/#examples", "text": "", "title": "Examples"}, {"location": "ach/#import-data", "text": "$ cat data.json { \"io.cozy.bills\" : [ { \"_id\" : \"eba16106554ca9e23012f83f9c7937c0\" , \"amount\" : 0 .71, \"beneficiary\" : \"Thyrion Lannister\" , \"date\" : \"1455-05-08T22:00:00.000Z\" , \"filename\" : \"20170508_528117465_R17125200206528395_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=34\" , \"groupAmount\" : 3 .58, \"idPrestation\" : \"528117465_R17125200206528395_412877436\" , \"idReimbursement\" : \"528117465_R17125200206528395\" , \"invoice\" : \"io.cozy.files:ff5864e01f2d20c472f2b0f6531860b7\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 2 .04, \"originalDate\" : \"2017-04-28T22:00:00.000Z\" , \"socialSecurityRefund\" : 1 .33, \"subtype\" : \"Liver transplant\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c793761\" , \"amount\" : 50 , \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"1455-05-17T22:00:00.000Z\" , \"filename\" : \"20170517_528117465_R17137202332136169_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=33\" , \"groupAmount\" : 175 , \"idPrestation\" : \"528117465_R17137202332136169_415641280\" , \"idReimbursement\" : \"528117465_R17137202332136169\" , \"invoice\" : \"io.cozy.files:c9a4b2104b4a10de543bd574ac9ff9b1\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 108 , \"originalDate\" : \"1455-05-09T22:00:00.000Z\" , \"socialSecurityRefund\" : 7 .22, \"subtype\" : \"Golden hand\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c7936fa\" , \"amount\" : 7 .5, \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"1455-05-21T22:00:00.000Z\" , \"filename\" : \"20170521_528117465_R171401014733001_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=32\" , \"groupAmount\" : 7 .5, \"idPrestation\" : \"528117465_R171401014733001_416477228\" , \"idReimbursement\" : \"528117465_R171401014733001\" , \"invoice\" : \"io.cozy.files:c9a4b2104b4a10de543bd574ac9fed3a\" , \"isRefund\" : true, \"isThirdPartyPayer\" : false, \"originalAmount\" : 25 , \"originalDate\" : \"1455-05-15T22:00:00.000Z\" , \"socialSecurityRefund\" : 17 .5, \"subtype\" : \"Chiropractor\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c7936dd\" , \"amount\" : 0 .89, \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"2017-07-30T22:00:00.000Z\" , \"filename\" : \"20170730_528117465_R17209200405325685_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=30\" , \"groupAmount\" : 5 .21, \"idPrestation\" : \"528117465_R17209200405325685_432873233\" , \"idReimbursement\" : \"528117465_R17209200405325685\" , \"invoice\" : \"io.cozy.files:ff5864e01f2d20c472f2b0f6531853ef\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 2 .54, \"originalDate\" : \"2017-07-24T22:00:00.000Z\" , \"socialSecurityRefund\" : 1 .65, \"subtype\" : \"Chemist\" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } , { \"_id\" : \"eba16106554ca9e23012f83f9c79311a\" , \"amount\" : 0 .36, \"beneficiary\" : \"Jamie LANNISTER\" , \"date\" : \"2017-08-06T22:00:00.000Z\" , \"filename\" : \"20170806_528117465_R17216201307522910_malakoff_mederic.pdf\" , \"fileurl\" : \"https://extranet.braavos-bank.com/espaceClient/sante/tbs/tbsGenererPDF.do?remb=29\" , \"groupAmount\" : 7 .709999999999999, \"idPrestation\" : \"528117465_R17216201307522910_434482904\" , \"idReimbursement\" : \"528117465_R17216201307522910\" , \"invoice\" : \"io.cozy.files:ff5864e01f2d20c472f2b0f653185344\" , \"isRefund\" : true, \"isThirdPartyPayer\" : true, \"originalAmount\" : 1 .02, \"originalDate\" : \"2017-08-01T22:00:00.000Z\" , \"socialSecurityRefund\" : 0 .66, \"subtype\" : \"Sour \" , \"type\" : \"health_costs\" , \"vendor\" : \"Iron Bank of Braavos\" } ] } $ ACH import data.json If the file doesn\u2019t exist in the application, ACH will try to find it inside its data folder.", "title": "Import data"}, {"location": "ach/#handlebars", "text": "Some JSON files use handlebars helpers, for those file, you need to specify the file where the helpers are defined. $ ACH import data/bank/bankData.json data/bank/helpers/bankDummyHelpers.js You can see an example of helpers here .", "title": "handlebars"}, {"location": "ach/#-url-param", "text": "You can import to a remote Cozy with the --url option : $ ACH import data/bank/bankData.json data/bank/helpers/bankDummyHelpers.js --url https://recette.cozy.works", "title": "--url param"}, {"location": "ach/#serial-import", "text": "By default, ACH imports data in parallel, by batches of 25. It is possible to import serially : $ env ACH_PARALLEL = false ACH import data.json", "title": "serial import"}, {"location": "ach/#import-directories-with-files", "text": "To import a directory into a Cozy, use the importDir command: $ ACH importDir myDirectoryPath # default will be ./DirectoriesToInject All your target directory content will be imported to the root of Cozy Drive following the correct repositories tree.", "title": "Import directories with files"}, {"location": "ach/#create-photo-albums-with-ach", "text": "You can create photo albums from a folder on your disk. $ python scripts/albums-from-dir.py my-photos-directory resulting-albums.json", "title": "Create photo albums with ACH"}, {"location": "ach/#export-data-removing-the-ids", "text": "By default, exported data contains all _id . Sometimes, you want to strip the ids from the documents you export. Set the environment variable ACH_NO_KEEP_ID to do so : env ACH_NO_KEEP_ID = true ACH export io.cozy.bills --url https://isabelledurand.cozy.rocks ./bills.json Contrary to _id , _rev is stripped by default. To keep the _rev field, set the environment variable ACH_KEEP_REV .", "title": "Export data removing the ids"}, {"location": "ach/#import-data-from-a-csv", "text": "See the example .", "title": "Import data from a CSV"}, {"location": "ach/#generate-some-files", "text": "To create files into a Cozy, use the generateFiles command: $ ACH generateFiles 10 # by default will be at the root of your Drive Options: - -q / --qualify : In order to have a random qualification on your files - -m / --mime : In order to change the default mime of files ( text/plain )", "title": "Generate some files"}, {"location": "ach/#generate-some-papers", "text": "(usefull for MesPapiers) To create qualified files with contacts referenced in a Cozy, use the script papers/createPapers command. ACH script papers/createPapers [ numberFile ] [ folderId ] -t Parameters: - numberFile : Number of papers to create (default: 1) - folderId : ID of the folder where the files will be created. (default: \u2018io.cozy.files.root-dir\u2019) Options: - -t / --token : app/konnector token, required to view files in the MesPapiers app. (Creates the cozyMetadata.createdByApp prop)", "title": "Generate some papers"}, {"location": "ach/DirectoriesToInject/testFile2/", "text": "", "title": "testFile2"}, {"location": "ach/DirectoriesToInject/Folder/testFile1/", "text": "", "title": "testFile1"}, {"location": "ach/data/bank/", "text": "The fixtures for Banks are in its repository . https://github.com/cozy/cozy-banks/tree/master/test/fixtures", "title": "Index"}, {"location": "ach/e2e/", "text": "E2E flow \u00b6 Create a cozy via Cloudery (or reuse an existing one, see below) Sets passphrase When setting the passphrase, the stack responds with a cookie that is kept for future logins \u26a0\ufe0f Since the passphrase is not hashed properly before being sent to the Cozy), we cannot login to the Cozy afterwards, this is not a real problem since 1) the Cozy is temporary, 2) we already are logged into the Cozy after setting the passphrase To create a usable token for ACH, we use the OAuth flow and reuse the session created after the passphrase is sent. \u2139\ufe0f The cookie jar used for the session is saved, this means that if the test suite is run locally, the Cozy will be reused. \u2139\ufe0f The slug of the Cozy is random and in the form test . Then the ach executable is used to import / export / drop and the output is compared to what is expected. \u26a0\ufe0f E2E tests use a cloudery token accessed via environment variables. It can be found in the password store. If this variable is not set, the e2e test suite will be skipped. export CLOUDERY_TOKEN=$(pass show cozy/e2e-front/manager-token | head -n 1)", "title": "E2E flow"}, {"location": "ach/e2e/#e2e-flow", "text": "Create a cozy via Cloudery (or reuse an existing one, see below) Sets passphrase When setting the passphrase, the stack responds with a cookie that is kept for future logins \u26a0\ufe0f Since the passphrase is not hashed properly before being sent to the Cozy), we cannot login to the Cozy afterwards, this is not a real problem since 1) the Cozy is temporary, 2) we already are logged into the Cozy after setting the passphrase To create a usable token for ACH, we use the OAuth flow and reuse the session created after the passphrase is sent. \u2139\ufe0f The cookie jar used for the session is saved, this means that if the test suite is run locally, the Cozy will be reused. \u2139\ufe0f The slug of the Cozy is random and in the form test . Then the ach executable is used to import / export / drop and the output is compared to what is expected. \u26a0\ufe0f E2E tests use a cloudery token accessed via environment variables. It can be found in the password store. If this variable is not set, the e2e test suite will be skipped. export CLOUDERY_TOKEN=$(pass show cozy/e2e-front/manager-token | head -n 1)", "title": "E2E flow"}, {"location": "ach/examples/data-from-csv/", "text": "Import data from CSV files \u00b6 ACH does not support the import of CSV directly. You need to transform the data into the JSON format understood by ACH You can use ACH to import your data Here the example is from a banking data perspective. Say you banking institutions has provided you data in CSV and you want to import it in your Cozy to see the data in Banks. accounts.csv : contains data on your banking accounts operations.csv : contains data on your banking operations You can look at the parser to see how we transform the CSV data contained in accounts.csv and operations.csv into a format understandable by ACH. THe parser is basic here, the main point of attention here is the reference helper being used to link operations to accounts after accounts have been inserted into the Cozy. \u26a0\ufe0f The parser is very barebone and is just intended as an example. Parsing CSV is much harder than what it seems . You\u2019d be better of with a real CSV parsing library. \u26a0\ufe0f There are many other attributes that can be put on accounts and operations. You can see the docs on operations for more documentation. Usage \u00b6 node parser . js accounts . csv operations . csv > banking - data . json ach import banking - data . json", "title": "Import data from CSV files"}, {"location": "ach/examples/data-from-csv/#import-data-from-csv-files", "text": "ACH does not support the import of CSV directly. You need to transform the data into the JSON format understood by ACH You can use ACH to import your data Here the example is from a banking data perspective. Say you banking institutions has provided you data in CSV and you want to import it in your Cozy to see the data in Banks. accounts.csv : contains data on your banking accounts operations.csv : contains data on your banking operations You can look at the parser to see how we transform the CSV data contained in accounts.csv and operations.csv into a format understandable by ACH. THe parser is basic here, the main point of attention here is the reference helper being used to link operations to accounts after accounts have been inserted into the Cozy. \u26a0\ufe0f The parser is very barebone and is just intended as an example. Parsing CSV is much harder than what it seems . You\u2019d be better of with a real CSV parsing library. \u26a0\ufe0f There are many other attributes that can be put on accounts and operations. You can see the docs on operations for more documentation.", "title": "Import data from CSV files"}, {"location": "ach/examples/data-from-csv/#usage", "text": "node parser . js accounts . csv operations . csv > banking - data . json ach import banking - data . json", "title": "Usage"}, {"location": "babel-preset-cozy-app/", "text": "Babel Preset Cozy App What\u2019s babel-preset-cozy-app? \u00b6 A shareable configuration for Cozy Applications or Scripts. This package is a Babel preset already used by create-cozy-app . To install: yarn add --dev babel-preset-cozy-app Usage with a Create Cozy App projects \u00b6 If you started your project using create-cozy-app , you don\u2019t need to do anything, you should already have a .babelrc configured to used this preset. Usage with other projects \u00b6 If you want to use this preset, you first need to have Babel installed (cf documentation ). Then, in a file named .babelrc (the Babel configuration file), you can use the preset using the following way: { \"presets\" : [ \"cozy-app\" ] } Options \u00b6 node (boolean): false by default \u00b6 By default, this babel preset targets browsers but you can target node by using the node option: { \"presets\" : [ [ \"cozy-app\" , { \"node\" : true }] ] } react (boolean): true by default \u00b6 By default, this babel preset uses the react preset ( babel-preset-react ) but you can disable this behaviour with the react option to false as following: { \"presets\" : [ [ \"cozy-app\" , { \"react\" : false }] ] } transformRegenerator (boolean): true by default (for browsers only) \u00b6 By default, this babel preset uses babel-plugin-transform-runtime to transform regenerator functions on the runtime. But sometimes (not always) it could break CSPs due to some eval usage so you can disable this behaviour with the transformRegenerator option to false as following: { \"presets\" : [ [ \"cozy-app\" , { \"transformRegenerator\" : false }] ] } Lib option \u00b6 When the lib option is activated, import/export nodes are not transpiled. This gives the downstream bundler the ability to prune unused module away. It works by configuring babel-preset-env with {\"modules\": false} . Advanced \u00b6 You can have control on the options passed to babel-preset-env and babel-plugin-transform-runtime : presetEnv will be passed to babel-preset-env transformRuntime will be passed to babel-plugin-transform-runtime { \"presets\" : [ [ \"cozy-app\" , { \"presetEnv\" : { \"modules\" : false }, \"transformRuntime\" : { \"helpers\" : true } }] ] } In this case, we do not want preset-env to touch to import/export and want the inlined Babel helpers to be replaced by imports from babel-runtime . See the options on the official docs : https://babeljs.io/docs/en/babel-preset-env#modules https://babeljs.io/docs/en/babel-plugin-transform-runtime#helpers Community \u00b6 What\u2019s Cozy? \u00b6 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\u2019s tracking you. Get in touch \u00b6 You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter License \u00b6 babel-preset-cozy-app is distributed under the MIT license.", "title": "Babel preset"}, {"location": "babel-preset-cozy-app/#whats-babel-preset-cozy-app", "text": "A shareable configuration for Cozy Applications or Scripts. This package is a Babel preset already used by create-cozy-app . To install: yarn add --dev babel-preset-cozy-app", "title": "What's babel-preset-cozy-app?"}, {"location": "babel-preset-cozy-app/#usage-with-a-create-cozy-app-projects", "text": "If you started your project using create-cozy-app , you don\u2019t need to do anything, you should already have a .babelrc configured to used this preset.", "title": "Usage with a Create Cozy App projects"}, {"location": "babel-preset-cozy-app/#usage-with-other-projects", "text": "If you want to use this preset, you first need to have Babel installed (cf documentation ). Then, in a file named .babelrc (the Babel configuration file), you can use the preset using the following way: { \"presets\" : [ \"cozy-app\" ] }", "title": "Usage with other projects"}, {"location": "babel-preset-cozy-app/#options", "text": "", "title": "Options"}, {"location": "babel-preset-cozy-app/#node-boolean-false-by-default", "text": "By default, this babel preset targets browsers but you can target node by using the node option: { \"presets\" : [ [ \"cozy-app\" , { \"node\" : true }] ] }", "title": "node (boolean): false by default"}, {"location": "babel-preset-cozy-app/#react-boolean-true-by-default", "text": "By default, this babel preset uses the react preset ( babel-preset-react ) but you can disable this behaviour with the react option to false as following: { \"presets\" : [ [ \"cozy-app\" , { \"react\" : false }] ] }", "title": "react (boolean): true by default"}, {"location": "babel-preset-cozy-app/#transformregenerator-boolean-true-by-default-for-browsers-only", "text": "By default, this babel preset uses babel-plugin-transform-runtime to transform regenerator functions on the runtime. But sometimes (not always) it could break CSPs due to some eval usage so you can disable this behaviour with the transformRegenerator option to false as following: { \"presets\" : [ [ \"cozy-app\" , { \"transformRegenerator\" : false }] ] }", "title": "transformRegenerator (boolean): true by default (for browsers only)"}, {"location": "babel-preset-cozy-app/#lib-option", "text": "When the lib option is activated, import/export nodes are not transpiled. This gives the downstream bundler the ability to prune unused module away. It works by configuring babel-preset-env with {\"modules\": false} .", "title": "Lib option"}, {"location": "babel-preset-cozy-app/#advanced", "text": "You can have control on the options passed to babel-preset-env and babel-plugin-transform-runtime : presetEnv will be passed to babel-preset-env transformRuntime will be passed to babel-plugin-transform-runtime { \"presets\" : [ [ \"cozy-app\" , { \"presetEnv\" : { \"modules\" : false }, \"transformRuntime\" : { \"helpers\" : true } }] ] } In this case, we do not want preset-env to touch to import/export and want the inlined Babel helpers to be replaced by imports from babel-runtime . See the options on the official docs : https://babeljs.io/docs/en/babel-preset-env#modules https://babeljs.io/docs/en/babel-plugin-transform-runtime#helpers", "title": "Advanced"}, {"location": "babel-preset-cozy-app/#community", "text": "", "title": "Community"}, {"location": "babel-preset-cozy-app/#whats-cozy", "text": "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\u2019s tracking you.", "title": "What's Cozy?"}, {"location": "babel-preset-cozy-app/#get-in-touch", "text": "You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter", "title": "Get in touch"}, {"location": "babel-preset-cozy-app/#license", "text": "babel-preset-cozy-app is distributed under the MIT license.", "title": "License"}, {"location": "babel-preset-cozy-app/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 2.1.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 2.0.4 (2022-10-03) \u00b6 Note: Version bump only for package babel-preset-cozy-app 2.0.3 (2022-08-01) \u00b6 Bug Fixes \u00b6 node: Upgrade to Node 16 ( 3a82521 ) 2.0.2 (2022-02-01) \u00b6 Bug Fixes \u00b6 deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 ) 2.0.1 (2021-12-20) \u00b6 Bug Fixes \u00b6 Downgrade babel-core in babel-preset ( 5456544 ) 2.0.0 (2021-12-02) \u00b6 Features \u00b6 Handle Typescript files in eslint and babel configs ( fe658ed ) BREAKING CHANGES \u00b6 upgrade from eslint 5 to eslint 8 upgrade prettier from 1 to 2 you\u2019ll need to run \u2013fix to fix lint issues after the upgrade. Few errors are not auto fixable, you can // disable-next-line if needed 1.12.0 (2021-10-22) \u00b6 Features \u00b6 Remove drive from homeHref ( 97010d3 ) Update preset config to target node 12 ( bae1bcd ) 1.11.0 (2021-02-12) \u00b6 Features \u00b6 Add finance theme ( bb8cf35 ) 1.10.0 (2020-11-23) \u00b6 Features \u00b6 Update babel-preset-cozy-app dependencies ( 0fcccb5 ) Use ^ for dependencies ( fc28de7 ) 1.9.3 (2020-10-01) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.9.2 (2020-09-15) \u00b6 Bug Fixes \u00b6 Flaky builds due to SyntaxError ( 6b86b76 ) 1.9.1 (2020-08-03) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.9.0 (2020-07-16) \u00b6 Bug Fixes \u00b6 Call revokeSelf if not the owner of the sharing ( f7afc60 ) Features \u00b6 Update lodash accross all packages ( 6a20128 ) 1.8.1 (2020-02-27) \u00b6 Bug Fixes \u00b6 Revert \u201cMerge pull request #974 from cozy/feat/RemovePropTypes\u201d ( 2d15d78 ) 1.8.0 (2020-02-25) \u00b6 Bug Fixes \u00b6 cozy-harvest-lib: Always show account form when editing an account ( a8718cd ) Features \u00b6 Remove proptype in production mode ( 4287527 ) 1.7.0 (2019-09-05) \u00b6 Features \u00b6 Add account route ( 7986708 ) 1.6.0 (2019-07-19) \u00b6 Features \u00b6 Activate babel helpers by default ( ab62bdb ) Add lib option ( 45469b5 ) Do not let lib add modules:false in Jest ( ee4058c ) 1.5.3 (2019-07-19) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.5.2 (2019-07-11) \u00b6 Bug Fixes \u00b6 deps: Update dependency lodash to v4.17.13 [SECURITY] ( #648 ) ( 1b36dac ) 1.5.1 (2019-03-18) \u00b6 Bug Fixes \u00b6 babel-preset-cozy-app: Publish validate.js file ( b3c4c5e ) 1.5.0 (2019-03-12) \u00b6 Features \u00b6 Disable a transform that makes React slower ( 035bb4f ) 1.4.0 (2019-03-12) \u00b6 Features \u00b6 Ability to configure transformRegenerator ( 8f928c3 ) Add presetEnv option ( dbd7e49 ) Can disable transformRuntime plugin ( 37ee490 ) Check result when running in CLI ( 791a005 ) Deprecated transformRegenerator option ( 011299f ) 1.3.3 (2019-03-12) \u00b6 Bug Fixes \u00b6 deps: update babel monorepo ( 099cc51 ) 1.3.2 (2019-02-12) \u00b6 Bug Fixes \u00b6 Make babel-preset uses browserslist cozy config ( 3418ac2 ) 1.3.1 (2019-02-11) \u00b6 Bug Fixes \u00b6 Add Android 5 and iOS 10 ( #266 ) ( 1677d25 ) 1.3.0 (2019-01-11) \u00b6 Features \u00b6 babel: Update supported browsers list for Cozy platform ( 8e810e1 ) 1.2.5 (2018-12-28) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.2.4 (2018-12-26) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.2.3 (2018-12-17) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.2.2 (2018-12-10) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.2.1 (2018-10-02) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.2.0 (2018-09-25) \u00b6 Bug Fixes \u00b6 \ud83d\udd27 add required @babel /core v7 in cozy-app ( cbce625 ) \ud83d\udd27 remove now deprecated polyfill option ( 63ec309 ) Features \u00b6 \ud83d\udd27 make cozy-app babel 7 compatible ( c2c5a5e ) 1.1.3 (2018-09-21) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.1.2 (2018-09-21) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.1.1 (2018-08-22) \u00b6 Note: Version bump only for package babel-preset-cozy-app 1.1.0 (2018-08-09) \u00b6 Features \u00b6 import babel and eslint cozy-app from create-cozy-app ( 0a3ab19 )", "title": "Change Log"}, {"location": "babel-preset-cozy-app/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "babel-preset-cozy-app/CHANGELOG/#210-2023-01-31", "text": "", "title": "2.1.0 (2023-01-31)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#204-2022-10-03", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "2.0.4 (2022-10-03)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#203-2022-08-01", "text": "", "title": "2.0.3 (2022-08-01)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes", "text": "node: Upgrade to Node 16 ( 3a82521 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#202-2022-02-01", "text": "", "title": "2.0.2 (2022-02-01)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_1", "text": "deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#201-2021-12-20", "text": "", "title": "2.0.1 (2021-12-20)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_2", "text": "Downgrade babel-core in babel-preset ( 5456544 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#200-2021-12-02", "text": "", "title": "2.0.0 (2021-12-02)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_1", "text": "Handle Typescript files in eslint and babel configs ( fe658ed )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#breaking-changes", "text": "upgrade from eslint 5 to eslint 8 upgrade prettier from 1 to 2 you\u2019ll need to run \u2013fix to fix lint issues after the upgrade. Few errors are not auto fixable, you can // disable-next-line if needed", "title": "BREAKING CHANGES"}, {"location": "babel-preset-cozy-app/CHANGELOG/#1120-2021-10-22", "text": "", "title": "1.12.0 (2021-10-22)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_2", "text": "Remove drive from homeHref ( 97010d3 ) Update preset config to target node 12 ( bae1bcd )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#1110-2021-02-12", "text": "", "title": "1.11.0 (2021-02-12)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_3", "text": "Add finance theme ( bb8cf35 )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#1100-2020-11-23", "text": "", "title": "1.10.0 (2020-11-23)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_4", "text": "Update babel-preset-cozy-app dependencies ( 0fcccb5 ) Use ^ for dependencies ( fc28de7 )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#193-2020-10-01", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.9.3 (2020-10-01)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#192-2020-09-15", "text": "", "title": "1.9.2 (2020-09-15)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_3", "text": "Flaky builds due to SyntaxError ( 6b86b76 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#191-2020-08-03", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.9.1 (2020-08-03)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#190-2020-07-16", "text": "", "title": "1.9.0 (2020-07-16)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_4", "text": "Call revokeSelf if not the owner of the sharing ( f7afc60 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_5", "text": "Update lodash accross all packages ( 6a20128 )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#181-2020-02-27", "text": "", "title": "1.8.1 (2020-02-27)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_5", "text": "Revert \u201cMerge pull request #974 from cozy/feat/RemovePropTypes\u201d ( 2d15d78 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#180-2020-02-25", "text": "", "title": "1.8.0 (2020-02-25)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_6", "text": "cozy-harvest-lib: Always show account form when editing an account ( a8718cd )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_6", "text": "Remove proptype in production mode ( 4287527 )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#170-2019-09-05", "text": "", "title": "1.7.0 (2019-09-05)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_7", "text": "Add account route ( 7986708 )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#160-2019-07-19", "text": "", "title": "1.6.0 (2019-07-19)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_8", "text": "Activate babel helpers by default ( ab62bdb ) Add lib option ( 45469b5 ) Do not let lib add modules:false in Jest ( ee4058c )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#153-2019-07-19", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.5.3 (2019-07-19)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#152-2019-07-11", "text": "", "title": "1.5.2 (2019-07-11)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_7", "text": "deps: Update dependency lodash to v4.17.13 [SECURITY] ( #648 ) ( 1b36dac )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#151-2019-03-18", "text": "", "title": "1.5.1 (2019-03-18)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_8", "text": "babel-preset-cozy-app: Publish validate.js file ( b3c4c5e )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#150-2019-03-12", "text": "", "title": "1.5.0 (2019-03-12)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_9", "text": "Disable a transform that makes React slower ( 035bb4f )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#140-2019-03-12", "text": "", "title": "1.4.0 (2019-03-12)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_10", "text": "Ability to configure transformRegenerator ( 8f928c3 ) Add presetEnv option ( dbd7e49 ) Can disable transformRuntime plugin ( 37ee490 ) Check result when running in CLI ( 791a005 ) Deprecated transformRegenerator option ( 011299f )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#133-2019-03-12", "text": "", "title": "1.3.3 (2019-03-12)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_9", "text": "deps: update babel monorepo ( 099cc51 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#132-2019-02-12", "text": "", "title": "1.3.2 (2019-02-12)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_10", "text": "Make babel-preset uses browserslist cozy config ( 3418ac2 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#131-2019-02-11", "text": "", "title": "1.3.1 (2019-02-11)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_11", "text": "Add Android 5 and iOS 10 ( #266 ) ( 1677d25 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#130-2019-01-11", "text": "", "title": "1.3.0 (2019-01-11)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_11", "text": "babel: Update supported browsers list for Cozy platform ( 8e810e1 )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#125-2018-12-28", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.2.5 (2018-12-28)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#124-2018-12-26", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.2.4 (2018-12-26)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#123-2018-12-17", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.2.3 (2018-12-17)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#122-2018-12-10", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.2.2 (2018-12-10)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#121-2018-10-02", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.2.1 (2018-10-02)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#120-2018-09-25", "text": "", "title": "1.2.0 (2018-09-25)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#bug-fixes_12", "text": "\ud83d\udd27 add required @babel /core v7 in cozy-app ( cbce625 ) \ud83d\udd27 remove now deprecated polyfill option ( 63ec309 )", "title": "Bug Fixes"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_12", "text": "\ud83d\udd27 make cozy-app babel 7 compatible ( c2c5a5e )", "title": "Features"}, {"location": "babel-preset-cozy-app/CHANGELOG/#113-2018-09-21", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.1.3 (2018-09-21)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#112-2018-09-21", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.1.2 (2018-09-21)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#111-2018-08-22", "text": "Note: Version bump only for package babel-preset-cozy-app", "title": "1.1.1 (2018-08-22)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#110-2018-08-09", "text": "", "title": "1.1.0 (2018-08-09)"}, {"location": "babel-preset-cozy-app/CHANGELOG/#features_13", "text": "import babel and eslint cozy-app from create-cozy-app ( 0a3ab19 )", "title": "Features"}, {"location": "commitlint-config-cozy/", "text": "Commitlint Config Cozy \u00b6 Shareable commitlint config enforcing the cozy commit convention Documentations \u00b6 Cozy commit documentation on Cozy Guideline Commitlint How to add it on your project \u00b6 Add the library on your dev dependency ( yarn add commitlint-config-cozy --dev --exact ) Add configuration on your package.json ( see an example ): \"commitlint\" : { \"extends\" : [ \"cozy\" ] } Add verification during a commit with husky (> 1.0.0) on your package.json ( see an example ): \"husky\": { \"hooks\": { \"commit-msg\": \"commitlint -e $GIT_PARAMS\" } } Community \u00b6 What\u2019s Cozy? \u00b6 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\u2019s tracking you. Get in touch \u00b6 You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter Maintainers \u00b6 The maintainer for Commitlint Config Cozy is kosssi ! License \u00b6 commitlint-config-cozy is distributed under the MIT license.", "title": "Commitlint"}, {"location": "commitlint-config-cozy/#commitlint-config-cozy", "text": "Shareable commitlint config enforcing the cozy commit convention", "title": "Commitlint Config Cozy"}, {"location": "commitlint-config-cozy/#documentations", "text": "Cozy commit documentation on Cozy Guideline Commitlint", "title": "Documentations"}, {"location": "commitlint-config-cozy/#how-to-add-it-on-your-project", "text": "Add the library on your dev dependency ( yarn add commitlint-config-cozy --dev --exact ) Add configuration on your package.json ( see an example ): \"commitlint\" : { \"extends\" : [ \"cozy\" ] } Add verification during a commit with husky (> 1.0.0) on your package.json ( see an example ): \"husky\": { \"hooks\": { \"commit-msg\": \"commitlint -e $GIT_PARAMS\" } }", "title": "How to add it on your project"}, {"location": "commitlint-config-cozy/#community", "text": "", "title": "Community"}, {"location": "commitlint-config-cozy/#whats-cozy", "text": "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\u2019s tracking you.", "title": "What's Cozy?"}, {"location": "commitlint-config-cozy/#get-in-touch", "text": "You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter", "title": "Get in touch"}, {"location": "commitlint-config-cozy/#maintainers", "text": "The maintainer for Commitlint Config Cozy is kosssi !", "title": "Maintainers"}, {"location": "commitlint-config-cozy/#license", "text": "commitlint-config-cozy is distributed under the MIT license.", "title": "License"}, {"location": "commitlint-config-cozy/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 0.8.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 0.7.9 (2022-10-03) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.7.8 (2022-08-01) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.7.7 (2022-05-13) \u00b6 Bug Fixes \u00b6 deps: update commitlint monorepo to v16.2.4 ( 6b17ecb ) 0.7.6 (2022-04-04) \u00b6 Bug Fixes \u00b6 bump @commitlint/cli from 16.1.0 to 16.2.3 ( 2167d5b ) 0.7.5 (2022-02-03) \u00b6 Bug Fixes \u00b6 deps: update dependency jest to v26.6.3 ( f442fff ) 0.7.4 (2022-02-01) \u00b6 Bug Fixes \u00b6 deps: update commitlint monorepo ( d3f4f27 ) 0.7.3 (2022-02-01) \u00b6 Bug Fixes \u00b6 deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 ) 0.7.2 (2021-12-20) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.7.1 (2021-12-02) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.7.0 (2021-10-22) \u00b6 Features \u00b6 Remove drive from homeHref ( 97010d3 ) 0.6.0 (2021-02-12) \u00b6 Features \u00b6 Add finance theme ( bb8cf35 ) 0.5.0 (2020-11-23) \u00b6 Features \u00b6 Update @babel/core and babel-jest ( 352ddc3 ) Update jest ( 3b2c32a ) 0.4.6 (2020-10-01) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.4.5 (2020-09-15) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.4.4 (2020-08-03) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.4.3 (2020-07-16) \u00b6 Bug Fixes \u00b6 Call revokeSelf if not the owner of the sharing ( f7afc60 ) 0.4.2 (2020-02-27) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.4.1 (2020-02-25) \u00b6 Bug Fixes \u00b6 cozy-harvest-lib: Always show account form when editing an account ( a8718cd ) 0.4.0 (2019-09-05) \u00b6 Features \u00b6 Add account route ( 7986708 ) 0.3.27 (2019-07-19) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.26 (2019-07-19) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.25 (2019-07-11) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.24 (2019-03-18) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.23 (2019-03-12) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.22 (2019-03-12) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.21 (2019-03-12) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.20 (2019-03-12) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.19 (2019-02-25) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.18 (2019-02-12) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.17 (2019-02-11) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.16 (2019-01-16) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.15 (2019-01-11) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.14 (2018-12-28) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.13 (2018-12-26) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.12 (2018-12-17) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.11 (2018-12-10) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.10 (2018-11-29) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.9 (2018-10-16) \u00b6 Bug Fixes \u00b6 deps: update commitlint monorepo to v7.2.1 ( 0ee263a ) 0.3.8 (2018-10-11) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.7 (2018-10-09) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.6 (2018-10-02) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.5 (2018-09-27) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.4 (2018-09-25) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.3 (2018-09-25) \u00b6 Bug Fixes \u00b6 add babel-core bridge for v7 ( 18665a8 ), closes /github.com/babel/babel/issues/8206#issuecomment-419705758 use ^7.1.0 for babel-jest issue ( 34b2d14 ) 0.3.2 (2018-09-25) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.1 (2018-09-21) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.3.0 (2018-09-17) \u00b6 Features \u00b6 Add commitlint cli on dependency \u2699\ufe0f ( 8a5652d ) Add limitation on body \ud83d\udccf ( dc33f61 ) 0.2.4 (2018-08-30) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.2.3 (2018-08-22) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.2.2 (2018-08-10) \u00b6 Bug Fixes \u00b6 Commitlint extend should start with @ \ud83d\ude22 ( dc9489f ), closes 40commitlint/resolve-extends/src/index.js#L71 Remove 72 chars limit on body description \ud83d\udd25 ( 5d1edd8 ) 0.2.1 (2018-08-09) \u00b6 Note: Version bump only for package commitlint-config-cozy 0.2.0 (2018-08-09) \u00b6 Features \u00b6 add commitlint-config-cozy package \ud83d\udccf ( b6c7c0e )", "title": "Change Log"}, {"location": "commitlint-config-cozy/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "commitlint-config-cozy/CHANGELOG/#080-2023-01-31", "text": "", "title": "0.8.0 (2023-01-31)"}, {"location": "commitlint-config-cozy/CHANGELOG/#features", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "commitlint-config-cozy/CHANGELOG/#079-2022-10-03", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.7.9 (2022-10-03)"}, {"location": "commitlint-config-cozy/CHANGELOG/#078-2022-08-01", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.7.8 (2022-08-01)"}, {"location": "commitlint-config-cozy/CHANGELOG/#077-2022-05-13", "text": "", "title": "0.7.7 (2022-05-13)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes", "text": "deps: update commitlint monorepo to v16.2.4 ( 6b17ecb )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#076-2022-04-04", "text": "", "title": "0.7.6 (2022-04-04)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_1", "text": "bump @commitlint/cli from 16.1.0 to 16.2.3 ( 2167d5b )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#075-2022-02-03", "text": "", "title": "0.7.5 (2022-02-03)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_2", "text": "deps: update dependency jest to v26.6.3 ( f442fff )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#074-2022-02-01", "text": "", "title": "0.7.4 (2022-02-01)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_3", "text": "deps: update commitlint monorepo ( d3f4f27 )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#073-2022-02-01", "text": "", "title": "0.7.3 (2022-02-01)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_4", "text": "deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#072-2021-12-20", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.7.2 (2021-12-20)"}, {"location": "commitlint-config-cozy/CHANGELOG/#071-2021-12-02", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.7.1 (2021-12-02)"}, {"location": "commitlint-config-cozy/CHANGELOG/#070-2021-10-22", "text": "", "title": "0.7.0 (2021-10-22)"}, {"location": "commitlint-config-cozy/CHANGELOG/#features_1", "text": "Remove drive from homeHref ( 97010d3 )", "title": "Features"}, {"location": "commitlint-config-cozy/CHANGELOG/#060-2021-02-12", "text": "", "title": "0.6.0 (2021-02-12)"}, {"location": "commitlint-config-cozy/CHANGELOG/#features_2", "text": "Add finance theme ( bb8cf35 )", "title": "Features"}, {"location": "commitlint-config-cozy/CHANGELOG/#050-2020-11-23", "text": "", "title": "0.5.0 (2020-11-23)"}, {"location": "commitlint-config-cozy/CHANGELOG/#features_3", "text": "Update @babel/core and babel-jest ( 352ddc3 ) Update jest ( 3b2c32a )", "title": "Features"}, {"location": "commitlint-config-cozy/CHANGELOG/#046-2020-10-01", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.4.6 (2020-10-01)"}, {"location": "commitlint-config-cozy/CHANGELOG/#045-2020-09-15", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.4.5 (2020-09-15)"}, {"location": "commitlint-config-cozy/CHANGELOG/#044-2020-08-03", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.4.4 (2020-08-03)"}, {"location": "commitlint-config-cozy/CHANGELOG/#043-2020-07-16", "text": "", "title": "0.4.3 (2020-07-16)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_5", "text": "Call revokeSelf if not the owner of the sharing ( f7afc60 )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#042-2020-02-27", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.4.2 (2020-02-27)"}, {"location": "commitlint-config-cozy/CHANGELOG/#041-2020-02-25", "text": "", "title": "0.4.1 (2020-02-25)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_6", "text": "cozy-harvest-lib: Always show account form when editing an account ( a8718cd )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#040-2019-09-05", "text": "", "title": "0.4.0 (2019-09-05)"}, {"location": "commitlint-config-cozy/CHANGELOG/#features_4", "text": "Add account route ( 7986708 )", "title": "Features"}, {"location": "commitlint-config-cozy/CHANGELOG/#0327-2019-07-19", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.27 (2019-07-19)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0326-2019-07-19", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.26 (2019-07-19)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0325-2019-07-11", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.25 (2019-07-11)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0324-2019-03-18", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.24 (2019-03-18)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0323-2019-03-12", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.23 (2019-03-12)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0322-2019-03-12", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.22 (2019-03-12)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0321-2019-03-12", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.21 (2019-03-12)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0320-2019-03-12", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.20 (2019-03-12)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0319-2019-02-25", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.19 (2019-02-25)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0318-2019-02-12", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.18 (2019-02-12)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0317-2019-02-11", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.17 (2019-02-11)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0316-2019-01-16", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.16 (2019-01-16)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0315-2019-01-11", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.15 (2019-01-11)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0314-2018-12-28", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.14 (2018-12-28)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0313-2018-12-26", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.13 (2018-12-26)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0312-2018-12-17", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.12 (2018-12-17)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0311-2018-12-10", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.11 (2018-12-10)"}, {"location": "commitlint-config-cozy/CHANGELOG/#0310-2018-11-29", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.10 (2018-11-29)"}, {"location": "commitlint-config-cozy/CHANGELOG/#039-2018-10-16", "text": "", "title": "0.3.9 (2018-10-16)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_7", "text": "deps: update commitlint monorepo to v7.2.1 ( 0ee263a )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#038-2018-10-11", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.8 (2018-10-11)"}, {"location": "commitlint-config-cozy/CHANGELOG/#037-2018-10-09", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.7 (2018-10-09)"}, {"location": "commitlint-config-cozy/CHANGELOG/#036-2018-10-02", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.6 (2018-10-02)"}, {"location": "commitlint-config-cozy/CHANGELOG/#035-2018-09-27", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.5 (2018-09-27)"}, {"location": "commitlint-config-cozy/CHANGELOG/#034-2018-09-25", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.4 (2018-09-25)"}, {"location": "commitlint-config-cozy/CHANGELOG/#033-2018-09-25", "text": "", "title": "0.3.3 (2018-09-25)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_8", "text": "add babel-core bridge for v7 ( 18665a8 ), closes /github.com/babel/babel/issues/8206#issuecomment-419705758 use ^7.1.0 for babel-jest issue ( 34b2d14 )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#032-2018-09-25", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.2 (2018-09-25)"}, {"location": "commitlint-config-cozy/CHANGELOG/#031-2018-09-21", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.3.1 (2018-09-21)"}, {"location": "commitlint-config-cozy/CHANGELOG/#030-2018-09-17", "text": "", "title": "0.3.0 (2018-09-17)"}, {"location": "commitlint-config-cozy/CHANGELOG/#features_5", "text": "Add commitlint cli on dependency \u2699\ufe0f ( 8a5652d ) Add limitation on body \ud83d\udccf ( dc33f61 )", "title": "Features"}, {"location": "commitlint-config-cozy/CHANGELOG/#024-2018-08-30", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.2.4 (2018-08-30)"}, {"location": "commitlint-config-cozy/CHANGELOG/#023-2018-08-22", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.2.3 (2018-08-22)"}, {"location": "commitlint-config-cozy/CHANGELOG/#022-2018-08-10", "text": "", "title": "0.2.2 (2018-08-10)"}, {"location": "commitlint-config-cozy/CHANGELOG/#bug-fixes_9", "text": "Commitlint extend should start with @ \ud83d\ude22 ( dc9489f ), closes 40commitlint/resolve-extends/src/index.js#L71 Remove 72 chars limit on body description \ud83d\udd25 ( 5d1edd8 )", "title": "Bug Fixes"}, {"location": "commitlint-config-cozy/CHANGELOG/#021-2018-08-09", "text": "Note: Version bump only for package commitlint-config-cozy", "title": "0.2.1 (2018-08-09)"}, {"location": "commitlint-config-cozy/CHANGELOG/#020-2018-08-09", "text": "", "title": "0.2.0 (2018-08-09)"}, {"location": "commitlint-config-cozy/CHANGELOG/#features_6", "text": "add commitlint-config-cozy package \ud83d\udccf ( b6c7c0e )", "title": "Features"}, {"location": "cozy-app-publish/", "text": "Cozy App Publish \u00b6 What\u2019s cozy-app-publish? \u00b6 cozy-app-publish is a command line tool that publish a Cozy application to the Cozy registry according to some options. Requirements \u00b6 Node.js version 8 or higher; Install \u00b6 yarn add --dev cozy-app-publish Registry documentation \u00b6 You can find more information about the registry and how to prepare an application to be published in the official registry documentation . Usage via Travis CI (recommended) \u00b6 First of all, don\u2019t forget to build the application: # build the application (in the ./build folder here) yarn build Then, just publish it using the Travis CI workflow: # publish it, REGISTRY_TOKEN should be # encrypted and provided via Travis CI environment # BUILD_COMMIT is your last build commit hash (git rev-parse build) yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-commit $BUILD_COMMIT Published version is inferred from the tag set on current commit or the version defined in the manifest version property: If the current commit has no tag associated, then this is a dev version in the form -dev. If the current commit has a beta tag x.y.z-beta.n or a stable tag x.y.z , then this is a beta or stable version and the tag value is used as the version Manual usage (not recommended) \u00b6 First of all, don\u2019t forget to build the application: # build the application (in the ./build folder here) yarn build Then, just publish it using: yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2-dev.042cef26d9d33ea604fe4364eaab569980b500c9 Publishing a beta version \u00b6 Beta versions are only available through beta channel of the registry and are not automatically deployable on production instances. However a beta tester can force deployment of beta versions of a given (installed) app from Cozy store. Ask your Cozy representative to explain you how to do this. Let\u2019s say you plan to publish version 1.0.2 of your application and want to test it before publishing it to stable. Then you will publish a 1.0.2-beta.1 version, test it, publish other beta versions if some adjustement are needed and when you\u2019re satisfied with the version you will publish a stable version. To publish a beta version: Have the target stable version as the version in your manifest file (eg 1.0.2 in our example). The manifest file always reference stable version. Publish with cozy-app-publish using the beta version like 1.0.2-beta.1 yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2-beta.1 Publishing a stable version \u00b6 Instances auto-update app versions as soon as they are published as stable. Publishing a new stable version will make it available immediately to all instances (existing and new ones) unless permission changes requiring user\u2019s validation. To publish a stable version, simply use a version in the form x.y.z and it will be considered as stable. Because manifest\u2019s version doesn\u2019t need to be changed between beta and stable, you don\u2019t need to rebuild the application and can publish the exact same app package you built for beta publication yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2 Options \u00b6 --token (required) \u00b6 The registry editor token. This token must match the editor name and is provided by Cozy Cloud (with the name) in order to use the registry. --build-dir \u00b6 The path to the build folder, relative to the current directory. Since the \u2018standard\u2019 Cozy application builds in the build/ folder, build is the default value. This folder is mainly used to read the application manifest during publishing. --build-url \u00b6 For now, the registry a build archive (.tar.gz file) from an external link to be used in the cozy-stack. In the travis script, this url is computed using the Github trick to get archives from a commit url (but it\u2019s overwritten if provided by this option). For the manual script, we have to provide it. --build-commit \u00b6 Using the travis mode, the archive tarball URL is computed using github and the build commit hash. If you are not on your build branch to publish, you can specify the correct build commit hash using this parameter. --manual-version (required for manual usage only) \u00b6 In the manual mode, we don\u2019t have a way to compute the version like in the Travis mode for example. So we have to provide it using this option. --prepublish \u00b6 Specify custom prepublish hook to manage how the app archive is generated and uploaded. The script must export a asynchronous function which has the following signature: module . exports = async ({ appBuildUrl , appSlug , appType , appVersion , buildCommit , registryUrl , registryEditor , registryToken , spaceName }) => { // ... } This function must return an object containing the same options given as parameter, which can have been updated. For example, you may specifiy a new appBuildUrl in the hook. Here\u2019s a description of the different options: Options Description appBuildUrl The url where the build can be retrieved. For example, http://github.com/cozy/cozy-foo/archives/cozy-foo.tar.gz appSlug The slug of the application, as defined in the manifest. Should not be mutated appType webapp or konnector appVersion App version, as defined in the manifest. Should not be mutated. buildCommit sha of the commit, should not be mutated. registryUrl URL of the Cozy registry, should not be mutated. registryEditor Editor as it appears in the Cozy registry. registryToken Registry Token. See registry documentation . Should not be mutated. spaceName Space name in the Cozy registry. --postpublish \u00b6 Works exactly like the prepublish option, but will be executed after the publication. Multiple hooks and built-in hooks \u00b6 You can specify more than one hook by separating them with a , : cozy-app-publish --prepublish , Some hooks are shipped with cozy-app-publish and can be used by specifying their name: cozy-app-publish --prepublish Downcloud prepublish hook \u00b6 cozy-app-publish --prepublish downcloud This hook allows to upload the app to our downcloud server and sets the appBuildUrl accordingly. In order to upload files to our downcloud server, you will need to generate a new pair of RSA keys, add the private key to your ssh-agent and make sure the corresponding public key is present on the downcloud server. Here\u2019s how to do it: Generate a new key pair with ssh-keygen -t rsa -b 4096 -f id_rsa_downcloud_myapp -C downcloud_myapp_deploy . Communicate the public key to someone who can deposit it on the downcloud server. If you\u2019re running things locally, you\u2019ll want to run ssh-add id_rsa_downcloud_myapp to add it to your ssh-agent. If you\u2019re planing to run this cozy-app-publish on Travis, you\u2019ll want to encrypt that file first . Run travis encrypt-file id_rsa_downcloud_myapp and copy the output. This command also generates a id_rsa_downcloud_myapp.enc . To add the key to Travis\u2019s ssh-agent, add the following lines in the before_install section of your .travis.yml , but don\u2019t forget to paste the output of travis encrypt-file where it\u2019s needed. - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then PASTE_TRAVIS_ENCRYPT_OUTPUT_HERE; fi - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then eval \"$(ssh-agent -s)\"; fi - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then chmod 600 id_rsa_downcloud_myapp; fi - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then ssh-add id_rsa_downcloud_myapp; fi We recommend changing the path used for the private key. You can change the -out argument of the command output by travis encrypt-file and the corresponding path\u2019s in the commands above. /tmp/id_rsa_downcloud_myapp is a good place to store this key. You mays also change the -in argument of the same command, and change the path of the file id_rsa_downcloud_myapp.enc to whatever you want. We recomend using ./deploy/id_rsa_downcloud_myapp.enc (don\u2019t forget to move the file as well!). Finally, secure the private key . If you\u2019re using Travis, the key is now stored by Travis so you should delete your local copy. If you\u2019re running things on your machine, make sure the private key doesn\u2019t end up in version control. Mattermost postpublish hook \u00b6 cozy-app-publish --postpublish mattermost Sends a message to a mattermost channel to notify of the app\u2019s deployment. Requires the following options: MATTERMOST_HOOK_URL : You will need to set up a new Incoming Hook . MATTERMOST_CHANNEL : (optional) The name of the channel messages will be posted to or else the default channel of the hook will be used --registry-url \u00b6 The url of the registry, by default it will be https://staging-apps-registry.cozycloud.cc . --space \u00b6 Use this options to provide a specific space name of the registry to publish the application in. By default it will be published in the default space. --verbose \u00b6 To print more logs when using tool (useful for debug). Recommended workflow \u00b6 Day to day \u00b6 Development is done on feature branches that are merged into master , once they are complete. Every time someone commits on master , a new archive is created and uploaded on Downcloud and then published to Cozy Cloud registry. Release workflow \u00b6 A new release branch is created from the current state of master . Let\u2019s say we want to deploy version 1.0.0 of the app, we will create release/1.0.0 . Since we created a new branch, we have to bump the version of master , so we have to create a PR to bump to 1.1.0 everywhere it is necessary. This depends on the app, but most of the time it requires to change the package.json and manifest.webapp versions. The only type of commits allowed on this release branch are bug fixes, that should be made on the release branch. To release a stable or beta version, generally we use directly github and the release creation interface. In this interface, don\u2019t forget to fill in the changelog and to check \u201cprelease\u201d for a beta version. The title of the release must be the released version (ex.: 1.40.0-beta.1 ) Every time bugs are fixed and the version is considered for release, the latest commit is tagged with a prerelease version number, eg. 1.0.0-beta.1 , 1.0.0-beta.2 , etc\u2026 Each of these prereleases is automatically uploaded on downcloud and deployed on instances that are on the beta channel. Once the branch is deemed ready for release, the last commit is tagged with the final version \u2014 1.0.0 in our example. It is then, again, uploaded on downcloud, published on the registry and deployed on specific instances as needed. The release branch is merged back into master so that all the bugfixes aren\u2019t lost. Versions \u00b6 We apply the semver convention: If the release brings only bug fixes, then we should create a patch version. If the release brings at least one feature, then we should create a minor version. If the release changes its application\u2019s permissions, we should create a minor version even if this release is for bug fixes only. Hot Fix \u00b6 If you need to quickly fix a bug in production, then you have to: fetch the latest branch release create a new release branch from there (since this is a bug fix, this is a patch version) fix the bug Make a beta Publish Merge it on master Example: You have to hot fix Drive. The current stable version of Drive is : 1.45.0. Master is on 1.47.0. Then you need to fetch release/1.45.0 Create a branch from this release: git checkout -b release/1.45.1 git commit -m \u201cfix: Bug fix..\u201d git push git tag \u2026", "title": "Publish on the store (app-publish)"}, {"location": "cozy-app-publish/#cozy-app-publish", "text": "", "title": "Cozy App Publish"}, {"location": "cozy-app-publish/#whats-cozy-app-publish", "text": "cozy-app-publish is a command line tool that publish a Cozy application to the Cozy registry according to some options.", "title": "What's cozy-app-publish?"}, {"location": "cozy-app-publish/#requirements", "text": "Node.js version 8 or higher;", "title": "Requirements"}, {"location": "cozy-app-publish/#install", "text": "yarn add --dev cozy-app-publish", "title": "Install"}, {"location": "cozy-app-publish/#registry-documentation", "text": "You can find more information about the registry and how to prepare an application to be published in the official registry documentation .", "title": "Registry documentation"}, {"location": "cozy-app-publish/#usage-via-travis-ci-recommended", "text": "First of all, don\u2019t forget to build the application: # build the application (in the ./build folder here) yarn build Then, just publish it using the Travis CI workflow: # publish it, REGISTRY_TOKEN should be # encrypted and provided via Travis CI environment # BUILD_COMMIT is your last build commit hash (git rev-parse build) yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-commit $BUILD_COMMIT Published version is inferred from the tag set on current commit or the version defined in the manifest version property: If the current commit has no tag associated, then this is a dev version in the form -dev. If the current commit has a beta tag x.y.z-beta.n or a stable tag x.y.z , then this is a beta or stable version and the tag value is used as the version", "title": "Usage via Travis CI (recommended)"}, {"location": "cozy-app-publish/#manual-usage-not-recommended", "text": "First of all, don\u2019t forget to build the application: # build the application (in the ./build folder here) yarn build Then, just publish it using: yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2-dev.042cef26d9d33ea604fe4364eaab569980b500c9", "title": "Manual usage (not recommended)"}, {"location": "cozy-app-publish/#publishing-a-beta-version", "text": "Beta versions are only available through beta channel of the registry and are not automatically deployable on production instances. However a beta tester can force deployment of beta versions of a given (installed) app from Cozy store. Ask your Cozy representative to explain you how to do this. Let\u2019s say you plan to publish version 1.0.2 of your application and want to test it before publishing it to stable. Then you will publish a 1.0.2-beta.1 version, test it, publish other beta versions if some adjustement are needed and when you\u2019re satisfied with the version you will publish a stable version. To publish a beta version: Have the target stable version as the version in your manifest file (eg 1.0.2 in our example). The manifest file always reference stable version. Publish with cozy-app-publish using the beta version like 1.0.2-beta.1 yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2-beta.1", "title": "Publishing a beta version"}, {"location": "cozy-app-publish/#publishing-a-stable-version", "text": "Instances auto-update app versions as soon as they are published as stable. Publishing a new stable version will make it available immediately to all instances (existing and new ones) unless permission changes requiring user\u2019s validation. To publish a stable version, simply use a version in the form x.y.z and it will be considered as stable. Because manifest\u2019s version doesn\u2019t need to be changed between beta and stable, you don\u2019t need to rebuild the application and can publish the exact same app package you built for beta publication yarn cozy-app-publish \\ --token $REGISTRY_TOKEN \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2", "title": "Publishing a stable version"}, {"location": "cozy-app-publish/#options", "text": "", "title": "Options"}, {"location": "cozy-app-publish/#-token-lteditor-tokengt-required", "text": "The registry editor token. This token must match the editor name and is provided by Cozy Cloud (with the name) in order to use the registry.", "title": "--token &lt;editor-token&gt; (required)"}, {"location": "cozy-app-publish/#-build-dir-ltrelative-pathgt", "text": "The path to the build folder, relative to the current directory. Since the \u2018standard\u2019 Cozy application builds in the build/ folder, build is the default value. This folder is mainly used to read the application manifest during publishing.", "title": "--build-dir &lt;relative-path&gt;"}, {"location": "cozy-app-publish/#-build-url-lturlgt", "text": "For now, the registry a build archive (.tar.gz file) from an external link to be used in the cozy-stack. In the travis script, this url is computed using the Github trick to get archives from a commit url (but it\u2019s overwritten if provided by this option). For the manual script, we have to provide it.", "title": "--build-url &lt;url&gt;"}, {"location": "cozy-app-publish/#-build-commit-ltcommit-hashgt", "text": "Using the travis mode, the archive tarball URL is computed using github and the build commit hash. If you are not on your build branch to publish, you can specify the correct build commit hash using this parameter.", "title": "--build-commit &lt;commit-hash&gt;"}, {"location": "cozy-app-publish/#-manual-version-ltversiongt-required-for-manual-usage-only", "text": "In the manual mode, we don\u2019t have a way to compute the version like in the Travis mode for example. So we have to provide it using this option.", "title": "--manual-version &lt;version&gt; (required for manual usage only)"}, {"location": "cozy-app-publish/#-prepublish-ltscript_pathgt", "text": "Specify custom prepublish hook to manage how the app archive is generated and uploaded. The script must export a asynchronous function which has the following signature: module . exports = async ({ appBuildUrl , appSlug , appType , appVersion , buildCommit , registryUrl , registryEditor , registryToken , spaceName }) => { // ... } This function must return an object containing the same options given as parameter, which can have been updated. For example, you may specifiy a new appBuildUrl in the hook. Here\u2019s a description of the different options: Options Description appBuildUrl The url where the build can be retrieved. For example, http://github.com/cozy/cozy-foo/archives/cozy-foo.tar.gz appSlug The slug of the application, as defined in the manifest. Should not be mutated appType webapp or konnector appVersion App version, as defined in the manifest. Should not be mutated. buildCommit sha of the commit, should not be mutated. registryUrl URL of the Cozy registry, should not be mutated. registryEditor Editor as it appears in the Cozy registry. registryToken Registry Token. See registry documentation . Should not be mutated. spaceName Space name in the Cozy registry.", "title": "--prepublish &lt;script_path&gt;"}, {"location": "cozy-app-publish/#-postpublish-ltscript_pathgt", "text": "Works exactly like the prepublish option, but will be executed after the publication.", "title": "--postpublish &lt;script_path&gt;"}, {"location": "cozy-app-publish/#multiple-hooks-and-built-in-hooks", "text": "You can specify more than one hook by separating them with a , : cozy-app-publish --prepublish , Some hooks are shipped with cozy-app-publish and can be used by specifying their name: cozy-app-publish --prepublish ", "title": "Multiple hooks and built-in hooks"}, {"location": "cozy-app-publish/#downcloud-prepublish-hook", "text": "cozy-app-publish --prepublish downcloud This hook allows to upload the app to our downcloud server and sets the appBuildUrl accordingly. In order to upload files to our downcloud server, you will need to generate a new pair of RSA keys, add the private key to your ssh-agent and make sure the corresponding public key is present on the downcloud server. Here\u2019s how to do it: Generate a new key pair with ssh-keygen -t rsa -b 4096 -f id_rsa_downcloud_myapp -C downcloud_myapp_deploy . Communicate the public key to someone who can deposit it on the downcloud server. If you\u2019re running things locally, you\u2019ll want to run ssh-add id_rsa_downcloud_myapp to add it to your ssh-agent. If you\u2019re planing to run this cozy-app-publish on Travis, you\u2019ll want to encrypt that file first . Run travis encrypt-file id_rsa_downcloud_myapp and copy the output. This command also generates a id_rsa_downcloud_myapp.enc . To add the key to Travis\u2019s ssh-agent, add the following lines in the before_install section of your .travis.yml , but don\u2019t forget to paste the output of travis encrypt-file where it\u2019s needed. - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then PASTE_TRAVIS_ENCRYPT_OUTPUT_HERE; fi - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then eval \"$(ssh-agent -s)\"; fi - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then chmod 600 id_rsa_downcloud_myapp; fi - if [ \"$TRAVIS_SECURE_ENV_VARS\" != \"false\" ]; then ssh-add id_rsa_downcloud_myapp; fi We recommend changing the path used for the private key. You can change the -out argument of the command output by travis encrypt-file and the corresponding path\u2019s in the commands above. /tmp/id_rsa_downcloud_myapp is a good place to store this key. You mays also change the -in argument of the same command, and change the path of the file id_rsa_downcloud_myapp.enc to whatever you want. We recomend using ./deploy/id_rsa_downcloud_myapp.enc (don\u2019t forget to move the file as well!). Finally, secure the private key . If you\u2019re using Travis, the key is now stored by Travis so you should delete your local copy. If you\u2019re running things on your machine, make sure the private key doesn\u2019t end up in version control.", "title": "Downcloud prepublish hook"}, {"location": "cozy-app-publish/#mattermost-postpublish-hook", "text": "cozy-app-publish --postpublish mattermost Sends a message to a mattermost channel to notify of the app\u2019s deployment. Requires the following options: MATTERMOST_HOOK_URL : You will need to set up a new Incoming Hook . MATTERMOST_CHANNEL : (optional) The name of the channel messages will be posted to or else the default channel of the hook will be used", "title": "Mattermost postpublish hook"}, {"location": "cozy-app-publish/#-registry-url-lturlgt", "text": "The url of the registry, by default it will be https://staging-apps-registry.cozycloud.cc .", "title": "--registry-url &lt;url&gt;"}, {"location": "cozy-app-publish/#-space-ltspace-namegt", "text": "Use this options to provide a specific space name of the registry to publish the application in. By default it will be published in the default space.", "title": "--space &lt;space-name&gt;"}, {"location": "cozy-app-publish/#-verbose", "text": "To print more logs when using tool (useful for debug).", "title": "--verbose"}, {"location": "cozy-app-publish/#recommended-workflow", "text": "", "title": "Recommended workflow"}, {"location": "cozy-app-publish/#day-to-day", "text": "Development is done on feature branches that are merged into master , once they are complete. Every time someone commits on master , a new archive is created and uploaded on Downcloud and then published to Cozy Cloud registry.", "title": "Day to day"}, {"location": "cozy-app-publish/#release-workflow", "text": "A new release branch is created from the current state of master . Let\u2019s say we want to deploy version 1.0.0 of the app, we will create release/1.0.0 . Since we created a new branch, we have to bump the version of master , so we have to create a PR to bump to 1.1.0 everywhere it is necessary. This depends on the app, but most of the time it requires to change the package.json and manifest.webapp versions. The only type of commits allowed on this release branch are bug fixes, that should be made on the release branch. To release a stable or beta version, generally we use directly github and the release creation interface. In this interface, don\u2019t forget to fill in the changelog and to check \u201cprelease\u201d for a beta version. The title of the release must be the released version (ex.: 1.40.0-beta.1 ) Every time bugs are fixed and the version is considered for release, the latest commit is tagged with a prerelease version number, eg. 1.0.0-beta.1 , 1.0.0-beta.2 , etc\u2026 Each of these prereleases is automatically uploaded on downcloud and deployed on instances that are on the beta channel. Once the branch is deemed ready for release, the last commit is tagged with the final version \u2014 1.0.0 in our example. It is then, again, uploaded on downcloud, published on the registry and deployed on specific instances as needed. The release branch is merged back into master so that all the bugfixes aren\u2019t lost.", "title": "Release workflow"}, {"location": "cozy-app-publish/#versions", "text": "We apply the semver convention: If the release brings only bug fixes, then we should create a patch version. If the release brings at least one feature, then we should create a minor version. If the release changes its application\u2019s permissions, we should create a minor version even if this release is for bug fixes only.", "title": "Versions"}, {"location": "cozy-app-publish/#hot-fix", "text": "If you need to quickly fix a bug in production, then you have to: fetch the latest branch release create a new release branch from there (since this is a bug fix, this is a patch version) fix the bug Make a beta Publish Merge it on master Example: You have to hot fix Drive. The current stable version of Drive is : 1.45.0. Master is on 1.47.0. Then you need to fetch release/1.45.0 Create a branch from this release: git checkout -b release/1.45.1 git commit -m \u201cfix: Bug fix..\u201d git push git tag \u2026", "title": "Hot Fix"}, {"location": "cozy-app-publish/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 0.34.0 (2024-04-10) \u00b6 Features \u00b6 Allow the possibility to override the mode even on Travis CI ( a565a0a ) 0.33.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 0.32.1 (2022-10-27) \u00b6 Note: Version bump only for package cozy-app-publish 0.32.0 (2022-10-04) \u00b6 Features \u00b6 Prohibits putting only spaces in a document name ( 5568408 ) 0.31.0 (2022-07-05) \u00b6 Features \u00b6 All oauth methods to handle reconection case ( b1a6033 ) 0.30.4 (2022-06-14) \u00b6 Note: Version bump only for package cozy-app-publish 0.30.3 (2022-06-13) \u00b6 Note: Version bump only for package cozy-app-publish 0.30.2 (2022-06-03) \u00b6 Bug Fixes \u00b6 bump tar from 4.4.19 to 6.1.11 ( 128c4a3 ) 0.30.1 (2022-06-02) \u00b6 Note: Version bump only for package cozy-app-publish 0.30.0 (2022-05-25) \u00b6 Bug Fixes \u00b6 bump argparse from 1.0.10 to 2.0.1 ( 832b3db ) Features \u00b6 Remove useVaultClient call in LegacyTriggerManager ( 439e603 ) 0.29.0 (2022-02-03) \u00b6 Bug Fixes \u00b6 deps: update dependency jest to v26.6.3 ( f442fff ) Features \u00b6 Add app parameter to cozy-intent \u2018s openApp method ( 58e0797 ) 0.28.1 (2021-12-02) \u00b6 Note: Version bump only for package cozy-app-publish 0.28.0 (2021-11-03) \u00b6 Features \u00b6 Add verror in cozy-app-publish dependencies ( 653ae83 ) 0.27.2 (2021-10-12) \u00b6 Bug Fixes \u00b6 Fix travis icon on mattermost publish announcement ( 798fac5 ) 0.27.1 (2021-09-03) \u00b6 Bug Fixes \u00b6 Lint cozy-app-publish/README.md ( ad636c5 ) 0.27.0 (2021-02-12) \u00b6 Features \u00b6 Add finance theme ( bb8cf35 ) 0.26.0 (2020-11-23) \u00b6 Features \u00b6 Update jest ( 3b2c32a ) Use ^ for dependencies ( fc28de7 ) 0.25.2 (2020-11-11) \u00b6 Note: Version bump only for package cozy-app-publish 0.25.1 (2020-11-05) \u00b6 Bug Fixes \u00b6 Adjust aligment issues ( efdf056 ) 0.25.0 (2020-08-13) \u00b6 Features \u00b6 Show confirmation prompt before prepublishing ( 3812d94 ) 0.24.1 (2020-08-03) \u00b6 Note: Version bump only for package cozy-app-publish 0.24.0 (2020-07-28) \u00b6 Bug Fixes \u00b6 Clone response since we need to read the text() after reading json() ( 0dd0c3a ) Features \u00b6 Use VError to chain stack traces ( fd3e586 ) 0.23.1 (2020-07-16) \u00b6 Note: Version bump only for package cozy-app-publish 0.23.0 (2020-07-16) \u00b6 Bug Fixes \u00b6 Call revokeSelf if not the owner of the sharing ( f7afc60 ) Features \u00b6 Update lodash accross all packages ( 6a20128 ) 0.22.3 (2020-02-26) \u00b6 Bug Fixes \u00b6 Export src files ( ba1b5c3 ) Import packagejson ( a210b8f ) 0.22.2 (2020-02-25) \u00b6 Note: Version bump only for package cozy-app-publish 0.22.1 (2020-02-24) \u00b6 Bug Fixes \u00b6 Must declare error variable in catch block ( cdd1d42 ) 0.22.0 (2020-02-24) \u00b6 Features \u00b6 Log precise error when failing to require hook ( 3636156 ) 0.21.0 (2020-02-17) \u00b6 Features \u00b6 Ability to send publication message on several channels ( b3d84ab ) Add way to test easily the mattermost hook ( 8d01617 ) Publication message mattermost chan depends on registry chan ( 464430a ) 0.20.3 (2020-02-12) \u00b6 Bug Fixes \u00b6 cozy-app-publish: Mattermost post ( 2f7f986 ) 0.20.2 (2020-01-31) \u00b6 Note: Version bump only for package cozy-app-publish 0.20.1 (2020-01-24) \u00b6 Bug Fixes \u00b6 cozy-app-publish: Handle explicit default space ( dc355cc ) 0.20.0 (2019-11-04) \u00b6 Bug Fixes \u00b6 Translating components ( 1101a66 ) Features \u00b6 Output commit link and travis link in publish message ( 779028e ) 0.19.3 (2019-10-07) \u00b6 Note: Version bump only for package cozy-app-publish 0.19.2 (2019-09-16) \u00b6 Note: Version bump only for package cozy-app-publish 0.19.1 (2019-09-13) \u00b6 Bug Fixes \u00b6 deps: update dependency tar to v4.4.10 ( 5cc8b48 ) 0.19.0 (2019-09-05) \u00b6 Features \u00b6 Add account route ( 7986708 ) 0.18.3 (2019-08-27) \u00b6 Note: Version bump only for package cozy-app-publish 0.18.2 (2019-08-21) \u00b6 Note: Version bump only for package cozy-app-publish 0.18.1 (2019-08-20) \u00b6 Note: Version bump only for package cozy-app-publish 0.18.0 (2019-08-14) \u00b6 Features \u00b6 cozy-app-publish: Add space and application type in matter\u2026 ( #708 ) ( a85a1aa ) cozy-app-publish: Add space and application type in mattermost ( c6b443f ) 0.17.0 (2019-08-13) \u00b6 Features \u00b6 cozy-app-publish: Make mattermost channel optional ( 1fce23d ) 0.16.4 (2019-07-19) \u00b6 Note: Version bump only for package cozy-app-publish 0.16.3 (2019-07-11) \u00b6 Bug Fixes \u00b6 deps: Update dependency lodash to v4.17.13 [SECURITY] ( #648 ) ( 1b36dac ) 0.16.2 (2019-06-25) \u00b6 Bug Fixes \u00b6 cozy-app-publish: Argparse generates null default values ( f9c08c8 ) 0.16.1 (2019-06-21) \u00b6 Bug Fixes \u00b6 cozy-app-publish: Handle snake case cli options ( 5c7da87 ) 0.16.0 (2019-06-18) \u00b6 Bug Fixes \u00b6 Expose FlagSwitcher only in browser context ( f2fafa7 ), closes #402 Features \u00b6 Use argparse ( 8298c62 ) 0.15.0 (2019-03-20) \u00b6 Features \u00b6 app-publish/downcloud: Use space name in remote path ( 22e88c5 ) 0.14.0 (2019-03-20) \u00b6 Features \u00b6 app-publish/downcloud: Use buildDir option ( 89bd5b8 ) 0.13.1 (2019-03-13) \u00b6 Bug Fixes \u00b6 Add lodash as dependency ( a580a78 ) 0.13.0 (2019-03-13) \u00b6 Bug Fixes \u00b6 publish: Typo in help ( 13e6d8b ) Features \u00b6 publish: Let npm warn when using old engine ( 810e9ce ) publish: Tag prefix in travis and manual ( 27b99c1 ) publish: Tags can contain a prefix ( bf59771 ) 0.12.3 (2019-03-13) \u00b6 Note: Version bump only for package cozy-app-publish 0.12.2 (2019-03-12) \u00b6 Note: Version bump only for package cozy-app-publish 0.12.1 (2019-03-07) \u00b6 Note: Version bump only for package cozy-app-publish 0.12.0 (2019-03-05) \u00b6 Bug Fixes \u00b6 Handle errors correctly ( 0769144 ) Features \u00b6 Improve descriptions ( cee1e6f ) yes ( df005ea ) 0.11.1 (2019-02-28) \u00b6 Bug Fixes \u00b6 Use short commit for travis version ( dabb28b ) 0.11.0 (2019-02-28) \u00b6 Bug Fixes \u00b6 Add error handling to CLI main handler ( 2f4b105 ) Reject on process/pipe error ( 35e13d4 ) Features \u00b6 appBuildURL can be provided by prepublish hooks ( c3f09ee ) Auto version in manual mode ( 4cf5065 ) Better error message if custom hook cannot be loaded ( 0f7ceae ) Logs for shasum ( 9190c10 ) Print stack when erroring ( f17de04 ) 0.10.5 (2019-01-29) \u00b6 Note: Version bump only for package cozy-app-publish 0.10.4 (2019-01-21) \u00b6 Note: Version bump only for package cozy-app-publish 0.10.3 (2019-01-10) \u00b6 Bug Fixes \u00b6 Shasum was not following redirects ( 94807ae ) 0.10.2 (2019-01-07) \u00b6 Bug Fixes \u00b6 deps: update dependency chalk to v2.4.2 ( e0921e2 ) 0.10.1 (2019-01-03) \u00b6 Bug Fixes \u00b6 Don\u2019t read publish response stream twice ( a6e7ca7 ) 0.10.0 (2018-12-28) \u00b6 Bug Fixes \u00b6 publish: Catch publishing error ( 63bf575 ) publish: Handle 404 error ( c71f7e6 ) Features \u00b6 publish: Do sha-sum in Node ( de9201d ), closes #68 0.9.1 (2018-12-10) \u00b6 Note: Version bump only for package cozy-app-publish 0.9.0 (2018-10-15) \u00b6 Features \u00b6 app-publish: Remove rundeck postpublish \ud83d\udd25 ( c9c5ffe ) app-publish: Update Mattermost message \ud83d\udcdd ( 8d32a06 ) 0.8.5 (2018-10-11) \u00b6 Note: Version bump only for package cozy-app-publish 0.8.4 (2018-09-27) \u00b6 Note: Version bump only for package cozy-app-publish 0.8.3 (2018-09-25) \u00b6 Note: Version bump only for package cozy-app-publish 0.8.2 (2018-09-25) \u00b6 Bug Fixes \u00b6 add babel-core bridge for v7 ( 18665a8 ), closes /github.com/babel/babel/issues/8206#issuecomment-419705758 0.8.1 (2018-09-21) \u00b6 Note: Version bump only for package cozy-app-publish 0.8.0 (2018-09-18) \u00b6 Features \u00b6 cozy-app-publish: Fail on Travis error \u2728 ( 0307241 ) cozy-app-publish: Throw publish error \u2728 ( 08db1c5 ) 0.7.2 (2018-09-11) \u00b6 Bug Fixes \u00b6 Downcloud folder name \ud83d\ude91 ( c8ac28b ) 0.7.1 (2018-09-07) \u00b6 Bug Fixes \u00b6 Avoid in archive folder \ud83d\ude91 ( 8b09b4b ) 0.7.0 (2018-09-04) \u00b6 Features \u00b6 travis: Throw error on prepublish fail \u2728 ( 7a88817 ) 0.6.0 (2018-08-29) \u00b6 Features \u00b6 cozy-app-publish: Better options check \ud83d\udc6e ( 8f2b33d ) 0.5.5 (2018-08-28) \u00b6 Note: Version bump only for package cozy-app-publish 0.5.4 (2018-08-28) \u00b6 Bug Fixes \u00b6 typo in deploy scripts example in readme ( cf3b558 ) 0.5.3 (2018-08-22) \u00b6 Note: Version bump only for package cozy-app-publish 0.5.2 (2018-08-21) \u00b6 Note: Version bump only for package cozy-app-publish 0.5.1 (2018-08-11) \u00b6 Note: Version bump only for package cozy-app-publish 0.5.0 (2018-08-10) \u00b6 Bug Fixes \u00b6 remove .prettierrc.json from cozy-app-publish ( 1cd528c ) Features \u00b6 import cozy-app-publish as a package ( 403d90d ) Change Log \u00b6 All notable changes to this project will be documented in this file. The format is based on Keep a Changelog and this project adheres to Semantic Versioning . Unreleased \u00b6 Changed \u00b6 none yet Fixed \u00b6 none yet Added \u00b6 disabled attribute for component Removed \u00b6 none yet Deprecated \u00b6 none yet Security \u00b6 none yet v0.3.6 \u00b6 Fixed \u00b6 Make --build-commit usage more priority than the TRAVIS_TAG environment variale v0.3.5 \u00b6 Added \u00b6 Enable --build-url option on Travis mode v0.3.4 \u00b6 Fixed \u00b6 Don\u2019t throw an error on 409 Conflict registry response (version already exists) v0.3.3 \u00b6 Fixed \u00b6 Prefer an option to provided the correct build commit hash: --build-commit $BUILD_COMMIT v0.3.2 \u00b6 Fixed \u00b6 Bug when using BUILD_COMMIT v0.3.1 \u00b6 Changed \u00b6 Use back the TRAVIS_COMMIT for dev versioning Added \u00b6 Hanlde BUILD_COMMIT from environment for dev versioning v0.3.0 \u00b6 Added \u00b6 Add an automatic mode detection according to environment variables Changed \u00b6 Grab editor name directly from the manifest instead of the CLI option The dev version computing in Travis mode use the archive shasum instead of the TRAVIS_COMMIT Removed \u00b6 --on-branch option with git branch checking in travis mode Unused --travis option The --editor option since it\u2019s now using the manifest Pull request checking in travis mode v0.2.0 \u00b6 Changed \u00b6 Now use the registry in production URL Added \u00b6 Handle registry spaces name through --space option v0.1.1 First release \u00b6 Deploy a Cozy application to Cozy Cloud registry", "title": "Change Log"}, {"location": "cozy-app-publish/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "cozy-app-publish/CHANGELOG/#0340-2024-04-10", "text": "", "title": "0.34.0 (2024-04-10)"}, {"location": "cozy-app-publish/CHANGELOG/#features", "text": "Allow the possibility to override the mode even on Travis CI ( a565a0a )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0330-2023-01-31", "text": "", "title": "0.33.0 (2023-01-31)"}, {"location": "cozy-app-publish/CHANGELOG/#features_1", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0321-2022-10-27", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.32.1 (2022-10-27)"}, {"location": "cozy-app-publish/CHANGELOG/#0320-2022-10-04", "text": "", "title": "0.32.0 (2022-10-04)"}, {"location": "cozy-app-publish/CHANGELOG/#features_2", "text": "Prohibits putting only spaces in a document name ( 5568408 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0310-2022-07-05", "text": "", "title": "0.31.0 (2022-07-05)"}, {"location": "cozy-app-publish/CHANGELOG/#features_3", "text": "All oauth methods to handle reconection case ( b1a6033 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0304-2022-06-14", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.30.4 (2022-06-14)"}, {"location": "cozy-app-publish/CHANGELOG/#0303-2022-06-13", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.30.3 (2022-06-13)"}, {"location": "cozy-app-publish/CHANGELOG/#0302-2022-06-03", "text": "", "title": "0.30.2 (2022-06-03)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes", "text": "bump tar from 4.4.19 to 6.1.11 ( 128c4a3 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0301-2022-06-02", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.30.1 (2022-06-02)"}, {"location": "cozy-app-publish/CHANGELOG/#0300-2022-05-25", "text": "", "title": "0.30.0 (2022-05-25)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_1", "text": "bump argparse from 1.0.10 to 2.0.1 ( 832b3db )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_4", "text": "Remove useVaultClient call in LegacyTriggerManager ( 439e603 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0290-2022-02-03", "text": "", "title": "0.29.0 (2022-02-03)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_2", "text": "deps: update dependency jest to v26.6.3 ( f442fff )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_5", "text": "Add app parameter to cozy-intent \u2018s openApp method ( 58e0797 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0281-2021-12-02", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.28.1 (2021-12-02)"}, {"location": "cozy-app-publish/CHANGELOG/#0280-2021-11-03", "text": "", "title": "0.28.0 (2021-11-03)"}, {"location": "cozy-app-publish/CHANGELOG/#features_6", "text": "Add verror in cozy-app-publish dependencies ( 653ae83 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0272-2021-10-12", "text": "", "title": "0.27.2 (2021-10-12)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_3", "text": "Fix travis icon on mattermost publish announcement ( 798fac5 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0271-2021-09-03", "text": "", "title": "0.27.1 (2021-09-03)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_4", "text": "Lint cozy-app-publish/README.md ( ad636c5 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0270-2021-02-12", "text": "", "title": "0.27.0 (2021-02-12)"}, {"location": "cozy-app-publish/CHANGELOG/#features_7", "text": "Add finance theme ( bb8cf35 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0260-2020-11-23", "text": "", "title": "0.26.0 (2020-11-23)"}, {"location": "cozy-app-publish/CHANGELOG/#features_8", "text": "Update jest ( 3b2c32a ) Use ^ for dependencies ( fc28de7 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0252-2020-11-11", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.25.2 (2020-11-11)"}, {"location": "cozy-app-publish/CHANGELOG/#0251-2020-11-05", "text": "", "title": "0.25.1 (2020-11-05)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_5", "text": "Adjust aligment issues ( efdf056 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0250-2020-08-13", "text": "", "title": "0.25.0 (2020-08-13)"}, {"location": "cozy-app-publish/CHANGELOG/#features_9", "text": "Show confirmation prompt before prepublishing ( 3812d94 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0241-2020-08-03", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.24.1 (2020-08-03)"}, {"location": "cozy-app-publish/CHANGELOG/#0240-2020-07-28", "text": "", "title": "0.24.0 (2020-07-28)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_6", "text": "Clone response since we need to read the text() after reading json() ( 0dd0c3a )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_10", "text": "Use VError to chain stack traces ( fd3e586 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0231-2020-07-16", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.23.1 (2020-07-16)"}, {"location": "cozy-app-publish/CHANGELOG/#0230-2020-07-16", "text": "", "title": "0.23.0 (2020-07-16)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_7", "text": "Call revokeSelf if not the owner of the sharing ( f7afc60 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_11", "text": "Update lodash accross all packages ( 6a20128 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0223-2020-02-26", "text": "", "title": "0.22.3 (2020-02-26)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_8", "text": "Export src files ( ba1b5c3 ) Import packagejson ( a210b8f )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0222-2020-02-25", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.22.2 (2020-02-25)"}, {"location": "cozy-app-publish/CHANGELOG/#0221-2020-02-24", "text": "", "title": "0.22.1 (2020-02-24)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_9", "text": "Must declare error variable in catch block ( cdd1d42 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0220-2020-02-24", "text": "", "title": "0.22.0 (2020-02-24)"}, {"location": "cozy-app-publish/CHANGELOG/#features_12", "text": "Log precise error when failing to require hook ( 3636156 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0210-2020-02-17", "text": "", "title": "0.21.0 (2020-02-17)"}, {"location": "cozy-app-publish/CHANGELOG/#features_13", "text": "Ability to send publication message on several channels ( b3d84ab ) Add way to test easily the mattermost hook ( 8d01617 ) Publication message mattermost chan depends on registry chan ( 464430a )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0203-2020-02-12", "text": "", "title": "0.20.3 (2020-02-12)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_10", "text": "cozy-app-publish: Mattermost post ( 2f7f986 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0202-2020-01-31", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.20.2 (2020-01-31)"}, {"location": "cozy-app-publish/CHANGELOG/#0201-2020-01-24", "text": "", "title": "0.20.1 (2020-01-24)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_11", "text": "cozy-app-publish: Handle explicit default space ( dc355cc )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0200-2019-11-04", "text": "", "title": "0.20.0 (2019-11-04)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_12", "text": "Translating components ( 1101a66 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_14", "text": "Output commit link and travis link in publish message ( 779028e )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0193-2019-10-07", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.19.3 (2019-10-07)"}, {"location": "cozy-app-publish/CHANGELOG/#0192-2019-09-16", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.19.2 (2019-09-16)"}, {"location": "cozy-app-publish/CHANGELOG/#0191-2019-09-13", "text": "", "title": "0.19.1 (2019-09-13)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_13", "text": "deps: update dependency tar to v4.4.10 ( 5cc8b48 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0190-2019-09-05", "text": "", "title": "0.19.0 (2019-09-05)"}, {"location": "cozy-app-publish/CHANGELOG/#features_15", "text": "Add account route ( 7986708 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0183-2019-08-27", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.18.3 (2019-08-27)"}, {"location": "cozy-app-publish/CHANGELOG/#0182-2019-08-21", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.18.2 (2019-08-21)"}, {"location": "cozy-app-publish/CHANGELOG/#0181-2019-08-20", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.18.1 (2019-08-20)"}, {"location": "cozy-app-publish/CHANGELOG/#0180-2019-08-14", "text": "", "title": "0.18.0 (2019-08-14)"}, {"location": "cozy-app-publish/CHANGELOG/#features_16", "text": "cozy-app-publish: Add space and application type in matter\u2026 ( #708 ) ( a85a1aa ) cozy-app-publish: Add space and application type in mattermost ( c6b443f )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0170-2019-08-13", "text": "", "title": "0.17.0 (2019-08-13)"}, {"location": "cozy-app-publish/CHANGELOG/#features_17", "text": "cozy-app-publish: Make mattermost channel optional ( 1fce23d )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0164-2019-07-19", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.16.4 (2019-07-19)"}, {"location": "cozy-app-publish/CHANGELOG/#0163-2019-07-11", "text": "", "title": "0.16.3 (2019-07-11)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_14", "text": "deps: Update dependency lodash to v4.17.13 [SECURITY] ( #648 ) ( 1b36dac )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0162-2019-06-25", "text": "", "title": "0.16.2 (2019-06-25)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_15", "text": "cozy-app-publish: Argparse generates null default values ( f9c08c8 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0161-2019-06-21", "text": "", "title": "0.16.1 (2019-06-21)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_16", "text": "cozy-app-publish: Handle snake case cli options ( 5c7da87 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0160-2019-06-18", "text": "", "title": "0.16.0 (2019-06-18)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_17", "text": "Expose FlagSwitcher only in browser context ( f2fafa7 ), closes #402", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_18", "text": "Use argparse ( 8298c62 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0150-2019-03-20", "text": "", "title": "0.15.0 (2019-03-20)"}, {"location": "cozy-app-publish/CHANGELOG/#features_19", "text": "app-publish/downcloud: Use space name in remote path ( 22e88c5 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0140-2019-03-20", "text": "", "title": "0.14.0 (2019-03-20)"}, {"location": "cozy-app-publish/CHANGELOG/#features_20", "text": "app-publish/downcloud: Use buildDir option ( 89bd5b8 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0131-2019-03-13", "text": "", "title": "0.13.1 (2019-03-13)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_18", "text": "Add lodash as dependency ( a580a78 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0130-2019-03-13", "text": "", "title": "0.13.0 (2019-03-13)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_19", "text": "publish: Typo in help ( 13e6d8b )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_21", "text": "publish: Let npm warn when using old engine ( 810e9ce ) publish: Tag prefix in travis and manual ( 27b99c1 ) publish: Tags can contain a prefix ( bf59771 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0123-2019-03-13", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.12.3 (2019-03-13)"}, {"location": "cozy-app-publish/CHANGELOG/#0122-2019-03-12", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.12.2 (2019-03-12)"}, {"location": "cozy-app-publish/CHANGELOG/#0121-2019-03-07", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.12.1 (2019-03-07)"}, {"location": "cozy-app-publish/CHANGELOG/#0120-2019-03-05", "text": "", "title": "0.12.0 (2019-03-05)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_20", "text": "Handle errors correctly ( 0769144 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_22", "text": "Improve descriptions ( cee1e6f ) yes ( df005ea )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0111-2019-02-28", "text": "", "title": "0.11.1 (2019-02-28)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_21", "text": "Use short commit for travis version ( dabb28b )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0110-2019-02-28", "text": "", "title": "0.11.0 (2019-02-28)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_22", "text": "Add error handling to CLI main handler ( 2f4b105 ) Reject on process/pipe error ( 35e13d4 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_23", "text": "appBuildURL can be provided by prepublish hooks ( c3f09ee ) Auto version in manual mode ( 4cf5065 ) Better error message if custom hook cannot be loaded ( 0f7ceae ) Logs for shasum ( 9190c10 ) Print stack when erroring ( f17de04 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#0105-2019-01-29", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.10.5 (2019-01-29)"}, {"location": "cozy-app-publish/CHANGELOG/#0104-2019-01-21", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.10.4 (2019-01-21)"}, {"location": "cozy-app-publish/CHANGELOG/#0103-2019-01-10", "text": "", "title": "0.10.3 (2019-01-10)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_23", "text": "Shasum was not following redirects ( 94807ae )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0102-2019-01-07", "text": "", "title": "0.10.2 (2019-01-07)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_24", "text": "deps: update dependency chalk to v2.4.2 ( e0921e2 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0101-2019-01-03", "text": "", "title": "0.10.1 (2019-01-03)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_25", "text": "Don\u2019t read publish response stream twice ( a6e7ca7 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#0100-2018-12-28", "text": "", "title": "0.10.0 (2018-12-28)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_26", "text": "publish: Catch publishing error ( 63bf575 ) publish: Handle 404 error ( c71f7e6 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_24", "text": "publish: Do sha-sum in Node ( de9201d ), closes #68", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#091-2018-12-10", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.9.1 (2018-12-10)"}, {"location": "cozy-app-publish/CHANGELOG/#090-2018-10-15", "text": "", "title": "0.9.0 (2018-10-15)"}, {"location": "cozy-app-publish/CHANGELOG/#features_25", "text": "app-publish: Remove rundeck postpublish \ud83d\udd25 ( c9c5ffe ) app-publish: Update Mattermost message \ud83d\udcdd ( 8d32a06 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#085-2018-10-11", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.8.5 (2018-10-11)"}, {"location": "cozy-app-publish/CHANGELOG/#084-2018-09-27", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.8.4 (2018-09-27)"}, {"location": "cozy-app-publish/CHANGELOG/#083-2018-09-25", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.8.3 (2018-09-25)"}, {"location": "cozy-app-publish/CHANGELOG/#082-2018-09-25", "text": "", "title": "0.8.2 (2018-09-25)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_27", "text": "add babel-core bridge for v7 ( 18665a8 ), closes /github.com/babel/babel/issues/8206#issuecomment-419705758", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#081-2018-09-21", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.8.1 (2018-09-21)"}, {"location": "cozy-app-publish/CHANGELOG/#080-2018-09-18", "text": "", "title": "0.8.0 (2018-09-18)"}, {"location": "cozy-app-publish/CHANGELOG/#features_26", "text": "cozy-app-publish: Fail on Travis error \u2728 ( 0307241 ) cozy-app-publish: Throw publish error \u2728 ( 08db1c5 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#072-2018-09-11", "text": "", "title": "0.7.2 (2018-09-11)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_28", "text": "Downcloud folder name \ud83d\ude91 ( c8ac28b )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#071-2018-09-07", "text": "", "title": "0.7.1 (2018-09-07)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_29", "text": "Avoid in archive folder \ud83d\ude91 ( 8b09b4b )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#070-2018-09-04", "text": "", "title": "0.7.0 (2018-09-04)"}, {"location": "cozy-app-publish/CHANGELOG/#features_27", "text": "travis: Throw error on prepublish fail \u2728 ( 7a88817 )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#060-2018-08-29", "text": "", "title": "0.6.0 (2018-08-29)"}, {"location": "cozy-app-publish/CHANGELOG/#features_28", "text": "cozy-app-publish: Better options check \ud83d\udc6e ( 8f2b33d )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#055-2018-08-28", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.5.5 (2018-08-28)"}, {"location": "cozy-app-publish/CHANGELOG/#054-2018-08-28", "text": "", "title": "0.5.4 (2018-08-28)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_30", "text": "typo in deploy scripts example in readme ( cf3b558 )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#053-2018-08-22", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.5.3 (2018-08-22)"}, {"location": "cozy-app-publish/CHANGELOG/#052-2018-08-21", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.5.2 (2018-08-21)"}, {"location": "cozy-app-publish/CHANGELOG/#051-2018-08-11", "text": "Note: Version bump only for package cozy-app-publish", "title": "0.5.1 (2018-08-11)"}, {"location": "cozy-app-publish/CHANGELOG/#050-2018-08-10", "text": "", "title": "0.5.0 (2018-08-10)"}, {"location": "cozy-app-publish/CHANGELOG/#bug-fixes_31", "text": "remove .prettierrc.json from cozy-app-publish ( 1cd528c )", "title": "Bug Fixes"}, {"location": "cozy-app-publish/CHANGELOG/#features_29", "text": "import cozy-app-publish as a package ( 403d90d )", "title": "Features"}, {"location": "cozy-app-publish/CHANGELOG/#change-log_1", "text": "All notable changes to this project will be documented in this file. The format is based on Keep a Changelog and this project adheres to Semantic Versioning .", "title": "Change Log"}, {"location": "cozy-app-publish/CHANGELOG/#unreleased", "text": "", "title": "Unreleased"}, {"location": "cozy-app-publish/CHANGELOG/#changed", "text": "none yet", "title": "Changed"}, {"location": "cozy-app-publish/CHANGELOG/#fixed", "text": "none yet", "title": "Fixed"}, {"location": "cozy-app-publish/CHANGELOG/#added", "text": "disabled attribute for component", "title": "Added"}, {"location": "cozy-app-publish/CHANGELOG/#removed", "text": "none yet", "title": "Removed"}, {"location": "cozy-app-publish/CHANGELOG/#deprecated", "text": "none yet", "title": "Deprecated"}, {"location": "cozy-app-publish/CHANGELOG/#security", "text": "none yet", "title": "Security"}, {"location": "cozy-app-publish/CHANGELOG/#v036", "text": "", "title": "v0.3.6"}, {"location": "cozy-app-publish/CHANGELOG/#fixed_1", "text": "Make --build-commit usage more priority than the TRAVIS_TAG environment variale", "title": "Fixed"}, {"location": "cozy-app-publish/CHANGELOG/#v035", "text": "", "title": "v0.3.5"}, {"location": "cozy-app-publish/CHANGELOG/#added_1", "text": "Enable --build-url option on Travis mode", "title": "Added"}, {"location": "cozy-app-publish/CHANGELOG/#v034", "text": "", "title": "v0.3.4"}, {"location": "cozy-app-publish/CHANGELOG/#fixed_2", "text": "Don\u2019t throw an error on 409 Conflict registry response (version already exists)", "title": "Fixed"}, {"location": "cozy-app-publish/CHANGELOG/#v033", "text": "", "title": "v0.3.3"}, {"location": "cozy-app-publish/CHANGELOG/#fixed_3", "text": "Prefer an option to provided the correct build commit hash: --build-commit $BUILD_COMMIT", "title": "Fixed"}, {"location": "cozy-app-publish/CHANGELOG/#v032", "text": "", "title": "v0.3.2"}, {"location": "cozy-app-publish/CHANGELOG/#fixed_4", "text": "Bug when using BUILD_COMMIT", "title": "Fixed"}, {"location": "cozy-app-publish/CHANGELOG/#v031", "text": "", "title": "v0.3.1"}, {"location": "cozy-app-publish/CHANGELOG/#changed_1", "text": "Use back the TRAVIS_COMMIT for dev versioning", "title": "Changed"}, {"location": "cozy-app-publish/CHANGELOG/#added_2", "text": "Hanlde BUILD_COMMIT from environment for dev versioning", "title": "Added"}, {"location": "cozy-app-publish/CHANGELOG/#v030", "text": "", "title": "v0.3.0"}, {"location": "cozy-app-publish/CHANGELOG/#added_3", "text": "Add an automatic mode detection according to environment variables", "title": "Added"}, {"location": "cozy-app-publish/CHANGELOG/#changed_2", "text": "Grab editor name directly from the manifest instead of the CLI option The dev version computing in Travis mode use the archive shasum instead of the TRAVIS_COMMIT", "title": "Changed"}, {"location": "cozy-app-publish/CHANGELOG/#removed_1", "text": "--on-branch option with git branch checking in travis mode Unused --travis option The --editor option since it\u2019s now using the manifest Pull request checking in travis mode", "title": "Removed"}, {"location": "cozy-app-publish/CHANGELOG/#v020", "text": "", "title": "v0.2.0"}, {"location": "cozy-app-publish/CHANGELOG/#changed_3", "text": "Now use the registry in production URL", "title": "Changed"}, {"location": "cozy-app-publish/CHANGELOG/#added_4", "text": "Handle registry spaces name through --space option", "title": "Added"}, {"location": "cozy-app-publish/CHANGELOG/#v011-first-release", "text": "Deploy a Cozy application to Cozy Cloud registry", "title": "v0.1.1 First release"}, {"location": "cozy-apps-registry/", "text": "cozy-apps-registry \u00b6 What\u2019s Cozy? \u00b6 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\u2019s tracking you. Table of contents \u00b6 cozy-apps-registry What\u2019s Cozy? Table of contents What about this repository? How to develop with a cozy-apps-registry working in local environment 1) Install and configure the local cozy-apps-registry 2) Configure the registry with cozy-registry.yml 3) Run the registry to serve the apps 4) Create an editor 5) Configure cozy-stack with the registry Publish your application on the registry 1) Define your application manifest Properties meaning (reference) Available manifest\u2019s features list : Translated manifest fields Application terms Konnectors folders handling Konnectors fields property Konnectors message property Categories and Data types 2) Add a new application in the registry Our official apps registry Custom registry 3) Add a new version of a registered application Via cozy-app-publish (highly recommanded) Via curl Spaces & Virtual Spaces Spaces Create a space Remove a space Virtual Spaces Automation (CI) Access control and tokens Maintenance Import/export Application confidence grade / labelling Universal links Configuration Config file Files Usage Budget-Insight web auth Community What about this repository? \u00b6 The cozy-apps-registry is a go project that implements the registry API described to work with the cozy-stack . To work properly, it requires: Go >= 1.18 Couchdb >= 3.2 Redis Openstack Object Storage (Swift) How to develop with a cozy-apps-registry working in local environment \u00b6 Before starting, you will need to have a couchdb running already. That can be the one used by the local cozy-stack if you have one. For this tutorial, couchdb will be running on the default port 5984. You also must have redis and an OpenStack Object Storage (Swift) up and running. You can follow install instructions on the official website 1) Install and configure the local cozy-apps-registry \u00b6 Since this is a golang project, you can install it using go with the followed command: go get -u github.com/cozy/cozy-apps-registry cd $GOPATH /src/github.com/cozy/cozy-apps-registry/ Then you will need a session secret key to run the registry (this key will be store in the sessionsecret.key file of your working directory) using a password: cozy-apps-registry gen-session-secret --passphrase sessionsecret.key This password is important, you will need it to run the cozy-apps-registry again later. If you lose it, you will have to start again these steps. 2) Configure the registry with cozy-registry.yml \u00b6 Before running the registry, you have to configure it correctly. Don\u2019t worry, here is the yaml file to copy and paste in your cozy-registry.yml (should be in the root folder of cozy-apps-registry/ ): You can find an example of this configuration file at the root of the directory. # server host (serve command) - flag --host host : \"localhost\" # server port (serve command) - flag --port port : 8081 couchdb : # CouchDB server url - flag --couchdb-url url : http://localhost:5984 # CouchDB user - flag --couchdb-user user : '' # CouchDB password - flag --couchdb-password password : '' # CouchDB prefix for the registries databases - flag --couchdb-prefix prefix : registry1 swift : # Swift auth URL (provided by keystone) auth_url : http://172.28.128.3/identity/v3 # Swift username username : admin # Swift password api_key : secret # Endpoint type (public/admin/internal) endpointy_type : public # Project name tenant : demo # Swift domain domain : default # Path to the session secret file containing the master secret to generate # session token. # # Should be generated with the \"gen-session-secret\" command. session-secret : sessionsecret.key Feel free to change it if some configurations change in your case (the couchdb user, the server parameters or the databases prefix for example). Notices: Here the generated session token (step 1) is stored in the sessionsecret.key file of the working directory, this is so the value of the property session-secret at the end of the configuration file. By default, the local couchdb allow all admin accesses without creating users, so there is no user and password here. But if an admin user has been created, you have to use the properties user and password in the couchdb part to provide these informations. It\u2019s also possible to use env variables for configuration. You can take the key from the configuration file and add the COZY_REGISTRY prefix. For example, you can run: COZY_REGISTRY_PORT = 8081 cozy-apps-registry serve There is also the REGISTRY_SESSION_PASS env variable for the password for the session secret. 3) Run the registry to serve the apps \u00b6 Run the registry using this followed command (here our configuration file is a cozy-registry.yml in the current working directory): cozy-apps-registry serve -c cozy-registry.yml At this step, you should have a cozy-apps-registry running and ready for the development. If you runnig the registry for the first time you can see the next steps to create a new editor and to configure your local cozy-stack to run with this new registry. The -c options is always mandatory if you want to specify a config file like here. 4) Create an editor \u00b6 This step is required to submit new applications in the registry. In another terminal, run these commands to create an editor (the one that will submit the application(s)) and generate an access token: cozy-apps-registry add-editor Cozy -c cozy-registry.yml cozy-apps-registry gen-token --master Cozy -c cozy-registry.yml Here we go, you have now an registry ready and running on the 8081 port. The -c options is always mandatory if you want to specify a config file like here. 5) Configure cozy-stack with the registry \u00b6 On the cozy-stack , you have to add the new registry in the stack configuration file cozy.yaml (registries property): ... registries : default : - http://localhost:8081/ ... Now restart your local cozy-stack to take this new configuration in consideration (stop and run again cozy-stack serve ) and you\u2019re ready to work with the cozy-apps-registry ! Publish your application on the registry \u00b6 If you need more details about the registry you can go to the official registry documentation Important: In this whole documentation, by the term application , we mean a web application or a konnector. Indeed, for the registry, all entities are applications and they can be either webapp or konnector type. 1) Define your application manifest \u00b6 To be publishable, your application requires some informations in its manifest.webapp , the manifest of a Cozy application. You can find an example of manifest for an application in Cozy-Drive and one for a konnector in cozy-konnector-trainline . Most properties are common to both applications and konnectors but platforms, screenshots, services, routes and intents are only used in applications. Properties oauth, data_types, doctypes, fields, frequency, language, messages, parameters, time_interval, uuid and vendor_link ar only used in konnectors. Properties meaning (reference) \u00b6 Here are all properties meaning for the manifest file (for webapp and konnectors) sorted alphabetically: Field Description aggregator Object containing aggregator data. Typically { accountId: 'aggregator-service' } . categories array of categories for your apps (see authorized categories), it will be ['others'] by default if empty data_types (konnector specific) Array of the data type the konnector will manage developer name and url for the developer editor the editor\u2019s name to display on the cozy-bar ( REQUIRED ) fields (konnector specific) JSON object describing the fields need by the konnector ( except folder path ). Used to generate a form. See below folders (konnector specific) A list of folders required by the konnector to store files according to datatype (see the specific documentation below ) frequency (konnector specific) A human readable value between monthly , weekly , daily , hourly , indicating the interval of time between two runs of the konnector. Default: weekly . icon path to the icon for the home (path in the build) intents (application specific) a list of intents provided by this app (see cozy-stack intents doc for more details) langs Languages available in your app (can be different from locales) language (konnector specific) the konnector development language used (ex: node ) license the SPDX license identifier locales an object with language slug as property, each name property is an object of localized informations (see the second part below) manifest_version The current manifest version used. This is a versioning for the manifest and allow better retrocompatiblity when processing app manifest messages (konnector specific) Array of message identifiers, which can be used by application to display information at known areas. See example below . mobile (application specific) JSON object containing information about app\u2019s mobile version (see cozy-stack routes doc for more details) name the name to display on the home ( REQUIRED ) name_prefix the prefix to display with the name oauth (konnector specific) JSON object containing oAuth information, like scope . If a manifest provides an oauth property, it is considered as an OAuth konnector. Note: scope can be a string or an array. If it is an array, its values will be joined with a space. A false or null value in scope will remove any scope parameter in the request sent to the oauth provider. parameters (konnector specific) Additional parameters which should be passed to the konnector. Used for example for bank konnectors to pass a bankId parameter. partnership an object to provide informations (to display in the Store for example) about a partnership related to the application ( icon description , name and domain ). It can also be used to trigger alternative konnector connection policies for some vendors (see the budget-insight konnector policy in cozy-harvest ). permissions a map of permissions needed by the app (see see cozy-stack permissions doc for more details) platforms (application specific) List of objects for platform native applications. For now there are only two properties: type (i.e. 'ios' or 'linux' ) and the optional url to reach this application page. routes (application specific) a map of routes for the app (see cozy-stack routes doc for more details) ( REQUIRED ) screenshots an array of paths to the screenshots of the application (paths in the build) services (application specific) a map of the services associated with the app (see cozy-stack services doc for more details) slug the default slug that should never change (alpha-numeric lowercase) ( REQUIRED ) source where the files of the app can be downloaded (by default it will look for the branch build ) terms an object defining properties for terms that need to be displayed/accepted by the user when installing the application ( more-info-below ) time_interval (konnector specific) By defaults, konnector triggers are scheduled randomly between 00:00 AM and 05:00 AM. Those two values can be overwritten thanks to this property, by passing an array containing two values: first is the interval start hour, second is the interval end hour. Example: [15, 21] will randomly schedule the konnector trigger between 15:00 (03:00 PM) and 21:00 (09:00 PM). The time zone used is GMT. type type of application ( konnector or webapp ) ( REQUIRED ) version the current version number ( REQUIRED ) vendor_link (konnector specific) URL to editor or service website qualification_labels (konnector specific) Array of one or more labels from the Cozy Client\u2019s qualifications list to associate with the files the konnector will receive from the website. features (konnector specific) Array of features added in the konnector from the list below. Available manifest\u2019s features list : \u00b6 2FA Two Factors identification. BILLS Import bills documents, doctype \u201cio.cozy.bills\u201d. FILES Import files documents, doctype \u201cio.cozy.files\u201d. CAPTCHA_RESOLUTION The konnector using a captcha resolution process. CARBON_COPY The konnector import legally true copy of the original files. DOC_QUALIFICATION The konnector uses the first version of files qualifications, you may stumble upon on some konnectors wich hasn\u2019t been treated. DOC_QUALIFICATION_V2 The konnector uses new version (last one for now) of files qualifications. ELECTRONIC_SAFE Files comes from a known electronic safe. HEALTH The konnector treat health documents HTML_TO_PDF The konnector needs to convert HTML page(s) to make pdf files. IDENTITY The konnector create identity(ies) for doctype \u201cio.cozy.identities\u201d LOGIN_OK The konnector deactivate the auto-notification METADATA_DEDUP The konnector uses a fileIdAttribute as detection to avoid deduplication. VENDOR_REF The konnector uses. SENTRY_V2 The konnector had been migrated (or packaged) to sentry V2 (errors.cozycloud.cc) Notices: All images paths ( icon , partnership.icon and screenshots ) should be relative to the build directory. For example, here, the icon.svg is stored in the build root directory and all screenshots are store in a folder screenshots in the build directory. Therefore, if you use a bundler (like webpack) be sure to know exactly where the bundler will store these assets in the build directory (and change it in the manifest if needed). All properties in locales objects will override the matched property of the main manifest.webapp body, if a property is not found in locales it will fallback to the main body one. We use to have the en locale as default one if the one wanted by the user doesn\u2019t exist. Be sure to have, at least, that locale complete with the name and all descriptions. In your build files, this manifest.webapp file must be at the root. Translated manifest fields \u00b6 Here are the properties that you can override using locales (we recommand to automatically build these properties according to your locales files if you\u2019re using a translating tool like transifex ): name , the app\u2019s name short_description , short description of what the app do long_description , longer and more complete description of the app behaviour changes , description of your new version of the konnector or all changes since the last version fields , An object containing translations for fields. screenshots folders { \"fields\" : { \"email\" : { \"type\" : \"email\" } }, \"locales\" : { \"en\" : { \"short_description\" : \"Collect your Orange's bills\" , \"fields\" : { \"email\" : { \"label\" : \"Identifier (your email)\" } } }, \"fr\" : { \"short_description\" : \"R\u00e9cup\u00e8re vos factures Orange\" , \"fields\" : { \"email\" : { \"label\" : \"Identifiant (votre adresse mail)\" } } } } } Application terms \u00b6 You can provide a related terms property if you want to display and make the user accept some terms (ToS for example) just before installing the application. Here are all properties allowed and used: url , the URL of the terms/contract to redirect the user to ( REQUIRED ) version : A specific version of the terms, we need it handle terms updates and ask the user again to accept the update. The special characters [*+~.()'\"!:@] are not allowed here. ( REQUIRED ) id : An id for the terms. When accepting terms, we store in io.cozy.terms , a document containing the id and version so that we know which terms have been accepted, and show the user a modal if the terms have not been accepted yet. The special characters [*+~.()'\"!:@] are not allowed here. ( REQUIRED ) Konnectors folders handling \u00b6 The folders property is a list of objects with these following properties: defaultDir : ( REQUIRED ) The default root directory of your folder. In this folder will automatically be created a subfolder with the konnector name and into this latter a subfolder with the account name to store the related files. Here you can use some variables in the path like the following: $administrative : Folder which will receive all administrative related files (bills, contracts, invoices\u2026) $photos : Folder which will receive all photos $konnector : The name of the konnector All paths provided using defaultDir will be the root directory, not the final folder which will receive the files. For example, if you set $photos , the final folder will be $photos/$konnector/$account in order to keep them always sorted by konnectors and accounts. Konnectors fields property \u00b6 The fields property is a JSON object describing the input fields needed to generate the konnector\u2019s configuration form. A typical example will be: { \"fields\" : { \"identifier\" : { \"type\" : \"text\" }, \"secret\" : { \"type\" : \"password\" } } } The keys of the fields object are the name/id of the fields. They will be passed as parameters to the konnector at every run. Each fields may also have the following properties: Property Description identifier (Boolean) indicating if the field is the main identifier. By default, the login field is the identifier. Default value is false and there can be only one identifier advanced Indicates if the field should be displayed in the \u201cadvanced\u201d area of the form (default: false ) default Default value. It can a string for a text field, or an object for a select field ( \"default\": {\"value\": \"foo\",\"name\": \"bar\"}, ) description Field description, as a locale key. label Predefined label. This value must match a locale key provided by Cozy-Home. Example: With label: \"identifier\" , Cozy-Home will use the locale key account.form.label.identifier . Translations for these fields use the locales property in the manifest. max Maximum length of the value (number of characters) min Minimum length of the value (number of characters) options When the field is a dropdown, list of available options pattern Define a regex used to validate the field. isRequired Boolean indicating if the field is required or not (default true ) type Required . Field type from dropdown , email , hidden , password , text , checkbox . Konnectors message property \u00b6 Messages are a common way to provide custom information to display in application. An app like cozy-home should have some specific area to display custom messages provided by the konnector. Example: // The final example will be available after the implementation of the whole mechanism, // but here is the global idea: { installSuccess && < p >{ t ( 'home.konnector.install.success.message' )} } { installSuccess && konnector . manifest . messages . includes ( 'success_message' ) && < p >{ t ( 'konnector.manifest.locales.messages.success_message' )} } Categories and Data types \u00b6 Categories are slugs from the following list: banking clouds cozy education energy finance health host_provider insurance isp mes_infos online_services partners press pro productivity ptnb public_service shopping social tech telecom transport Data types are slugs from the following list: activity appointment bankTransactions bankAccounts bill bloodPressure calendar certificate commit consumption contact contract courseMaterial document event family geopoint heartbeat home phonecommunicationlog podcast profile refund sinister sleepTime stepsNumber temperature travelDate tweet videostream weight 2) Add a new application in the registry \u00b6 Our official apps registry \u00b6 Official registry URL: https://apps-registry.cozycloud.cc In order to use our official repository, you need a token for a specific editor. To do so, contact us directly at the address contact@cozycloud.cc with a mail using the following title prefix: [registry] and provide us these folowing information (not changeable after): - slug of your application - editor name that you want We will provide you with the correct token. Custom registry \u00b6 See the details below to know how to add a new application in a custom cozy-apps-registry instance (local or not). Prequisites : - For this step, you will need your editor token access generated when you created your editor (see below ). You have to replace all {{EDITOR_TOKEN}} in this documentation by this token. - The communication with the registry is done through HTTP requests for now. So we will use the curl command line tool to register our application here. Now you can add your application in the registry. This step is splitted in two septs: - Add a new application (without versions) - Add a version of the application A new application without registered version won\u2019t be displayed by the cozy-store application . To add a new application, you have to do a POST request which all the informations needed to the route registryAddress/registry with registryAddress your registry address (for example here http://localhost:8081 ). Let\u2019s add the Collect application as example: # {{EDITOR_TOKEN}} -> your generated editor access token curl -X \"POST\" \"http://localhost:8081/registry\" \\ -H \"Authorization: Token {{EDITOR_TOKEN}}\" \\ -H \"Content-Type: application/json\" \\ -d $'{ \"slug\": \"collect\", \"type\": \"webapp\", \"editor\": \"{{EDITOR}}\" }' Field Description slug your application unique ID type kind of application (it can be only webapp or konnector ) editor Name of the editor matching the {{EDITOR_TOKEN}} Here the slug is the unique ID of the application in the registry, so it can\u2019t be changed after the application is already registered. 3) Add a new version of a registered application \u00b6 Please note that an application bundle cannot be larger than 20MB (hardcoded value). This limitation has been implemented to encourage better web application development practices because in general the larger the application bundle is, the worst the performance and user experience will be. Via cozy-app-publish (highly recommanded) \u00b6 Here we will show the classical way to add a version using the manual mode of cozy-app-publish as reference. But you may need to look at the Automation CI part of this documentation instead. Prequisites : For this step, you will need your editor token access generated when you created your editor (see below ). You have to replace all {{EDITOR_TOKEN}} in this documentation by this token. Don\u2019t forget to build your application first (run yarn build ), cozy-app-publish will read the manifest from your build Firstly, install the cozy-app-publish package using yarn or npm : yarn add cozy-app-publish --dev You can also install the package as a global package, but don\u2019t forget to update it frequently Then use it to publish your application, here is an example for collect : yarn cozy-app-publish \\ --token {{ EDITOR_TOKEN }} \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2-dev.042cef26d9d33ea604fe4364eaab569980b500c9 If you need more information about this tool, you can go to the official cozy-app-publish documentation . Via curl \u00b6 Here we will show the classical way to add a version using curl as reference. But you may need to look at our dedicated tool cozy-app-publish or the Automation CI part of this documentation instead. Prequisites : - For this step, you will need your editor token access generated when you created your editor (see below ). You have to replace all {{EDITOR_TOKEN}} in this documentation by this token. - The communication with the registry is done through HTTP requests for now. So we will use the curl command line tool to register our application here. To add a new version for a registered application, you have to do a POST request with all needed information to the route registryAddress/registry/:appSlug to publish in default space or registryAddress/:space/registry/:appSlug for a named space (see Spaces & Virtual Spaces below) with registryAddress your registry address (for example here http://localhost:8081 ), :appName your application slug (here drive ) and :space your registry space. Let\u2019s add the version 1.0.1 of the Collect application for example: # {{EDITOR_TOKEN}} -> your generated editor access token curl -X \"POST\" \"http://localhost:8081/registry/collect\" \\ -H \"Authorization: Token {{EDITOR_TOKEN}}\" \\ -H \"Content-Type: application/json\" \\ -d $'{ \"url\": \"https://github.com/cozy/cozy-collect/archive/1.0.1.tar.gz\", \"sha256\": \"96212bf53ab618808da0a92c7b6d9f2867b1f9487ba7c1c29606826b107041b5\", \"version\": \"1.0.1\", }' Field Description url the archive source of your application, it will be downloaded and checked with the sha256 property sha256 the sha256 hash of your source archive matching the archive in url (see the notice below) version version of the application, must match the one in the manifest (see the notice below) Important notices: The version must match the one in the manifest.webapp file for stable release. For beta (X.X.X-betaX) or dev releases (X.X.X-dev.hash256), the version before the cyphen must match the one in the manifest.webapp . If version starts with the v letter (like v1.2.3 ), then the v letter is silently stripped from version, allowing you to simply publish according to tag name if your tags are labelled vx.y.z . For better integrity, the sha256 provided must match the sha256 of the archive provided in url . If it\u2019s not the case, that will be considered as an error and the version won\u2019t be registered. Spaces & Virtual Spaces \u00b6 Spaces \u00b6 You can divide your applications between several isolated places, called spaces . When an application and its versions are published in a space , they are only reachable in that one (you can consider a space like a entire sub-part of the registry). It is espacially useful for splitting up applications by logical topics. Most of the CLI and API endpoints have a space option. You can refer to the documentation or CLI help to view all available parameters. Create a space \u00b6 Spaces are defined in the config file and are automatically created during registry launching. Add a space entry, followed by your spaces names, and let the registry do the work: spaces : __default__ myspace foospace Remove a space \u00b6 To remove a space, you have to clean all the remaining apps & versions before removing the space entry name. A CLI is available for the job: $ cozy-apps-registry rm-space Example: $ cozy-apps-registry rm-space foobar Warning: You are going to remove space foobar and all its applications. This action is irreversible. Please enter the space name to confirm: foobar Removing app1/0.7.3-dev.f26bf2b8db3da459071a074a1367ce36e78bb34c Removing app1/0.7.3-dev.cf1efba4c1b6dd08bb5857f5752790f0d2663d6d Removing app1/0.7.3-dev.0bbd57a6ce50af82cfbefb8c231fbfe04516e742 Removing app1/0.7.3-dev.21338229a0c2317dc0f3b94e92b22a367f84c537 Removing app1/0.7.3-dev.08ab3624136fb70dc996003aebc3049af51f7438 Removing app1/0.7.3-dev.4e9d174a3b01acaf8a44b561455efc3f34871142 Removing app1/0.7.3-dev.b2654bf00be393aa611fcbb7f70a8ef671895a84 Removing app1/0.7.3-dev.860861868a5dfe294c7120d81fa9feb5387bb57f Removing app2/0.1.9-dev.954dac9e12e080d591cb76591c311611fed1bea9 You can now delete the name from your config file. Virtual Spaces \u00b6 A virtual space is necessarily built over an existing space . It allows to filter by selecting or rejecting applications available on the underlying space. Please note that it is not possible to publish applications or versions on a virtual space . It is possible to change the name of an application in the virtual space, without changing it in the underlying space, with the cozy-apps-registry overwrite-app-name command. The same thing is possible for the icon with cozy-apps-registry overwrite-app-icon . And the maintenance status can also be changed in the virtual space with the cozy-apps-registry maintenance commands. That\u2019s all for the moment. Automation (CI) \u00b6 The following tutorial explains how to connect your continuous integration based on Travis to automatically publish new versions on the apps registry. In this tutorial, we assume: you have a token allowing you to publish applications for your editor : {{EDITOR_TOKEN}} you are working on a repository plugged on travis and named on github myname/cozy-example You first need to add the token to your travis configuration file .travis.yml . To do so, you need the travis utility to encrypt its value. $ travis encrypt REGISTRY_TOKEN ={{ EDITOR_TOKEN }} -r myname/cozy-example --org Please add the following to your .travis.yml file: secure: \"jUAjk..LOOOOONG_ENCRYPTED_STRING.....jdk89=\" Like said, you need to add this block of ciphered data in the .travis.yml (if it\u2019s not already done automatically). This will allow you to use the REGISTRY_TOKEN variable in your deployment script. Then, you can add the publish script in your package.json in order to be used by Travis: ... \"publish:cozy\" : \"git fetch origin ${DEPLOY_BRANCH:-build}:${DEPLOY_BRANCH:-build} && cozy-app-publish --token $REGISTRY_TOKEN --build-commit $(git rev-parse ${DEPLOY_BRANCH:-build})\" ... This script will fetch your last commit from the build branch to publish to the registry. If you push a tag, be sure to wait the last build branch Travis build finished in order to have the real last commit to publish. Finally, you can add this script to your .travis.yml to publish your app using our publishing tool cozy-app-publish during the deploy process: ... before_deploy: - yarn add cozy-app-publish deploy: - provider: script repo: myname/cozy-example skip-cleanup: true script: export DEPLOY_BRANCH=build && yarn deploy && yarn publish:cozy on: branch: master - provider: script repo: myname/cozy-example skip-cleanup: true script: export DEPLOY_BRANCH=build && yarn publish:cozy on: tags: true ... Important notices: A commit push to the branch master will publish your application in the dev channel of the registry. A tag push (Github release) will publish a stable version (ex: 1.0.0 ) or a beta version (ex: 1.0.1-beta2 ) to the registry (automatically handled by the registry). cozy-app-publish will use the github archive URL computing to get the application tarball. If your applicaiton is not on Github, you may need to use the manual mode of the command. Access control and tokens \u00b6 The read-only routes of the registry are all public and do not require any access-control. However routes allowing to create applications and versions have access-control policies associated to them. The registry has two types of access permissions, that are associated to two different tokens: editor tokens : these tokens give access to the publication of new versions on the registry, for a specific editor name, at these conditions: the version\u2019s application must already exist in the registry the version\u2019s application must have the same \u201ceditor\u201d value as the token master tokens : these tokens are allowed to create and register new applications on the registry, and associate them with an existing editor name. They also have the same accesses as the editor tokens. Editor tokens can be specific to one or more applications names that they are allowed to publish. In order to create tokens, the binary offers a gen-token command-line. Here are some examples to illustrates some usages: # Generating tokens # generate an editor token for the editor \"cozy\", for any application $ cozy-apps-registry gen-token cozy # generate an editor token for the editor \"cozy\" expiring after 30 days $ cozy-apps-registry gen-token cozy --max-age 30d # generate an editor token for the editor \"cozy\" for application \"collect\" and \"drive\" $ cozy-apps-registry gen-token cozy --apps collect,drive # generate a master token associated with the editor \"cozy\" expiring after 30 days $ cozy-apps-registry gen-token cozy --master --max-age 30d # Verifying tokens # verify the editor token \"XXX\" for the editor \"cozy\" $ cozy-apps-registry verify-token cozy \"XXX\" # verify the master token \"XXX\" associated with the editor \"cozy\" $ cozy-apps-registry verify-token cozy \"XXX\" --master # Revoking tokens # revoke all editors tokens for the cozy editor $ cozy-apps-registry revoke-tokens cozy # revoke all master tokens associated with the cozy editor $ cozy-apps-registry revoke-tokens cozy --master Maintenance \u00b6 In order to set/unset an application into maintenance mode, the binary offers a maintenance command-line. Here are some examples of how to use it: # Activate maintenance mode for the application 'bank' of space 'myspace' # Available flagged options: # --infra specify a maintenance specific to our infra # --no-manual-exec specify a maintenance disallowing manual execution # --short specify a short maintenance $ cozy-apps-registry maintenance activate bank --space myspace # Deactivate maintenance mode for the application 'bank' of space 'myspace' $ cozy-apps-registry maintenance deactivate bank --space myspace Or using a cURL request and a master token: curl -XPUT \\ -H \"Authorization: Token $COZY_REGISTRY_ADMIN_TOKEN \" \\ -H \"Content-Type: application/json\" \\ -d '{\"flag_infra_maintenance\": false,\"flag_short_maintenance\": false,\"flag_disallow_manual_exec\": false,\"messages\": {\"fr\": {\"long_message\": \"Bla bla bla\",\"short_message\": \"Bla\"},\"en\": {\"long_message\": \"Yadi yadi yada\",\"short_message\": \"Yada\"}}}' \\ https://apps-registry.cozycloud.cc/myspace/registry/maintenance/bank/activate curl -XPUT \\ -H \"Authorization: Token $COZY_REGISTRY_ADMIN_TOKEN \" \\ https://apps-registry.cozycloud.cc/registry/maintenance/bank/deactivate Import/export \u00b6 CouchDB & Swift can be exported into a single archive with cozy-apps-registry export . Registry data are exported as below: registry/couchdb/{db}/{uuid}.json : CouchDB document exported as JSON registry/swift/{file/path} : Swift document, with the following tar custom metadata COZY.content-type : associated content type The generated archive can be imported with cozy-apps-registry import -d . The -d option will drop CouchDB databases and Swift containers related to declared spaces on the registry configuration. Application confidence grade / labelling \u00b6 The confidence grade of an applications can be specified by specifying the data_usage_commitment and data_usage_commitment_by fields of the application document. Possible values for these properties are: data_usage_commitment : specify a technical commitment from the application editor: user_ciphered : technical commitment that the user\u2019s data is encrypted and can only be known by him. user_reserved : commitment that the data is only used for the user, to directly offer its service. none : no commitment data_usage_commitment_by : specify what entity is taking the commitment: cozy : the commitment is taken by cozy editor : the commitment is taken by the application\u2019s editor none : no commitment is taken To do that, a command line and admin API are available, and be used as follow: $ cozy-apps-registry modify-app banks --space my_space --data-usage-commitment user_reserved --data-usage-commitment-by editor Or using a cURL request and a master token: curl -XPATCH \\ -H\"Authorization: Token $COZY_REGISTRY_ADMIN_TOKEN\" \\ -H\"Content-Type: application/json\" \\ -d'{\"data_usage_commitment\": \"user_reserved\", \"data_usage_commitment_by\": \"editor\"} https://apps-registry.cozycloud.cc/my_space/registry/banks Universal links \u00b6 The registry can manage Universal links . Configuration \u00b6 Config file \u00b6 Each space holds its own files. The space determination is based on the request host, so you must bind a domain to a space in the config file. domain_space : mycloud.com : \"__default__\" cloud.foobar.com : \"foobar\" Files \u00b6 Place your files (e.g apple-app-site-association ) in the space container. The file must be prepended with universallink/ For the foobar space and file apple-app-site-association , the file has to be named universallink/apple-app-site-association and placed in the foobar container Usage \u00b6 The following endpoint is available to get any file: http:///.well-known/:filename You can now query your endpoint to get your file: curl -X GET http://cloud.foobar.com/.well-known/apple-app-site-association { \"applinks\" : { \"apps\" : [] , \"details\" : [ { \"appID\" : \"3AKXFMV43J.io.cozy.drive.mobile\" , \"paths\" : [ \"/drive\" ] } , { \"appID\" : \"3AKXFMV43J.io.cozy.banks.mobile\" , \"paths\" : [ \"/banks\" ] } , { \"appID\" : \"3AKXFMV43J.io.cozy.photos.mobile\" , \"paths\" : [ \"/photos\" ] } ] } } Budget-Insight web auth \u00b6 For some banks integration (Paypal, Orange Bank, Revolut\u2026), Budget-Insight need something similar to universal link because they expect a static domain for fallback but there is a specific domain per Cozy instance. In contrast with universal links, query parameters (provided by BI) are propagated to the final fallback redirection. http:///biwebauth?fallback=http%3A%2F%2Fa.cozy%3Ffoo%3Dfoo&bar=bar redirect to http://a.cozy?foo=foo&bar=bar , merging fallback provided query parameters ( foo=foo ) with webauth provided ones ( bar=bar ). Community \u00b6 You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter", "title": "Registry server"}, {"location": "cozy-apps-registry/#cozy-apps-registry", "text": "", "title": "cozy-apps-registry"}, {"location": "cozy-apps-registry/#whats-cozy", "text": "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\u2019s tracking you.", "title": "What's Cozy?"}, {"location": "cozy-apps-registry/#table-of-contents", "text": "cozy-apps-registry What\u2019s Cozy? Table of contents What about this repository? How to develop with a cozy-apps-registry working in local environment 1) Install and configure the local cozy-apps-registry 2) Configure the registry with cozy-registry.yml 3) Run the registry to serve the apps 4) Create an editor 5) Configure cozy-stack with the registry Publish your application on the registry 1) Define your application manifest Properties meaning (reference) Available manifest\u2019s features list : Translated manifest fields Application terms Konnectors folders handling Konnectors fields property Konnectors message property Categories and Data types 2) Add a new application in the registry Our official apps registry Custom registry 3) Add a new version of a registered application Via cozy-app-publish (highly recommanded) Via curl Spaces & Virtual Spaces Spaces Create a space Remove a space Virtual Spaces Automation (CI) Access control and tokens Maintenance Import/export Application confidence grade / labelling Universal links Configuration Config file Files Usage Budget-Insight web auth Community", "title": "Table of contents"}, {"location": "cozy-apps-registry/#what-about-this-repository", "text": "The cozy-apps-registry is a go project that implements the registry API described to work with the cozy-stack . To work properly, it requires: Go >= 1.18 Couchdb >= 3.2 Redis Openstack Object Storage (Swift)", "title": "What about this repository?"}, {"location": "cozy-apps-registry/#how-to-develop-with-a-cozy-apps-registry-working-in-local-environment", "text": "Before starting, you will need to have a couchdb running already. That can be the one used by the local cozy-stack if you have one. For this tutorial, couchdb will be running on the default port 5984. You also must have redis and an OpenStack Object Storage (Swift) up and running. You can follow install instructions on the official website", "title": "How to develop with a cozy-apps-registry working in local environment"}, {"location": "cozy-apps-registry/#1-install-and-configure-the-local-cozy-apps-registry", "text": "Since this is a golang project, you can install it using go with the followed command: go get -u github.com/cozy/cozy-apps-registry cd $GOPATH /src/github.com/cozy/cozy-apps-registry/ Then you will need a session secret key to run the registry (this key will be store in the sessionsecret.key file of your working directory) using a password: cozy-apps-registry gen-session-secret --passphrase sessionsecret.key This password is important, you will need it to run the cozy-apps-registry again later. If you lose it, you will have to start again these steps.", "title": "1) Install and configure the local cozy-apps-registry"}, {"location": "cozy-apps-registry/#2-configure-the-registry-with-cozy-registryyml", "text": "Before running the registry, you have to configure it correctly. Don\u2019t worry, here is the yaml file to copy and paste in your cozy-registry.yml (should be in the root folder of cozy-apps-registry/ ): You can find an example of this configuration file at the root of the directory. # server host (serve command) - flag --host host : \"localhost\" # server port (serve command) - flag --port port : 8081 couchdb : # CouchDB server url - flag --couchdb-url url : http://localhost:5984 # CouchDB user - flag --couchdb-user user : '' # CouchDB password - flag --couchdb-password password : '' # CouchDB prefix for the registries databases - flag --couchdb-prefix prefix : registry1 swift : # Swift auth URL (provided by keystone) auth_url : http://172.28.128.3/identity/v3 # Swift username username : admin # Swift password api_key : secret # Endpoint type (public/admin/internal) endpointy_type : public # Project name tenant : demo # Swift domain domain : default # Path to the session secret file containing the master secret to generate # session token. # # Should be generated with the \"gen-session-secret\" command. session-secret : sessionsecret.key Feel free to change it if some configurations change in your case (the couchdb user, the server parameters or the databases prefix for example). Notices: Here the generated session token (step 1) is stored in the sessionsecret.key file of the working directory, this is so the value of the property session-secret at the end of the configuration file. By default, the local couchdb allow all admin accesses without creating users, so there is no user and password here. But if an admin user has been created, you have to use the properties user and password in the couchdb part to provide these informations. It\u2019s also possible to use env variables for configuration. You can take the key from the configuration file and add the COZY_REGISTRY prefix. For example, you can run: COZY_REGISTRY_PORT = 8081 cozy-apps-registry serve There is also the REGISTRY_SESSION_PASS env variable for the password for the session secret.", "title": "2) Configure the registry with cozy-registry.yml"}, {"location": "cozy-apps-registry/#3-run-the-registry-to-serve-the-apps", "text": "Run the registry using this followed command (here our configuration file is a cozy-registry.yml in the current working directory): cozy-apps-registry serve -c cozy-registry.yml At this step, you should have a cozy-apps-registry running and ready for the development. If you runnig the registry for the first time you can see the next steps to create a new editor and to configure your local cozy-stack to run with this new registry. The -c options is always mandatory if you want to specify a config file like here.", "title": "3) Run the registry to serve the apps"}, {"location": "cozy-apps-registry/#4-create-an-editor", "text": "This step is required to submit new applications in the registry. In another terminal, run these commands to create an editor (the one that will submit the application(s)) and generate an access token: cozy-apps-registry add-editor Cozy -c cozy-registry.yml cozy-apps-registry gen-token --master Cozy -c cozy-registry.yml Here we go, you have now an registry ready and running on the 8081 port. The -c options is always mandatory if you want to specify a config file like here.", "title": "4) Create an editor"}, {"location": "cozy-apps-registry/#5-configure-cozy-stack-with-the-registry", "text": "On the cozy-stack , you have to add the new registry in the stack configuration file cozy.yaml (registries property): ... registries : default : - http://localhost:8081/ ... Now restart your local cozy-stack to take this new configuration in consideration (stop and run again cozy-stack serve ) and you\u2019re ready to work with the cozy-apps-registry !", "title": "5) Configure cozy-stack with the registry"}, {"location": "cozy-apps-registry/#publish-your-application-on-the-registry", "text": "If you need more details about the registry you can go to the official registry documentation Important: In this whole documentation, by the term application , we mean a web application or a konnector. Indeed, for the registry, all entities are applications and they can be either webapp or konnector type.", "title": "Publish your application on the registry"}, {"location": "cozy-apps-registry/#1-define-your-application-manifest", "text": "To be publishable, your application requires some informations in its manifest.webapp , the manifest of a Cozy application. You can find an example of manifest for an application in Cozy-Drive and one for a konnector in cozy-konnector-trainline . Most properties are common to both applications and konnectors but platforms, screenshots, services, routes and intents are only used in applications. Properties oauth, data_types, doctypes, fields, frequency, language, messages, parameters, time_interval, uuid and vendor_link ar only used in konnectors.", "title": "1) Define your application manifest"}, {"location": "cozy-apps-registry/#properties-meaning-reference", "text": "Here are all properties meaning for the manifest file (for webapp and konnectors) sorted alphabetically: Field Description aggregator Object containing aggregator data. Typically { accountId: 'aggregator-service' } . categories array of categories for your apps (see authorized categories), it will be ['others'] by default if empty data_types (konnector specific) Array of the data type the konnector will manage developer name and url for the developer editor the editor\u2019s name to display on the cozy-bar ( REQUIRED ) fields (konnector specific) JSON object describing the fields need by the konnector ( except folder path ). Used to generate a form. See below folders (konnector specific) A list of folders required by the konnector to store files according to datatype (see the specific documentation below ) frequency (konnector specific) A human readable value between monthly , weekly , daily , hourly , indicating the interval of time between two runs of the konnector. Default: weekly . icon path to the icon for the home (path in the build) intents (application specific) a list of intents provided by this app (see cozy-stack intents doc for more details) langs Languages available in your app (can be different from locales) language (konnector specific) the konnector development language used (ex: node ) license the SPDX license identifier locales an object with language slug as property, each name property is an object of localized informations (see the second part below) manifest_version The current manifest version used. This is a versioning for the manifest and allow better retrocompatiblity when processing app manifest messages (konnector specific) Array of message identifiers, which can be used by application to display information at known areas. See example below . mobile (application specific) JSON object containing information about app\u2019s mobile version (see cozy-stack routes doc for more details) name the name to display on the home ( REQUIRED ) name_prefix the prefix to display with the name oauth (konnector specific) JSON object containing oAuth information, like scope . If a manifest provides an oauth property, it is considered as an OAuth konnector. Note: scope can be a string or an array. If it is an array, its values will be joined with a space. A false or null value in scope will remove any scope parameter in the request sent to the oauth provider. parameters (konnector specific) Additional parameters which should be passed to the konnector. Used for example for bank konnectors to pass a bankId parameter. partnership an object to provide informations (to display in the Store for example) about a partnership related to the application ( icon description , name and domain ). It can also be used to trigger alternative konnector connection policies for some vendors (see the budget-insight konnector policy in cozy-harvest ). permissions a map of permissions needed by the app (see see cozy-stack permissions doc for more details) platforms (application specific) List of objects for platform native applications. For now there are only two properties: type (i.e. 'ios' or 'linux' ) and the optional url to reach this application page. routes (application specific) a map of routes for the app (see cozy-stack routes doc for more details) ( REQUIRED ) screenshots an array of paths to the screenshots of the application (paths in the build) services (application specific) a map of the services associated with the app (see cozy-stack services doc for more details) slug the default slug that should never change (alpha-numeric lowercase) ( REQUIRED ) source where the files of the app can be downloaded (by default it will look for the branch build ) terms an object defining properties for terms that need to be displayed/accepted by the user when installing the application ( more-info-below ) time_interval (konnector specific) By defaults, konnector triggers are scheduled randomly between 00:00 AM and 05:00 AM. Those two values can be overwritten thanks to this property, by passing an array containing two values: first is the interval start hour, second is the interval end hour. Example: [15, 21] will randomly schedule the konnector trigger between 15:00 (03:00 PM) and 21:00 (09:00 PM). The time zone used is GMT. type type of application ( konnector or webapp ) ( REQUIRED ) version the current version number ( REQUIRED ) vendor_link (konnector specific) URL to editor or service website qualification_labels (konnector specific) Array of one or more labels from the Cozy Client\u2019s qualifications list to associate with the files the konnector will receive from the website. features (konnector specific) Array of features added in the konnector from the list below.", "title": "Properties meaning (reference)"}, {"location": "cozy-apps-registry/#available-manifests-features-list", "text": "2FA Two Factors identification. BILLS Import bills documents, doctype \u201cio.cozy.bills\u201d. FILES Import files documents, doctype \u201cio.cozy.files\u201d. CAPTCHA_RESOLUTION The konnector using a captcha resolution process. CARBON_COPY The konnector import legally true copy of the original files. DOC_QUALIFICATION The konnector uses the first version of files qualifications, you may stumble upon on some konnectors wich hasn\u2019t been treated. DOC_QUALIFICATION_V2 The konnector uses new version (last one for now) of files qualifications. ELECTRONIC_SAFE Files comes from a known electronic safe. HEALTH The konnector treat health documents HTML_TO_PDF The konnector needs to convert HTML page(s) to make pdf files. IDENTITY The konnector create identity(ies) for doctype \u201cio.cozy.identities\u201d LOGIN_OK The konnector deactivate the auto-notification METADATA_DEDUP The konnector uses a fileIdAttribute as detection to avoid deduplication. VENDOR_REF The konnector uses. SENTRY_V2 The konnector had been migrated (or packaged) to sentry V2 (errors.cozycloud.cc) Notices: All images paths ( icon , partnership.icon and screenshots ) should be relative to the build directory. For example, here, the icon.svg is stored in the build root directory and all screenshots are store in a folder screenshots in the build directory. Therefore, if you use a bundler (like webpack) be sure to know exactly where the bundler will store these assets in the build directory (and change it in the manifest if needed). All properties in locales objects will override the matched property of the main manifest.webapp body, if a property is not found in locales it will fallback to the main body one. We use to have the en locale as default one if the one wanted by the user doesn\u2019t exist. Be sure to have, at least, that locale complete with the name and all descriptions. In your build files, this manifest.webapp file must be at the root.", "title": "Available manifest\u2019s features list :"}, {"location": "cozy-apps-registry/#translated-manifest-fields", "text": "Here are the properties that you can override using locales (we recommand to automatically build these properties according to your locales files if you\u2019re using a translating tool like transifex ): name , the app\u2019s name short_description , short description of what the app do long_description , longer and more complete description of the app behaviour changes , description of your new version of the konnector or all changes since the last version fields , An object containing translations for fields. screenshots folders { \"fields\" : { \"email\" : { \"type\" : \"email\" } }, \"locales\" : { \"en\" : { \"short_description\" : \"Collect your Orange's bills\" , \"fields\" : { \"email\" : { \"label\" : \"Identifier (your email)\" } } }, \"fr\" : { \"short_description\" : \"R\u00e9cup\u00e8re vos factures Orange\" , \"fields\" : { \"email\" : { \"label\" : \"Identifiant (votre adresse mail)\" } } } } }", "title": "Translated manifest fields"}, {"location": "cozy-apps-registry/#application-terms", "text": "You can provide a related terms property if you want to display and make the user accept some terms (ToS for example) just before installing the application. Here are all properties allowed and used: url , the URL of the terms/contract to redirect the user to ( REQUIRED ) version : A specific version of the terms, we need it handle terms updates and ask the user again to accept the update. The special characters [*+~.()'\"!:@] are not allowed here. ( REQUIRED ) id : An id for the terms. When accepting terms, we store in io.cozy.terms , a document containing the id and version so that we know which terms have been accepted, and show the user a modal if the terms have not been accepted yet. The special characters [*+~.()'\"!:@] are not allowed here. ( REQUIRED )", "title": "Application terms"}, {"location": "cozy-apps-registry/#konnectors-folders-handling", "text": "The folders property is a list of objects with these following properties: defaultDir : ( REQUIRED ) The default root directory of your folder. In this folder will automatically be created a subfolder with the konnector name and into this latter a subfolder with the account name to store the related files. Here you can use some variables in the path like the following: $administrative : Folder which will receive all administrative related files (bills, contracts, invoices\u2026) $photos : Folder which will receive all photos $konnector : The name of the konnector All paths provided using defaultDir will be the root directory, not the final folder which will receive the files. For example, if you set $photos , the final folder will be $photos/$konnector/$account in order to keep them always sorted by konnectors and accounts.", "title": "Konnectors folders handling"}, {"location": "cozy-apps-registry/#konnectors-fields-property", "text": "The fields property is a JSON object describing the input fields needed to generate the konnector\u2019s configuration form. A typical example will be: { \"fields\" : { \"identifier\" : { \"type\" : \"text\" }, \"secret\" : { \"type\" : \"password\" } } } The keys of the fields object are the name/id of the fields. They will be passed as parameters to the konnector at every run. Each fields may also have the following properties: Property Description identifier (Boolean) indicating if the field is the main identifier. By default, the login field is the identifier. Default value is false and there can be only one identifier advanced Indicates if the field should be displayed in the \u201cadvanced\u201d area of the form (default: false ) default Default value. It can a string for a text field, or an object for a select field ( \"default\": {\"value\": \"foo\",\"name\": \"bar\"}, ) description Field description, as a locale key. label Predefined label. This value must match a locale key provided by Cozy-Home. Example: With label: \"identifier\" , Cozy-Home will use the locale key account.form.label.identifier . Translations for these fields use the locales property in the manifest. max Maximum length of the value (number of characters) min Minimum length of the value (number of characters) options When the field is a dropdown, list of available options pattern Define a regex used to validate the field. isRequired Boolean indicating if the field is required or not (default true ) type Required . Field type from dropdown , email , hidden , password , text , checkbox .", "title": "Konnectors fields property"}, {"location": "cozy-apps-registry/#konnectors-message-property", "text": "Messages are a common way to provide custom information to display in application. An app like cozy-home should have some specific area to display custom messages provided by the konnector. Example: // The final example will be available after the implementation of the whole mechanism, // but here is the global idea: { installSuccess && < p >{ t ( 'home.konnector.install.success.message' )} } { installSuccess && konnector . manifest . messages . includes ( 'success_message' ) && < p >{ t ( 'konnector.manifest.locales.messages.success_message' )} }", "title": "Konnectors message property"}, {"location": "cozy-apps-registry/#categories-and-data-types", "text": "Categories are slugs from the following list: banking clouds cozy education energy finance health host_provider insurance isp mes_infos online_services partners press pro productivity ptnb public_service shopping social tech telecom transport Data types are slugs from the following list: activity appointment bankTransactions bankAccounts bill bloodPressure calendar certificate commit consumption contact contract courseMaterial document event family geopoint heartbeat home phonecommunicationlog podcast profile refund sinister sleepTime stepsNumber temperature travelDate tweet videostream weight", "title": "Categories and Data types"}, {"location": "cozy-apps-registry/#2-add-a-new-application-in-the-registry", "text": "", "title": "2) Add a new application in the registry"}, {"location": "cozy-apps-registry/#our-official-apps-registry", "text": "Official registry URL: https://apps-registry.cozycloud.cc In order to use our official repository, you need a token for a specific editor. To do so, contact us directly at the address contact@cozycloud.cc with a mail using the following title prefix: [registry] and provide us these folowing information (not changeable after): - slug of your application - editor name that you want We will provide you with the correct token.", "title": "Our official apps registry"}, {"location": "cozy-apps-registry/#custom-registry", "text": "See the details below to know how to add a new application in a custom cozy-apps-registry instance (local or not). Prequisites : - For this step, you will need your editor token access generated when you created your editor (see below ). You have to replace all {{EDITOR_TOKEN}} in this documentation by this token. - The communication with the registry is done through HTTP requests for now. So we will use the curl command line tool to register our application here. Now you can add your application in the registry. This step is splitted in two septs: - Add a new application (without versions) - Add a version of the application A new application without registered version won\u2019t be displayed by the cozy-store application . To add a new application, you have to do a POST request which all the informations needed to the route registryAddress/registry with registryAddress your registry address (for example here http://localhost:8081 ). Let\u2019s add the Collect application as example: # {{EDITOR_TOKEN}} -> your generated editor access token curl -X \"POST\" \"http://localhost:8081/registry\" \\ -H \"Authorization: Token {{EDITOR_TOKEN}}\" \\ -H \"Content-Type: application/json\" \\ -d $'{ \"slug\": \"collect\", \"type\": \"webapp\", \"editor\": \"{{EDITOR}}\" }' Field Description slug your application unique ID type kind of application (it can be only webapp or konnector ) editor Name of the editor matching the {{EDITOR_TOKEN}} Here the slug is the unique ID of the application in the registry, so it can\u2019t be changed after the application is already registered.", "title": "Custom registry"}, {"location": "cozy-apps-registry/#3-add-a-new-version-of-a-registered-application", "text": "Please note that an application bundle cannot be larger than 20MB (hardcoded value). This limitation has been implemented to encourage better web application development practices because in general the larger the application bundle is, the worst the performance and user experience will be.", "title": "3) Add a new version of a registered application"}, {"location": "cozy-apps-registry/#via-cozy-app-publish-highly-recommanded", "text": "Here we will show the classical way to add a version using the manual mode of cozy-app-publish as reference. But you may need to look at the Automation CI part of this documentation instead. Prequisites : For this step, you will need your editor token access generated when you created your editor (see below ). You have to replace all {{EDITOR_TOKEN}} in this documentation by this token. Don\u2019t forget to build your application first (run yarn build ), cozy-app-publish will read the manifest from your build Firstly, install the cozy-app-publish package using yarn or npm : yarn add cozy-app-publish --dev You can also install the package as a global package, but don\u2019t forget to update it frequently Then use it to publish your application, here is an example for collect : yarn cozy-app-publish \\ --token {{ EDITOR_TOKEN }} \\ --build-url https://github.com/cozy/cozy-collect/archive/042cef26d9d33ea604fe4364eaab569980b500c9.tar.gz \\ --manual-version 1.0.2-dev.042cef26d9d33ea604fe4364eaab569980b500c9 If you need more information about this tool, you can go to the official cozy-app-publish documentation .", "title": "Via cozy-app-publish (highly recommanded)"}, {"location": "cozy-apps-registry/#via-curl", "text": "Here we will show the classical way to add a version using curl as reference. But you may need to look at our dedicated tool cozy-app-publish or the Automation CI part of this documentation instead. Prequisites : - For this step, you will need your editor token access generated when you created your editor (see below ). You have to replace all {{EDITOR_TOKEN}} in this documentation by this token. - The communication with the registry is done through HTTP requests for now. So we will use the curl command line tool to register our application here. To add a new version for a registered application, you have to do a POST request with all needed information to the route registryAddress/registry/:appSlug to publish in default space or registryAddress/:space/registry/:appSlug for a named space (see Spaces & Virtual Spaces below) with registryAddress your registry address (for example here http://localhost:8081 ), :appName your application slug (here drive ) and :space your registry space. Let\u2019s add the version 1.0.1 of the Collect application for example: # {{EDITOR_TOKEN}} -> your generated editor access token curl -X \"POST\" \"http://localhost:8081/registry/collect\" \\ -H \"Authorization: Token {{EDITOR_TOKEN}}\" \\ -H \"Content-Type: application/json\" \\ -d $'{ \"url\": \"https://github.com/cozy/cozy-collect/archive/1.0.1.tar.gz\", \"sha256\": \"96212bf53ab618808da0a92c7b6d9f2867b1f9487ba7c1c29606826b107041b5\", \"version\": \"1.0.1\", }' Field Description url the archive source of your application, it will be downloaded and checked with the sha256 property sha256 the sha256 hash of your source archive matching the archive in url (see the notice below) version version of the application, must match the one in the manifest (see the notice below) Important notices: The version must match the one in the manifest.webapp file for stable release. For beta (X.X.X-betaX) or dev releases (X.X.X-dev.hash256), the version before the cyphen must match the one in the manifest.webapp . If version starts with the v letter (like v1.2.3 ), then the v letter is silently stripped from version, allowing you to simply publish according to tag name if your tags are labelled vx.y.z . For better integrity, the sha256 provided must match the sha256 of the archive provided in url . If it\u2019s not the case, that will be considered as an error and the version won\u2019t be registered.", "title": "Via curl"}, {"location": "cozy-apps-registry/#spaces-virtual-spaces", "text": "", "title": "Spaces & Virtual Spaces"}, {"location": "cozy-apps-registry/#spaces", "text": "You can divide your applications between several isolated places, called spaces . When an application and its versions are published in a space , they are only reachable in that one (you can consider a space like a entire sub-part of the registry). It is espacially useful for splitting up applications by logical topics. Most of the CLI and API endpoints have a space option. You can refer to the documentation or CLI help to view all available parameters.", "title": "Spaces"}, {"location": "cozy-apps-registry/#create-a-space", "text": "Spaces are defined in the config file and are automatically created during registry launching. Add a space entry, followed by your spaces names, and let the registry do the work: spaces : __default__ myspace foospace", "title": "Create a space"}, {"location": "cozy-apps-registry/#remove-a-space", "text": "To remove a space, you have to clean all the remaining apps & versions before removing the space entry name. A CLI is available for the job: $ cozy-apps-registry rm-space Example: $ cozy-apps-registry rm-space foobar Warning: You are going to remove space foobar and all its applications. This action is irreversible. Please enter the space name to confirm: foobar Removing app1/0.7.3-dev.f26bf2b8db3da459071a074a1367ce36e78bb34c Removing app1/0.7.3-dev.cf1efba4c1b6dd08bb5857f5752790f0d2663d6d Removing app1/0.7.3-dev.0bbd57a6ce50af82cfbefb8c231fbfe04516e742 Removing app1/0.7.3-dev.21338229a0c2317dc0f3b94e92b22a367f84c537 Removing app1/0.7.3-dev.08ab3624136fb70dc996003aebc3049af51f7438 Removing app1/0.7.3-dev.4e9d174a3b01acaf8a44b561455efc3f34871142 Removing app1/0.7.3-dev.b2654bf00be393aa611fcbb7f70a8ef671895a84 Removing app1/0.7.3-dev.860861868a5dfe294c7120d81fa9feb5387bb57f Removing app2/0.1.9-dev.954dac9e12e080d591cb76591c311611fed1bea9 You can now delete the name from your config file.", "title": "Remove a space"}, {"location": "cozy-apps-registry/#virtual-spaces", "text": "A virtual space is necessarily built over an existing space . It allows to filter by selecting or rejecting applications available on the underlying space. Please note that it is not possible to publish applications or versions on a virtual space . It is possible to change the name of an application in the virtual space, without changing it in the underlying space, with the cozy-apps-registry overwrite-app-name command. The same thing is possible for the icon with cozy-apps-registry overwrite-app-icon . And the maintenance status can also be changed in the virtual space with the cozy-apps-registry maintenance commands. That\u2019s all for the moment.", "title": "Virtual Spaces"}, {"location": "cozy-apps-registry/#automation-ci", "text": "The following tutorial explains how to connect your continuous integration based on Travis to automatically publish new versions on the apps registry. In this tutorial, we assume: you have a token allowing you to publish applications for your editor : {{EDITOR_TOKEN}} you are working on a repository plugged on travis and named on github myname/cozy-example You first need to add the token to your travis configuration file .travis.yml . To do so, you need the travis utility to encrypt its value. $ travis encrypt REGISTRY_TOKEN ={{ EDITOR_TOKEN }} -r myname/cozy-example --org Please add the following to your .travis.yml file: secure: \"jUAjk..LOOOOONG_ENCRYPTED_STRING.....jdk89=\" Like said, you need to add this block of ciphered data in the .travis.yml (if it\u2019s not already done automatically). This will allow you to use the REGISTRY_TOKEN variable in your deployment script. Then, you can add the publish script in your package.json in order to be used by Travis: ... \"publish:cozy\" : \"git fetch origin ${DEPLOY_BRANCH:-build}:${DEPLOY_BRANCH:-build} && cozy-app-publish --token $REGISTRY_TOKEN --build-commit $(git rev-parse ${DEPLOY_BRANCH:-build})\" ... This script will fetch your last commit from the build branch to publish to the registry. If you push a tag, be sure to wait the last build branch Travis build finished in order to have the real last commit to publish. Finally, you can add this script to your .travis.yml to publish your app using our publishing tool cozy-app-publish during the deploy process: ... before_deploy: - yarn add cozy-app-publish deploy: - provider: script repo: myname/cozy-example skip-cleanup: true script: export DEPLOY_BRANCH=build && yarn deploy && yarn publish:cozy on: branch: master - provider: script repo: myname/cozy-example skip-cleanup: true script: export DEPLOY_BRANCH=build && yarn publish:cozy on: tags: true ... Important notices: A commit push to the branch master will publish your application in the dev channel of the registry. A tag push (Github release) will publish a stable version (ex: 1.0.0 ) or a beta version (ex: 1.0.1-beta2 ) to the registry (automatically handled by the registry). cozy-app-publish will use the github archive URL computing to get the application tarball. If your applicaiton is not on Github, you may need to use the manual mode of the command.", "title": "Automation (CI)"}, {"location": "cozy-apps-registry/#access-control-and-tokens", "text": "The read-only routes of the registry are all public and do not require any access-control. However routes allowing to create applications and versions have access-control policies associated to them. The registry has two types of access permissions, that are associated to two different tokens: editor tokens : these tokens give access to the publication of new versions on the registry, for a specific editor name, at these conditions: the version\u2019s application must already exist in the registry the version\u2019s application must have the same \u201ceditor\u201d value as the token master tokens : these tokens are allowed to create and register new applications on the registry, and associate them with an existing editor name. They also have the same accesses as the editor tokens. Editor tokens can be specific to one or more applications names that they are allowed to publish. In order to create tokens, the binary offers a gen-token command-line. Here are some examples to illustrates some usages: # Generating tokens # generate an editor token for the editor \"cozy\", for any application $ cozy-apps-registry gen-token cozy # generate an editor token for the editor \"cozy\" expiring after 30 days $ cozy-apps-registry gen-token cozy --max-age 30d # generate an editor token for the editor \"cozy\" for application \"collect\" and \"drive\" $ cozy-apps-registry gen-token cozy --apps collect,drive # generate a master token associated with the editor \"cozy\" expiring after 30 days $ cozy-apps-registry gen-token cozy --master --max-age 30d # Verifying tokens # verify the editor token \"XXX\" for the editor \"cozy\" $ cozy-apps-registry verify-token cozy \"XXX\" # verify the master token \"XXX\" associated with the editor \"cozy\" $ cozy-apps-registry verify-token cozy \"XXX\" --master # Revoking tokens # revoke all editors tokens for the cozy editor $ cozy-apps-registry revoke-tokens cozy # revoke all master tokens associated with the cozy editor $ cozy-apps-registry revoke-tokens cozy --master", "title": "Access control and tokens"}, {"location": "cozy-apps-registry/#maintenance", "text": "In order to set/unset an application into maintenance mode, the binary offers a maintenance command-line. Here are some examples of how to use it: # Activate maintenance mode for the application 'bank' of space 'myspace' # Available flagged options: # --infra specify a maintenance specific to our infra # --no-manual-exec specify a maintenance disallowing manual execution # --short specify a short maintenance $ cozy-apps-registry maintenance activate bank --space myspace # Deactivate maintenance mode for the application 'bank' of space 'myspace' $ cozy-apps-registry maintenance deactivate bank --space myspace Or using a cURL request and a master token: curl -XPUT \\ -H \"Authorization: Token $COZY_REGISTRY_ADMIN_TOKEN \" \\ -H \"Content-Type: application/json\" \\ -d '{\"flag_infra_maintenance\": false,\"flag_short_maintenance\": false,\"flag_disallow_manual_exec\": false,\"messages\": {\"fr\": {\"long_message\": \"Bla bla bla\",\"short_message\": \"Bla\"},\"en\": {\"long_message\": \"Yadi yadi yada\",\"short_message\": \"Yada\"}}}' \\ https://apps-registry.cozycloud.cc/myspace/registry/maintenance/bank/activate curl -XPUT \\ -H \"Authorization: Token $COZY_REGISTRY_ADMIN_TOKEN \" \\ https://apps-registry.cozycloud.cc/registry/maintenance/bank/deactivate", "title": "Maintenance"}, {"location": "cozy-apps-registry/#importexport", "text": "CouchDB & Swift can be exported into a single archive with cozy-apps-registry export . Registry data are exported as below: registry/couchdb/{db}/{uuid}.json : CouchDB document exported as JSON registry/swift/{file/path} : Swift document, with the following tar custom metadata COZY.content-type : associated content type The generated archive can be imported with cozy-apps-registry import -d . The -d option will drop CouchDB databases and Swift containers related to declared spaces on the registry configuration.", "title": "Import/export"}, {"location": "cozy-apps-registry/#application-confidence-grade-labelling", "text": "The confidence grade of an applications can be specified by specifying the data_usage_commitment and data_usage_commitment_by fields of the application document. Possible values for these properties are: data_usage_commitment : specify a technical commitment from the application editor: user_ciphered : technical commitment that the user\u2019s data is encrypted and can only be known by him. user_reserved : commitment that the data is only used for the user, to directly offer its service. none : no commitment data_usage_commitment_by : specify what entity is taking the commitment: cozy : the commitment is taken by cozy editor : the commitment is taken by the application\u2019s editor none : no commitment is taken To do that, a command line and admin API are available, and be used as follow: $ cozy-apps-registry modify-app banks --space my_space --data-usage-commitment user_reserved --data-usage-commitment-by editor Or using a cURL request and a master token: curl -XPATCH \\ -H\"Authorization: Token $COZY_REGISTRY_ADMIN_TOKEN\" \\ -H\"Content-Type: application/json\" \\ -d'{\"data_usage_commitment\": \"user_reserved\", \"data_usage_commitment_by\": \"editor\"} https://apps-registry.cozycloud.cc/my_space/registry/banks", "title": "Application confidence grade / labelling"}, {"location": "cozy-apps-registry/#universal-links", "text": "The registry can manage Universal links .", "title": "Universal links"}, {"location": "cozy-apps-registry/#configuration", "text": "", "title": "Configuration"}, {"location": "cozy-apps-registry/#config-file", "text": "Each space holds its own files. The space determination is based on the request host, so you must bind a domain to a space in the config file. domain_space : mycloud.com : \"__default__\" cloud.foobar.com : \"foobar\"", "title": "Config file"}, {"location": "cozy-apps-registry/#files", "text": "Place your files (e.g apple-app-site-association ) in the space container. The file must be prepended with universallink/ For the foobar space and file apple-app-site-association , the file has to be named universallink/apple-app-site-association and placed in the foobar container", "title": "Files"}, {"location": "cozy-apps-registry/#usage", "text": "The following endpoint is available to get any file: http:///.well-known/:filename You can now query your endpoint to get your file: curl -X GET http://cloud.foobar.com/.well-known/apple-app-site-association { \"applinks\" : { \"apps\" : [] , \"details\" : [ { \"appID\" : \"3AKXFMV43J.io.cozy.drive.mobile\" , \"paths\" : [ \"/drive\" ] } , { \"appID\" : \"3AKXFMV43J.io.cozy.banks.mobile\" , \"paths\" : [ \"/banks\" ] } , { \"appID\" : \"3AKXFMV43J.io.cozy.photos.mobile\" , \"paths\" : [ \"/photos\" ] } ] } }", "title": "Usage"}, {"location": "cozy-apps-registry/#budget-insight-web-auth", "text": "For some banks integration (Paypal, Orange Bank, Revolut\u2026), Budget-Insight need something similar to universal link because they expect a static domain for fallback but there is a specific domain per Cozy instance. In contrast with universal links, query parameters (provided by BI) are propagated to the final fallback redirection. http:///biwebauth?fallback=http%3A%2F%2Fa.cozy%3Ffoo%3Dfoo&bar=bar redirect to http://a.cozy?foo=foo&bar=bar , merging fallback provided query parameters ( foo=foo ) with webauth provided ones ( bar=bar ).", "title": "Budget-Insight web auth"}, {"location": "cozy-apps-registry/#community", "text": "You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter", "title": "Community"}, {"location": "cozy-apps-registry/CONTRIBUTING/", "text": "How to contribute to the Cozy Registry v3? \u00b6 Thank you for your interest in contributing to Cozy! There are many ways to contribute, and we appreciate all of them. Security Issues \u00b6 If you discover a security issue, please bring it to their attention right away! Please DO NOT file a public issue, instead send your report privately to security AT cozycloud DOT cc. Security reports are greatly appreciated and we will publicly thank you for it. We currently do not offer a paid security bounty program, but are not ruling it out in the future. Bug Reports \u00b6 While bugs are unfortunate, they\u2019re a reality in software. We can\u2019t fix what we don\u2019t know about, so please report liberally. If you\u2019re not sure if something is a bug or not, feel free to file a bug anyway. Opening an issue is as easy as following this link and filling out the fields. Here are some things you can write about your bug: A short summary What did you try, step by step? What did you expect? What did happen instead? What is the version of the Cozy Stack? Pull Requests \u00b6 Workflow \u00b6 Pull requests are the primary mechanism we use to change Cozy. GitHub itself has some great documentation on using the Pull Request feature. We use the \u2018fork and pull\u2019 model described there. Step 1: Fork \u00b6 Fork the project on GitHub and check out your copy locally: $ git clone https://github.com/cozy/cozy-apps-registry.git $ cd cozy-apps-registry $ git remote add fork git://github.com/username/cozy-apps-registry.git Step 2: Branch \u00b6 Create a branch and start hacking: $ git checkout -b my-branch -t origin/master Step 3: Code \u00b6 Well, I think you know how to do that. Just be sure to follow the coding guidelines from the Go community (gofmt, Effective Go , comment the code, etc.). Step 4: Test \u00b6 Don\u2019t forget to add tests and be sure they are green: $ go test -v Step 5: Commit \u00b6 Writing good commit messages is important. A commit message should describe what changed and why. Step 6: Rebase \u00b6 Use git pull --rebase , or git rebase (but not git merge ), to sync your work from time to time: $ git pull origin master --rebase Step 7: Push \u00b6 $ git push fork my-branch Go to https://github.com/username/cozy-apps-registry and select your branch. Click the \u2018Pull Request\u2019 button and fill out the form. Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in a separate commit and push that to your branch. Community \u00b6 You can help us by making our community even more vibrant. For example, you can write a blog post, take some videos, answer the questions on the forum , organize new meetups, and speak about what you like in Cozy!", "title": "CONTRIBUTING"}, {"location": "cozy-apps-registry/CONTRIBUTING/#how-to-contribute-to-the-cozy-registry-v3", "text": "Thank you for your interest in contributing to Cozy! There are many ways to contribute, and we appreciate all of them.", "title": "How to contribute to the Cozy Registry v3?"}, {"location": "cozy-apps-registry/CONTRIBUTING/#security-issues", "text": "If you discover a security issue, please bring it to their attention right away! Please DO NOT file a public issue, instead send your report privately to security AT cozycloud DOT cc. Security reports are greatly appreciated and we will publicly thank you for it. We currently do not offer a paid security bounty program, but are not ruling it out in the future.", "title": "Security Issues"}, {"location": "cozy-apps-registry/CONTRIBUTING/#bug-reports", "text": "While bugs are unfortunate, they\u2019re a reality in software. We can\u2019t fix what we don\u2019t know about, so please report liberally. If you\u2019re not sure if something is a bug or not, feel free to file a bug anyway. Opening an issue is as easy as following this link and filling out the fields. Here are some things you can write about your bug: A short summary What did you try, step by step? What did you expect? What did happen instead? What is the version of the Cozy Stack?", "title": "Bug Reports"}, {"location": "cozy-apps-registry/CONTRIBUTING/#pull-requests", "text": "", "title": "Pull Requests"}, {"location": "cozy-apps-registry/CONTRIBUTING/#workflow", "text": "Pull requests are the primary mechanism we use to change Cozy. GitHub itself has some great documentation on using the Pull Request feature. We use the \u2018fork and pull\u2019 model described there.", "title": "Workflow"}, {"location": "cozy-apps-registry/CONTRIBUTING/#step-1-fork", "text": "Fork the project on GitHub and check out your copy locally: $ git clone https://github.com/cozy/cozy-apps-registry.git $ cd cozy-apps-registry $ git remote add fork git://github.com/username/cozy-apps-registry.git", "title": "Step 1: Fork"}, {"location": "cozy-apps-registry/CONTRIBUTING/#step-2-branch", "text": "Create a branch and start hacking: $ git checkout -b my-branch -t origin/master", "title": "Step 2: Branch"}, {"location": "cozy-apps-registry/CONTRIBUTING/#step-3-code", "text": "Well, I think you know how to do that. Just be sure to follow the coding guidelines from the Go community (gofmt, Effective Go , comment the code, etc.).", "title": "Step 3: Code"}, {"location": "cozy-apps-registry/CONTRIBUTING/#step-4-test", "text": "Don\u2019t forget to add tests and be sure they are green: $ go test -v", "title": "Step 4: Test"}, {"location": "cozy-apps-registry/CONTRIBUTING/#step-5-commit", "text": "Writing good commit messages is important. A commit message should describe what changed and why.", "title": "Step 5: Commit"}, {"location": "cozy-apps-registry/CONTRIBUTING/#step-6-rebase", "text": "Use git pull --rebase , or git rebase (but not git merge ), to sync your work from time to time: $ git pull origin master --rebase", "title": "Step 6: Rebase"}, {"location": "cozy-apps-registry/CONTRIBUTING/#step-7-push", "text": "$ git push fork my-branch Go to https://github.com/username/cozy-apps-registry and select your branch. Click the \u2018Pull Request\u2019 button and fill out the form. Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in a separate commit and push that to your branch.", "title": "Step 7: Push"}, {"location": "cozy-apps-registry/CONTRIBUTING/#community", "text": "You can help us by making our community even more vibrant. For example, you can write a blog post, take some videos, answer the questions on the forum , organize new meetups, and speak about what you like in Cozy!", "title": "Community"}, {"location": "cozy-banks/", "text": "Cozy Banks \u00b6 Cozy Banks is the personal financial management application available on Cozy. It helps you gain understanding of your personal finances, and much more . As the first digital home on the market, Cozy helps all users with applications and connectors regain control, streamline and maximize their digital lives. With Cozy Banks, you can easily: Have all your bank accounts in one place Get an comprehensive overview of all your expenses with one-click access to your bills Directly access your health insurance reimbursements Enjoy all the features for free Developing Account Types Bills Matching Brand Dictionnary Categorization Category Code Conventions Credentials Data Fetching Demo Notification Override Cordova Config Perfs Services Tracking Feature requests Feature requests \u00b6 We love getting feedback, do not hesitate if you have any. Please use the forum for any feature requests.", "title": "Cozy Banks"}, {"location": "cozy-banks/#cozy-banks", "text": "Cozy Banks is the personal financial management application available on Cozy. It helps you gain understanding of your personal finances, and much more . As the first digital home on the market, Cozy helps all users with applications and connectors regain control, streamline and maximize their digital lives. With Cozy Banks, you can easily: Have all your bank accounts in one place Get an comprehensive overview of all your expenses with one-click access to your bills Directly access your health insurance reimbursements Enjoy all the features for free Developing Account Types Bills Matching Brand Dictionnary Categorization Category Code Conventions Credentials Data Fetching Demo Notification Override Cordova Config Perfs Services Tracking Feature requests", "title": "Cozy Banks"}, {"location": "cozy-banks/#feature-requests", "text": "We love getting feedback, do not hesitate if you have any. Please use the forum for any feature requests.", "title": "Feature requests"}, {"location": "cozy-banks/CHANGELOG/", "text": "1.59.0 \u00b6 1.58.0 \u00b6 \u2728 Features \u00b6 Use redux store for save all brands Use optimize query for get triggers without jobs \ud83d\udc1b Bug Fixes \u00b6 No chips for Konnectors under maintenance In order to display correctly the KonnectorChip and don\u2019t propose the installation of a clisk if it\u2019s already connected \ud83d\udd27 Tech \u00b6 Retrieving connectors via the registry in addition to the JSON file 1.57.0 \u00b6 \u2728 Features \u00b6 Upgrade cozy-scripts from 6.3.0 to 8.1.1 \ud83d\udc1b Bug Fixes \u00b6 Transaction modale closed by itself on some mobile devices Fields in Intent modals must be clickable 1.56.0 \u00b6 \u2728 Features \u00b6 Hide KonnectorChip by flag for health category Hide BillChip by flag for health category Remove native link and icon from manifest \ud83d\udc1b Bug Fixes \u00b6 Transaction modale closed by itself on some mobile devices \ud83d\udd27 Tech \u00b6 Remove logs with unnecessary or sensitive data 1.55.0 \u00b6 \u2728 Features \u00b6 Update cozy-bar to get fixed cloud icon position Save imported transactions count Update Success modal to specify number of successfully imported operations Add balancesNotifications to io.cozy.bank.settings Add current balance for each account in io.cozy.bank.settings when onOperationOrBillCreate service run. \ud83d\udc1b Bug Fixes \u00b6 French wording for import success title Email notification for balance greater wasn\u2019t using the right title Reduction of the number of BalanceLower & BalanceGreater notifications \ud83d\udd27 Tech \u00b6 Add import service documentation 1.54.0 \u00b6 \ud83d\udc1b Bug Fixes \u00b6 Import accounts with a normalized number Prevent fallback on sub-optimal index for in-progress jobs query. \ud83d\udd27 Tech \u00b6 Notifications are compatible with the new Cozy app 1.53.0 \u00b6 \u2728 Features \u00b6 Export your bank\u2019s data in csv format via the Settings page Import bank data from Cozy bank export file ( csv format) via the Settings page Rework renderExtraRoutesWithoutLayout AppRoute method Allow grouping bank accounts by institution labels in Settings \ud83d\udc1b Bug Fixes \u00b6 The service onOperationOrBillCreate was failing with a CozyStackClient.collection() called without a doctype error. Bank accounts imported via the import service are grouped by their institution label in the Settings\u202f>\u202fAccounts tab \ud83d\udd27 Tech \u00b6 Remove direct dependency to cozy-stack-client Bump cozy-stack-client from 35.3.1 to 35.6.0 Bump cozy-pouch-link from 35.3.1 to 35.6.0 Services launched via the CLI use a CozyClient instance with appMetadata 1.52.0 \u00b6 \u2728 Features \u00b6 Update cozy-bar from 8.11.2 to 8.14.0 \ud83d\udc1b Bug Fixes \u00b6 When a connector needs to be updated, it no longer impacts the add bank connector buttons The recurrence service should not modify transactions already associated with a recurrence Use absolute links for analysis tabs Right arrow on advanced filter in category page was not clickable \ud83d\udd27 Tech \u00b6 Clarified recurrence service functions and variables names Add better log for services More specific log for doTransactionsMatching and doBillsMatching in onOperationOrBillCreate Improved performance of transactions filtering in the recurrence service 1.51.0 \u00b6 \u2728 Features \u00b6 The stats service is no longer useful, we can remove it from the manifest and delete the deprecated code Update React Router to v6 Update cozy-authentication from 2.1.0 to 2.12.1 \ud83d\udc1b Bug Fixes \u00b6 Fix bad display of settings menu \ud83d\udd27 Tech \u00b6 Remove cozy-client-js assets 1.50.0 \u00b6 \u2728 Features \u00b6 Upgrade cozy-ui from 75.4.0 to 79.0.0 Upgrade cozy-client from 33.2.0 to 34.5.0 Upgrade cozy-stack-client from 33.2.0 to 34.1.5 Upgrade cozy-pouch-link from 33.2.0 to 34.5.0 Upgrade cozy-device-helper from 2.1.0 to 2.6.0 Upgrade cozy-harvest-lib from 9.32.4 to 10.0.0 \ud83d\udc1b Bug Fixes \u00b6 Exclude virtual accounts from the counter on the balance page Localize account and group labels in notification settings 1.49.0 \u00b6 \u2728 Features \u00b6 upgrade cozy-bar and cozy-intent to 8.11/2.7 \ud83d\udc1b Bug Fixes \u00b6 update icon-banks svg file 1.48.0 \u00b6 \ud83d\udd27 Tech \u00b6 Use warn log instead of info for konnectorAlerts service \ud83d\udc1b Bug Fixes \u00b6 KonnectorAlerts notification onSuccess is async 1.47.1 \u00b6 \u2728 Features \u00b6 Upgrade cozy-harvest-lib to 9.32.3 : Use OAuthService in KonnectorAccountTabs Use OAuthService in OAuthForm Update wording for Bank disconnect dialog close button Add independent confirm dialog Use independant OAuth window Better locale for delete BI connection confirmation button Follow current trigger jobs even after the first load Only update cozy-client store when refreshing contracts Do not unsubscribe all realtime events Prevent createTemporaryToken to updateCache twice at the same time upgrade cozy-realtime to 4.2.9 to get the sendNotification method Upgrade cozy-bar from 8.9.3 to 8.9.4 Add konnector slug in fake trigger passed to onLoginSuccess Add realtime update of cozy accounts Add the virtual reimbursement accounts to the account switch Add the account switch to the reimbursement page Do not display success or error toast for webhooks other than CONNECTION_SYNCED \ud83d\udc1b Bug Fixes \u00b6 Do not display an error icon for all accounts with the same slug Ignore account delete and account disabled jobs for import success message Remove import in progress in the end of the connector job Use CozyClient.saveAll() instead of Document.updateAll() from deprecated cozy-doctypes to avoid CouchDB errors with attributes starting with an underscore (#2547) Swap providers to make some Harvest dialogs match the theme Handles accounts created after bi webhooks on contract synchronization Fix notifications issues on the b2c app Don\u2019t register the flag plugin twice Wrong locale on BI connection removal https://github.com/cozy/cozy-libs/commit/ed2f352467da5f36ef1753de5578f156bb2a1ffb Update cozy accounts when removed from cozy-stack after BI connection removal from BI webview Reverts \u201cInclude virtual accounts in the account total count in balance details\u201d Exclude virtual accounts from the account count in balance details Do not show any account when none is selected in balance details Always show the action column since tags are always enabled Handles accounts created after bi webhooks on contract synchronization \ud83d\udd27 Tech \u00b6 Add more logs around LateHealthReimbursement onSuccess method 1.47.0 \u00b6 \u2728 Features \u00b6 Add wait job New OAuthWrapperCompProps in TriggerManager Preserve selected tags when navigating in categories Don\u2019t notify users about very old konnector run failures (i.e. older than 7 days and 15 minutes which is the maximum delay between the last failure and the scheduled 7 days reminder). Remove flag for Tags feature \ud83d\udc1b Bug Fixes \u00b6 Add and remove tags at the same time on a transaction Fix blank block within the flagship app for the cozy-bar Prevent scheduling konnectorAlerts triggers in the past which would be executed right away by cozy-stack ending up sending multiple notifications to the user about the failed konnector run. Include virtual accounts in the account total count in balance details Log event only when hiding incomes and not when unhiding them 1.46.0 \u00b6 \u2728 Features \u00b6 Optimization of the Mango query to get first / last date for an account No more 404 call to manifest.json Add new event and page loggers for tags Add a new switch to toggle hiding amounts in mobile notifications \ud83d\udc1b Bug Fixes \u00b6 Revert cozy-script to deduplicate CSS files Harvest: Hide BIContractActivationWindow behind the bi webview flag 1.45.0 \u00b6 \u2728 Features \u00b6 Add tags on transactions Add a tab in the settings to list all the tags Add a modal to filter by Tags on the analysis page Upgrade cozy-ui from 69.3.0 to 74.3.0 Add a page for managing a given tag Optimization of the Mango query to get first / last date for an account \ud83d\udc1b Bug Fixes \u00b6 Fix recurrence service that was triggering itself in an infinite loop [PR] Fix typo in French translation [PR] Transactions actions style on mobile Notifications based on transactions changes will only be sent once, even if the transaction is modified after the first trigger [PR] Update trigger without fetch policy in AccountModal, while reconnecting a konnector Update cozy-harvest-lib 9.15.1 : Update trigger while status changed [PR] Update trigger without fetch policy in AccountModal, while reconnecting a konnector [PR] Prevent recurrence service from running until we figure out why it is triggering itself in an infinite loop [PR] \ud83d\udd27 Tech \u00b6 Remove dev dependency to cozy-ach [PR] 1.44.0 \u00b6 \u2728 Features \u00b6 Update cozy-stack-client and cozy-pouch-link to sync with cozy-client version Use DropdownText comp instead of custom in AccountSwitch Update cozy-harvest-lib 9.8.0 : Add reconnect to bi Webviews [PR] 9.10.1 : Add custom intentsApi prop to TriggerManager [PR] 9.11.1 : Add sync date on ContractItem and overrides ability in AccountModal [PR] and [PR] 9.12.0 : Do not show Popup when intentsApi parameter is given [PR] 9.12.2 : Do not pre encode oauth url [PR] and Do not show popup when intentsApi is given [PR] 9.12.3 : Do not double encode oauth url [PR] 9.14.1 : Change RedirectToAccountFormButton label & size [PR] 9.15.1 : Update trigger while status changed [PR] 9.16.0 : Allow EditAccountModal to have intentsApi ( 43c5910 ) Now open the BI manage webview to the correct connection id ( 2f3da74 ) 9.17.0 : All oauth methods to handle reconection case ( b1a6033 ) Do not show identifiers with bi Webviews ( 58e1bb1 ) 9.18.0 : Add error message display in OAuthForm component ( f29b3c4 ) Handle user dismiss in Oauth window ( a6dcba8 ) 9.22.2 : feat: Allow disabled banks to be clickable 9.23.2 : Add BI aggregator releationship to BI accounts 9.25.0 : Now OAuth popup/inAppBrowser wait for login success to hide 9.26.1 : Use BI account creation webview to handle account synchronization RefreshContracts now updates contracts in realtime Disable account line in import group panel to prevent accessing an account not yet ready Change wording for toast message when importing data from a bank is completed Remove icon on ReconnectTriggerButton Add intentsApi prop to HarvestBankAccountSettings Add a spinner in OAuth popup/InAppBrowser after OAuth redirection \ud83d\udc1b Bug Fixes \u00b6 Fix App Amirale UI issues by updating cozy-ui [PR] Update trigger without fetch policy in AccountModal, while reconnecting a konnector [PR] Use the right color for input text Colors when importing account Prevent recurrence service from running until we figure out why it is triggering itself in an infinite loop [PR] Do not allways show the same bank in BI webview Do fail the connector for banks with multiple bank ids Update cozy-client to 32.2.7 : Lodash.merge is not creating a new object PR fix temporary token cache when beginning with an empty cache PR Breaking changes are not supposed to affect cozy-banks Update cozy-harvest-lib 9.12.2 : Do not pre encode oauth url PR and Do not show popup when intentsApi is given PR 9.12.3 : Do not double encode oauth url PR Prevent recurrence service from running until we figure out why it is triggering itself in an infinite loop [PR] Do not allways show the same bank in BI webview Do fail the connector for banks with multiple bank ids Update cozy-client to 32.2.6 : fix temporary token cache when beginning with an empty cache PR Breaking changes are not supposed to affect cozy-banks Invalidate temporary token cache when there is a change of BI user OauthWindowInAppBrowser re-render 9.12.2 : Do not pre encode oauth url PR and Do not show popup when intentsApi is given PR Harvest 9.25.0: Remove an BI webview reconnection step Remove an unused request to BI api to be faster 9.26.6 : Better handling of duplicate accounts : locale + realtime in bank accounts Display the resulting account in the Settings screen after an account creation (with realtime) Update cozy-harvest-lib 9.14.1 Update cozy-client to 32.2.6 \ud83d\udd27 Tech \u00b6 Extract import of AccountModalContent in HarvestAccountModal to be able to override it easily 1.43.1 \u00b6 \ud83d\udc1b Bug Fixes \u00b6 Fix services that were broken due to latest cozy-client update [PR] 1.43.0 \u00b6 \u2728 Features \u00b6 Change Sentry url + add instance in tags context Upgrade cozy-client to get ability to force HTTPs fetches when window.cozy.isSecureProtocol is true CozyClient can be used in a node env [PR] Fix App Amirale localhost dev server issues by updating cozy-scripts [PR] \ud83d\udc1b Bug Fixes \u00b6 cozy-harvest-lib 9.4.0 : Get correct bi mapping for bnp_es and cic_es PR Remove useVaultClient call in LegacyTriggerManager PR TriggerManager OAuthForm wrapper PR Upgrade cozy-ui to 67.0.2 to get bugfix on Matomo tracking Fix deprecated bundles help french translation \ud83d\udd27 Tech \u00b6 Update cozy packages 1.42.0 \u00b6 \u2728 Features \u00b6 Update cozy-client and cozy-stack-client to 27.17.0 Update cozy-harvest-lib to 7.3.1 \ud83d\udd27 Tech \u00b6 Remove the creation of an Android version of the application 1.41.0 \u00b6 \ud83d\udc1b Bug Fixes \u00b6 Transactions page indicated isDesktop undefined when changing month in the date selector Reimbursements shows correct datas even if coming from the home page \ud83d\udd27 Tech \u00b6 Refactor of Reimbursements from class component to functional component Update documentation to install and start project 1.40.0 \u00b6 \u2728 Features \u00b6 cozy-harvest-lib 6.15.0 : get support email according to the contect PR \ud83d\udc1b Bug Fixes \u00b6 Scheduled notification are created only if a notification will be sent in the next day, and only if there is no already notification in the futur Notifications for errored connector are now sent at 5am local time (UTC for cozy servers) instead of 6am Scheduling notifications if sending is between 10pm and 5am local time (UTC for cozy servers) instead of 11pm and 6am Reimbursment panel was not correctly displaying the transactions Switching to /analysis/categories from \u201creimbursment virutal group\u201d no longer leads to empty page Get reimbursements data for transactions fetched on the homepage. This fixes reimbursements group. \ud83d\udd27 Tech \u00b6 1.39.0 \u00b6 \u2728 Features \u00b6 Scheduling notifications if sending is between 11pm and 6am Notifications for errored connector are now sent at 6am instead of 8am Show alert message when a request failed (allows to reload the app) \ud83d\udc1b Bug Fixes \u00b6 Show empty page title only for mobile Reimbursement block is visible again on the balance page if it is shown first Show operations by date and by account (and not the reverse) in group details Fix colors Alerter component and alert message displayed several times 1.38.0 \u00b6 \u2728 Features \u00b6 Alert notifications for KO connectors link to the accounts page in the settings Change wording push content notification Change EUR by \u20ac Replace \u2018.\u2019 in amount by \u2018,\u2019 Capitalize each transaction label word Show by line 50 char max Example if the label from transaction is Salaire du mois de Septembre 2021 (01/09/2021) with an amount 1234.56 so we display that: Salaire Du Mois De Septembre 2021 (01/0 : 1234,56\u20ac Color change for the recurrence edition modal \ud83d\udd27 Tech \u00b6 Refactor for RecurrencePage and split component into different files 1.37.0 \u00b6 \u2728 Features \u00b6 Add notifications at +3 and +7 days for banking connectors, if the connector is in an actionable error Recurrency service: allows to attach transactions whose amount is between 2 extremes of amounts in the existing recurrences (+/- 5% by default). This percentage is configurable with the flag banks.recurrency.percentage-amounts-accepted . Example for 10% set 0.1 \ud83d\udc1b Bug Fixes \u00b6 Fix Month / Year selection on iOS in Analysis Page Fix no data displayed in Analysis Page on iOS Fix Accordion border color and SelectDates text color \ud83d\udd27 Tech \u00b6 Move / Refactor / Split CategoriesHeader component Split bundle into 3 chunks: main, vendor and cozy-bar Update Cozy App Publish (Fix travis icon on mattermost publish announcement) 1.36.0 \u00b6 \u2728 Features \u00b6 Add latest transaction amount value in recurrences Futur balances shows latest transaction amount \ud83d\udc1b Bug Fixes \u00b6 Update cozy-ui to 52.0.0 to reduce the size of the bundle Exclude some modules to reduce the size of the bundle \u2018node-forge\u2019, \u2018node-jose\u2019, \u2018tldjs\u2019 Remove third level import from Mui in HistoryChart fix undefined var in the categ service Transaction Label is now truncated if too long in the Transaction details modal Fix Search Link when clicking on the magnifying glasse if label contained an \u201c/\u201d \ud83d\udd27 Tech \u00b6 Add recurrence test for not same account scenario + refactor other recurrence tests Use CozyClient links instead of StackClient in removeAccountFromGroups 1.35.0 \u00b6 \u2728 Features \u00b6 Optimization of the database on mobile (addition of the indexeddb adapter). For old users, a modal appears and allows to launch the data migration. Update cozy-pouch-link to 24.3.2 to be able to migrates database on mobile to indexeddb Remove minimum limit to find recurrence Recurrence creation process will always try to update existing bundle before creating some Ability to update old recurrences and create new ones in the same batch Change recurrence lookback date limit from 90 to 100 days Selection mode to change the category of several transactions at once Update cozy-harvest-lib to 6.6.0 to get the correct BI slug for palatine bank Change migration modal wording \ud83d\udc1b Bug Fixes \u00b6 Error when removing a group on desktop and mobile Correct minimum date is used to create recurrence Fix warming queries with null applicationDate selector \ud83d\udd27 Tech \u00b6 Add pouchdb-adapter-idb and pouchdb-adapter-indexeddb v7.2.2 Extract component from GroupSettings Groups are not filtered anymore to exclude undefined one in AccountSwitch Remove updateOrCreateGroup() to remove router from dependencies Only deep import for lodash Add logs to better debugging recurrence 1.34.0 \u00b6 \u2728 Features \u00b6 Remove balance from transaction header Add checkbox icon button to activate selection mode in transactions page and search page Improve ui for no result in search page Recategorizing multiple transactions is much faster with better performance Optimize transactions queries by changing indexes order Separates notifications content by a return to line Update cozy-ui to 51.4.0 Update cozy-harvest-lib to 6.4.0 Update cozy-client and cozy-pouch-link to 24.1.0 to fix queryAll bug and destroy on Pouch Update cozy-stack-client to 24.0.0 \ud83d\udc1b Bug Fixes \u00b6 Checkbox horizontal position for selectionning rows in desktop Hide owner field in account configuration when Contacts app is not installed Deactivates selection mode when leaving an account page First transactions are no longer trimmed on the balance page on tablet Missing colors for categories in the chart on the analysis page The analysis page correctly retrieves information when viewing all accounts Prevent render loop after login if a pin had been set Render pin setting row in configuration even when no pin has been set yet Autogroups and LinkMyselfToAccount services crashed if configuration settings had not been saved yet Median function in Recurrence returns the correct median Reassigned transactions are displayed in the correct period according to the selected period On mobile, account settings page doesn\u2019t loop after removing an account Checkbox in transaction row are no longer trimmed Transactions are no longer selectable in the projected expenses page Planned transactions page shows transactions correctly on tablet \ud83d\udd27 Tech \u00b6 To facilitate overriding about notifications and standardize their entry point, a bit refactoring was necessary: Move CategoryBudget to notifications folder Move lang and dictRequire to utils/lang Ability to run the push notifications debug server from the CLI Add some documentation to develop for android Extract HeaderInfoCard from PlannedTransactionsPage Extract PlannedTransactionsPage header in its own component", "title": "1.59.0"}, {"location": "cozy-banks/CHANGELOG/#1590", "text": "", "title": "1.59.0"}, {"location": "cozy-banks/CHANGELOG/#1580", "text": "", "title": "1.58.0"}, {"location": "cozy-banks/CHANGELOG/#features", "text": "Use redux store for save all brands Use optimize query for get triggers without jobs", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes", "text": "No chips for Konnectors under maintenance In order to display correctly the KonnectorChip and don\u2019t propose the installation of a clisk if it\u2019s already connected", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech", "text": "Retrieving connectors via the registry in addition to the JSON file", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1570", "text": "", "title": "1.57.0"}, {"location": "cozy-banks/CHANGELOG/#features_1", "text": "Upgrade cozy-scripts from 6.3.0 to 8.1.1", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_1", "text": "Transaction modale closed by itself on some mobile devices Fields in Intent modals must be clickable", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1560", "text": "", "title": "1.56.0"}, {"location": "cozy-banks/CHANGELOG/#features_2", "text": "Hide KonnectorChip by flag for health category Hide BillChip by flag for health category Remove native link and icon from manifest", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_2", "text": "Transaction modale closed by itself on some mobile devices", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_1", "text": "Remove logs with unnecessary or sensitive data", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1550", "text": "", "title": "1.55.0"}, {"location": "cozy-banks/CHANGELOG/#features_3", "text": "Update cozy-bar to get fixed cloud icon position Save imported transactions count Update Success modal to specify number of successfully imported operations Add balancesNotifications to io.cozy.bank.settings Add current balance for each account in io.cozy.bank.settings when onOperationOrBillCreate service run.", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_3", "text": "French wording for import success title Email notification for balance greater wasn\u2019t using the right title Reduction of the number of BalanceLower & BalanceGreater notifications", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_2", "text": "Add import service documentation", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1540", "text": "", "title": "1.54.0"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_4", "text": "Import accounts with a normalized number Prevent fallback on sub-optimal index for in-progress jobs query.", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_3", "text": "Notifications are compatible with the new Cozy app", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1530", "text": "", "title": "1.53.0"}, {"location": "cozy-banks/CHANGELOG/#features_4", "text": "Export your bank\u2019s data in csv format via the Settings page Import bank data from Cozy bank export file ( csv format) via the Settings page Rework renderExtraRoutesWithoutLayout AppRoute method Allow grouping bank accounts by institution labels in Settings", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_5", "text": "The service onOperationOrBillCreate was failing with a CozyStackClient.collection() called without a doctype error. Bank accounts imported via the import service are grouped by their institution label in the Settings\u202f>\u202fAccounts tab", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_4", "text": "Remove direct dependency to cozy-stack-client Bump cozy-stack-client from 35.3.1 to 35.6.0 Bump cozy-pouch-link from 35.3.1 to 35.6.0 Services launched via the CLI use a CozyClient instance with appMetadata", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1520", "text": "", "title": "1.52.0"}, {"location": "cozy-banks/CHANGELOG/#features_5", "text": "Update cozy-bar from 8.11.2 to 8.14.0", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_6", "text": "When a connector needs to be updated, it no longer impacts the add bank connector buttons The recurrence service should not modify transactions already associated with a recurrence Use absolute links for analysis tabs Right arrow on advanced filter in category page was not clickable", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_5", "text": "Clarified recurrence service functions and variables names Add better log for services More specific log for doTransactionsMatching and doBillsMatching in onOperationOrBillCreate Improved performance of transactions filtering in the recurrence service", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1510", "text": "", "title": "1.51.0"}, {"location": "cozy-banks/CHANGELOG/#features_6", "text": "The stats service is no longer useful, we can remove it from the manifest and delete the deprecated code Update React Router to v6 Update cozy-authentication from 2.1.0 to 2.12.1", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_7", "text": "Fix bad display of settings menu", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_6", "text": "Remove cozy-client-js assets", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1500", "text": "", "title": "1.50.0"}, {"location": "cozy-banks/CHANGELOG/#features_7", "text": "Upgrade cozy-ui from 75.4.0 to 79.0.0 Upgrade cozy-client from 33.2.0 to 34.5.0 Upgrade cozy-stack-client from 33.2.0 to 34.1.5 Upgrade cozy-pouch-link from 33.2.0 to 34.5.0 Upgrade cozy-device-helper from 2.1.0 to 2.6.0 Upgrade cozy-harvest-lib from 9.32.4 to 10.0.0", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_8", "text": "Exclude virtual accounts from the counter on the balance page Localize account and group labels in notification settings", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1490", "text": "", "title": "1.49.0"}, {"location": "cozy-banks/CHANGELOG/#features_8", "text": "upgrade cozy-bar and cozy-intent to 8.11/2.7", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_9", "text": "update icon-banks svg file", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1480", "text": "", "title": "1.48.0"}, {"location": "cozy-banks/CHANGELOG/#tech_7", "text": "Use warn log instead of info for konnectorAlerts service", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_10", "text": "KonnectorAlerts notification onSuccess is async", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1471", "text": "", "title": "1.47.1"}, {"location": "cozy-banks/CHANGELOG/#features_9", "text": "Upgrade cozy-harvest-lib to 9.32.3 : Use OAuthService in KonnectorAccountTabs Use OAuthService in OAuthForm Update wording for Bank disconnect dialog close button Add independent confirm dialog Use independant OAuth window Better locale for delete BI connection confirmation button Follow current trigger jobs even after the first load Only update cozy-client store when refreshing contracts Do not unsubscribe all realtime events Prevent createTemporaryToken to updateCache twice at the same time upgrade cozy-realtime to 4.2.9 to get the sendNotification method Upgrade cozy-bar from 8.9.3 to 8.9.4 Add konnector slug in fake trigger passed to onLoginSuccess Add realtime update of cozy accounts Add the virtual reimbursement accounts to the account switch Add the account switch to the reimbursement page Do not display success or error toast for webhooks other than CONNECTION_SYNCED", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_11", "text": "Do not display an error icon for all accounts with the same slug Ignore account delete and account disabled jobs for import success message Remove import in progress in the end of the connector job Use CozyClient.saveAll() instead of Document.updateAll() from deprecated cozy-doctypes to avoid CouchDB errors with attributes starting with an underscore (#2547) Swap providers to make some Harvest dialogs match the theme Handles accounts created after bi webhooks on contract synchronization Fix notifications issues on the b2c app Don\u2019t register the flag plugin twice Wrong locale on BI connection removal https://github.com/cozy/cozy-libs/commit/ed2f352467da5f36ef1753de5578f156bb2a1ffb Update cozy accounts when removed from cozy-stack after BI connection removal from BI webview Reverts \u201cInclude virtual accounts in the account total count in balance details\u201d Exclude virtual accounts from the account count in balance details Do not show any account when none is selected in balance details Always show the action column since tags are always enabled Handles accounts created after bi webhooks on contract synchronization", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_8", "text": "Add more logs around LateHealthReimbursement onSuccess method", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1470", "text": "", "title": "1.47.0"}, {"location": "cozy-banks/CHANGELOG/#features_10", "text": "Add wait job New OAuthWrapperCompProps in TriggerManager Preserve selected tags when navigating in categories Don\u2019t notify users about very old konnector run failures (i.e. older than 7 days and 15 minutes which is the maximum delay between the last failure and the scheduled 7 days reminder). Remove flag for Tags feature", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_12", "text": "Add and remove tags at the same time on a transaction Fix blank block within the flagship app for the cozy-bar Prevent scheduling konnectorAlerts triggers in the past which would be executed right away by cozy-stack ending up sending multiple notifications to the user about the failed konnector run. Include virtual accounts in the account total count in balance details Log event only when hiding incomes and not when unhiding them", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1460", "text": "", "title": "1.46.0"}, {"location": "cozy-banks/CHANGELOG/#features_11", "text": "Optimization of the Mango query to get first / last date for an account No more 404 call to manifest.json Add new event and page loggers for tags Add a new switch to toggle hiding amounts in mobile notifications", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_13", "text": "Revert cozy-script to deduplicate CSS files Harvest: Hide BIContractActivationWindow behind the bi webview flag", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1450", "text": "", "title": "1.45.0"}, {"location": "cozy-banks/CHANGELOG/#features_12", "text": "Add tags on transactions Add a tab in the settings to list all the tags Add a modal to filter by Tags on the analysis page Upgrade cozy-ui from 69.3.0 to 74.3.0 Add a page for managing a given tag Optimization of the Mango query to get first / last date for an account", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_14", "text": "Fix recurrence service that was triggering itself in an infinite loop [PR] Fix typo in French translation [PR] Transactions actions style on mobile Notifications based on transactions changes will only be sent once, even if the transaction is modified after the first trigger [PR] Update trigger without fetch policy in AccountModal, while reconnecting a konnector Update cozy-harvest-lib 9.15.1 : Update trigger while status changed [PR] Update trigger without fetch policy in AccountModal, while reconnecting a konnector [PR] Prevent recurrence service from running until we figure out why it is triggering itself in an infinite loop [PR]", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_9", "text": "Remove dev dependency to cozy-ach [PR]", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1440", "text": "", "title": "1.44.0"}, {"location": "cozy-banks/CHANGELOG/#features_13", "text": "Update cozy-stack-client and cozy-pouch-link to sync with cozy-client version Use DropdownText comp instead of custom in AccountSwitch Update cozy-harvest-lib 9.8.0 : Add reconnect to bi Webviews [PR] 9.10.1 : Add custom intentsApi prop to TriggerManager [PR] 9.11.1 : Add sync date on ContractItem and overrides ability in AccountModal [PR] and [PR] 9.12.0 : Do not show Popup when intentsApi parameter is given [PR] 9.12.2 : Do not pre encode oauth url [PR] and Do not show popup when intentsApi is given [PR] 9.12.3 : Do not double encode oauth url [PR] 9.14.1 : Change RedirectToAccountFormButton label & size [PR] 9.15.1 : Update trigger while status changed [PR] 9.16.0 : Allow EditAccountModal to have intentsApi ( 43c5910 ) Now open the BI manage webview to the correct connection id ( 2f3da74 ) 9.17.0 : All oauth methods to handle reconection case ( b1a6033 ) Do not show identifiers with bi Webviews ( 58e1bb1 ) 9.18.0 : Add error message display in OAuthForm component ( f29b3c4 ) Handle user dismiss in Oauth window ( a6dcba8 ) 9.22.2 : feat: Allow disabled banks to be clickable 9.23.2 : Add BI aggregator releationship to BI accounts 9.25.0 : Now OAuth popup/inAppBrowser wait for login success to hide 9.26.1 : Use BI account creation webview to handle account synchronization RefreshContracts now updates contracts in realtime Disable account line in import group panel to prevent accessing an account not yet ready Change wording for toast message when importing data from a bank is completed Remove icon on ReconnectTriggerButton Add intentsApi prop to HarvestBankAccountSettings Add a spinner in OAuth popup/InAppBrowser after OAuth redirection", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_15", "text": "Fix App Amirale UI issues by updating cozy-ui [PR] Update trigger without fetch policy in AccountModal, while reconnecting a konnector [PR] Use the right color for input text Colors when importing account Prevent recurrence service from running until we figure out why it is triggering itself in an infinite loop [PR] Do not allways show the same bank in BI webview Do fail the connector for banks with multiple bank ids Update cozy-client to 32.2.7 : Lodash.merge is not creating a new object PR fix temporary token cache when beginning with an empty cache PR Breaking changes are not supposed to affect cozy-banks Update cozy-harvest-lib 9.12.2 : Do not pre encode oauth url PR and Do not show popup when intentsApi is given PR 9.12.3 : Do not double encode oauth url PR Prevent recurrence service from running until we figure out why it is triggering itself in an infinite loop [PR] Do not allways show the same bank in BI webview Do fail the connector for banks with multiple bank ids Update cozy-client to 32.2.6 : fix temporary token cache when beginning with an empty cache PR Breaking changes are not supposed to affect cozy-banks Invalidate temporary token cache when there is a change of BI user OauthWindowInAppBrowser re-render 9.12.2 : Do not pre encode oauth url PR and Do not show popup when intentsApi is given PR Harvest 9.25.0: Remove an BI webview reconnection step Remove an unused request to BI api to be faster 9.26.6 : Better handling of duplicate accounts : locale + realtime in bank accounts Display the resulting account in the Settings screen after an account creation (with realtime) Update cozy-harvest-lib 9.14.1 Update cozy-client to 32.2.6", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_10", "text": "Extract import of AccountModalContent in HarvestAccountModal to be able to override it easily", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1431", "text": "", "title": "1.43.1"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_16", "text": "Fix services that were broken due to latest cozy-client update [PR]", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1430", "text": "", "title": "1.43.0"}, {"location": "cozy-banks/CHANGELOG/#features_14", "text": "Change Sentry url + add instance in tags context Upgrade cozy-client to get ability to force HTTPs fetches when window.cozy.isSecureProtocol is true CozyClient can be used in a node env [PR] Fix App Amirale localhost dev server issues by updating cozy-scripts [PR]", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_17", "text": "cozy-harvest-lib 9.4.0 : Get correct bi mapping for bnp_es and cic_es PR Remove useVaultClient call in LegacyTriggerManager PR TriggerManager OAuthForm wrapper PR Upgrade cozy-ui to 67.0.2 to get bugfix on Matomo tracking Fix deprecated bundles help french translation", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_11", "text": "Update cozy packages", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1420", "text": "", "title": "1.42.0"}, {"location": "cozy-banks/CHANGELOG/#features_15", "text": "Update cozy-client and cozy-stack-client to 27.17.0 Update cozy-harvest-lib to 7.3.1", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#tech_12", "text": "Remove the creation of an Android version of the application", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1410", "text": "", "title": "1.41.0"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_18", "text": "Transactions page indicated isDesktop undefined when changing month in the date selector Reimbursements shows correct datas even if coming from the home page", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_13", "text": "Refactor of Reimbursements from class component to functional component Update documentation to install and start project", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1400", "text": "", "title": "1.40.0"}, {"location": "cozy-banks/CHANGELOG/#features_16", "text": "cozy-harvest-lib 6.15.0 : get support email according to the contect PR", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_19", "text": "Scheduled notification are created only if a notification will be sent in the next day, and only if there is no already notification in the futur Notifications for errored connector are now sent at 5am local time (UTC for cozy servers) instead of 6am Scheduling notifications if sending is between 10pm and 5am local time (UTC for cozy servers) instead of 11pm and 6am Reimbursment panel was not correctly displaying the transactions Switching to /analysis/categories from \u201creimbursment virutal group\u201d no longer leads to empty page Get reimbursements data for transactions fetched on the homepage. This fixes reimbursements group.", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_14", "text": "", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1390", "text": "", "title": "1.39.0"}, {"location": "cozy-banks/CHANGELOG/#features_17", "text": "Scheduling notifications if sending is between 11pm and 6am Notifications for errored connector are now sent at 6am instead of 8am Show alert message when a request failed (allows to reload the app)", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_20", "text": "Show empty page title only for mobile Reimbursement block is visible again on the balance page if it is shown first Show operations by date and by account (and not the reverse) in group details Fix colors Alerter component and alert message displayed several times", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#1380", "text": "", "title": "1.38.0"}, {"location": "cozy-banks/CHANGELOG/#features_18", "text": "Alert notifications for KO connectors link to the accounts page in the settings Change wording push content notification Change EUR by \u20ac Replace \u2018.\u2019 in amount by \u2018,\u2019 Capitalize each transaction label word Show by line 50 char max Example if the label from transaction is Salaire du mois de Septembre 2021 (01/09/2021) with an amount 1234.56 so we display that: Salaire Du Mois De Septembre 2021 (01/0 : 1234,56\u20ac Color change for the recurrence edition modal", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#tech_15", "text": "Refactor for RecurrencePage and split component into different files", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1370", "text": "", "title": "1.37.0"}, {"location": "cozy-banks/CHANGELOG/#features_19", "text": "Add notifications at +3 and +7 days for banking connectors, if the connector is in an actionable error Recurrency service: allows to attach transactions whose amount is between 2 extremes of amounts in the existing recurrences (+/- 5% by default). This percentage is configurable with the flag banks.recurrency.percentage-amounts-accepted . Example for 10% set 0.1", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_21", "text": "Fix Month / Year selection on iOS in Analysis Page Fix no data displayed in Analysis Page on iOS Fix Accordion border color and SelectDates text color", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_16", "text": "Move / Refactor / Split CategoriesHeader component Split bundle into 3 chunks: main, vendor and cozy-bar Update Cozy App Publish (Fix travis icon on mattermost publish announcement)", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1360", "text": "", "title": "1.36.0"}, {"location": "cozy-banks/CHANGELOG/#features_20", "text": "Add latest transaction amount value in recurrences Futur balances shows latest transaction amount", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_22", "text": "Update cozy-ui to 52.0.0 to reduce the size of the bundle Exclude some modules to reduce the size of the bundle \u2018node-forge\u2019, \u2018node-jose\u2019, \u2018tldjs\u2019 Remove third level import from Mui in HistoryChart fix undefined var in the categ service Transaction Label is now truncated if too long in the Transaction details modal Fix Search Link when clicking on the magnifying glasse if label contained an \u201c/\u201d", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_17", "text": "Add recurrence test for not same account scenario + refactor other recurrence tests Use CozyClient links instead of StackClient in removeAccountFromGroups", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1350", "text": "", "title": "1.35.0"}, {"location": "cozy-banks/CHANGELOG/#features_21", "text": "Optimization of the database on mobile (addition of the indexeddb adapter). For old users, a modal appears and allows to launch the data migration. Update cozy-pouch-link to 24.3.2 to be able to migrates database on mobile to indexeddb Remove minimum limit to find recurrence Recurrence creation process will always try to update existing bundle before creating some Ability to update old recurrences and create new ones in the same batch Change recurrence lookback date limit from 90 to 100 days Selection mode to change the category of several transactions at once Update cozy-harvest-lib to 6.6.0 to get the correct BI slug for palatine bank Change migration modal wording", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_23", "text": "Error when removing a group on desktop and mobile Correct minimum date is used to create recurrence Fix warming queries with null applicationDate selector", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_18", "text": "Add pouchdb-adapter-idb and pouchdb-adapter-indexeddb v7.2.2 Extract component from GroupSettings Groups are not filtered anymore to exclude undefined one in AccountSwitch Remove updateOrCreateGroup() to remove router from dependencies Only deep import for lodash Add logs to better debugging recurrence", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/CHANGELOG/#1340", "text": "", "title": "1.34.0"}, {"location": "cozy-banks/CHANGELOG/#features_22", "text": "Remove balance from transaction header Add checkbox icon button to activate selection mode in transactions page and search page Improve ui for no result in search page Recategorizing multiple transactions is much faster with better performance Optimize transactions queries by changing indexes order Separates notifications content by a return to line Update cozy-ui to 51.4.0 Update cozy-harvest-lib to 6.4.0 Update cozy-client and cozy-pouch-link to 24.1.0 to fix queryAll bug and destroy on Pouch Update cozy-stack-client to 24.0.0", "title": "\u2728 Features"}, {"location": "cozy-banks/CHANGELOG/#bug-fixes_24", "text": "Checkbox horizontal position for selectionning rows in desktop Hide owner field in account configuration when Contacts app is not installed Deactivates selection mode when leaving an account page First transactions are no longer trimmed on the balance page on tablet Missing colors for categories in the chart on the analysis page The analysis page correctly retrieves information when viewing all accounts Prevent render loop after login if a pin had been set Render pin setting row in configuration even when no pin has been set yet Autogroups and LinkMyselfToAccount services crashed if configuration settings had not been saved yet Median function in Recurrence returns the correct median Reassigned transactions are displayed in the correct period according to the selected period On mobile, account settings page doesn\u2019t loop after removing an account Checkbox in transaction row are no longer trimmed Transactions are no longer selectable in the projected expenses page Planned transactions page shows transactions correctly on tablet", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-banks/CHANGELOG/#tech_19", "text": "To facilitate overriding about notifications and standardize their entry point, a bit refactoring was necessary: Move CategoryBudget to notifications folder Move lang and dictRequire to utils/lang Ability to run the push notifications debug server from the CLI Add some documentation to develop for android Extract HeaderInfoCard from PlannedTransactionsPage Extract PlannedTransactionsPage header in its own component", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-banks/docs/account-types/", "text": "Account types \u00b6 Here is the complete list of the account types managed by the app: Asset Bank Capitalisation Cash Checkings ConsumerCredit CreditCard Credit Card Deposit Joint Liability LifeInsurance Loan Madelin Market Mortgage PEA PEE RevolvingCredit RSP Savings Other Unkown None Credit card Perco Perp Article83 Mapping \u00b6 Some types are dynamically mapped to other types: Original type Mapped type `Article83` `LongTermSavings` `LifeInsurance` `Madelin` `Market` `Mortgage` `PEA` `PEE` `Perco` `Perp` `RSP` `Asset` `Business` `Capitalisation` `Liability` `Bank` `Checkings` `Cash` `Deposit` `ConsumerCredit` `Loan` `RevolvingCredit` `Credit card` `CreditCard` `None` `Other` `Unkown`", "title": "Account types"}, {"location": "cozy-banks/docs/account-types/#account-types", "text": "Here is the complete list of the account types managed by the app: Asset Bank Capitalisation Cash Checkings ConsumerCredit CreditCard Credit Card Deposit Joint Liability LifeInsurance Loan Madelin Market Mortgage PEA PEE RevolvingCredit RSP Savings Other Unkown None Credit card Perco Perp Article83", "title": "Account types"}, {"location": "cozy-banks/docs/account-types/#mapping", "text": "Some types are dynamically mapped to other types: Original type Mapped type `Article83` `LongTermSavings` `LifeInsurance` `Madelin` `Market` `Mortgage` `PEA` `PEE` `Perco` `Perp` `RSP` `Asset` `Business` `Capitalisation` `Liability` `Bank` `Checkings` `Cash` `Deposit` `ConsumerCredit` `Loan` `RevolvingCredit` `Credit card` `CreditCard` `None` `Other` `Unkown`", "title": "Mapping"}, {"location": "cozy-banks/docs/bills-matching/", "text": "Bills/transactions matching algorithm \u00b6 The matching algorithm is in charge of finding matchings between io.cozy.bills and io.cozy.bank.operations documents. This document explains how the matching algorithm works. What are matchings? \u00b6 Matchings are links that can be made between io.cozy.bills and io.cozy.bank.operations documents. For example, if the user ordered something on Amazon, his Amazon connector will import a io.cozy.bills document representing this order, and his banking connector will import a io.cozy.bank.operations representing the bank transaction associated to this order. In banks\u2019 UI, it is used to show a CTA with the transaction on which the user can click to show the linked bill PDF without leaving banks app. The Linker \u00b6 The algorithm is held by the Linker , and more precisely its linkBillsToOperations method. This method takes 3 parameters: An array of io.cozy.bills objects An array of io.cozy.bank.operations objects An options object The options object can contain the following properties: amountLowerDelta : defaults to 0.001 amountUpperDelta : defaults to 0.001 dateLowerDelta : defaults to 15 (days) dateUpperDelta : defaults to 29 (days) These options will determine the default date and amount windows in which a transaction should be to match with a bill. General flow \u00b6 When called, this method will do the following (each part will be explained in details after): Filter bills that are declared as third party payer: these bills have no matching transation since it has been paid by somebody else Then for each bill: Try to find a matching debit transaction (amount < 0) Try to find a matching credit transaction (amount > 0) if the bill is a refund Try to combine bills that didn\u2019t match anything to see if they match something when combined Update transactions that matched in database Finding debit and credit operations for a bill \u00b6 The algorithm is globally the same to find a debit or a credit operation for a bill, but there are some differences at some steps. Each step is explained below. Find neighboring transactions \u00b6 First, we look for transactions that are \u00ab neighbors \u00bb of the bill. It means the ones that fits in the amount and date windows of the bill. The date window is [bill date - dateLowerDelta; bill date + dateUpperDelta] . Where: bill date is bill.date if we are looking for a credit; bill.originalDate with a fallback on bill.date if we are looking for a debit dateLowerDelta is bill.matchingCriterias.dateLowerDelta if it exists, options.dateLowerDelta otherwise dateUpperDelta is bill.matchingCriterias.dateUpperDelta if it exists, options.dateUpperDelta otherwise The amount window is [bill amount - amountLowerDelta; bill amount + amountUpperDelta] . Where: bill amount is bill.groupAmount with a fallback on bill.amount if we are looking for a credit; -bill.originalAmount with a fallback on -bill.amount if we are looking for a debit amountLowerDelta is bill.matchingCriterias.amountLowerDelta if it exists, options.minAmoutDelta otherwise amountUpperDelta is bill.matchingCriterias.amountUpperDelta if it exists, options.maxAmoutDelta otherwise All transactions that matches these two criterias are kept. Apply filters to neighboring transactions \u00b6 There are other filters a transaction must pass to match with a bill. Category \u00b6 Health bills are a little special because they can only match with health transactions. So if the bill is an health bill, we keep only health transactions. Otherwise, we keep all but health transactions. You can pass a allowUncategorized option to the algorithm, in which case uncategorized transactions will also be able to match bills. Reimbursements \u00b6 This filter is applied only if we are looking for a debit transactions. If we try to link a bill as a reimbursement to a debit transaction, we check that the bill\u2019s amount and transaction\u2019s reimbursements sum does not overflows the transaction\u2019s amount. Label regex \u00b6 This filter is applied only if we are looking for a credit transaction or if the bill is not of health type. This filter checks if a transaction matches a regex that is built upon the bill\u2019s properties. Here is how the regexp is built: If the bill has a matchingCriterias.labelRegex property, this is used Otherwise we try to get the brand corresponding to the bill\u2019s vendor in our brands dictionary . If it exists, we use its regexp property Otherwise, we create a regexp containing the bill\u2019s vendor Lastly, if the bill has no vendor, we can\u2019t do anything and the filter will be false for every transaction and the bill will not match any transaction Sort remaining transactions \u00b6 A score is given to the remaining transactions according to their \u00ab distance \u00bb to the bill\u2019s date and amount. The closest one wins and continues through the algorithm. Link bills to debit and credit transactions \u00b6 When transactions were found for a given bill, we need to link the bill to them, either as a bill or as a reimbursement . When a bill matched with a transaction (debit or credit), it is added to the transaction\u2019s bills array. When a bill matched with a debit and a credit transactions, it is also added to the debit transaction\u2019s reimbursements array. A last safety net is applied by checking if adding the bill to the transaction would make the bills sum overflowing the transaction amount or not. It it overflows, the bill is not added. For the bills property, a removed bill will be ignored. But for the reimbursements property, since we don\u2019t fetch the bill because the amount is already present in the transaction, a removed bill will not be ignored. Bills combinations \u00b6 Sometimes, bills need to be combined to match with a debit transaction. It is generally the case for health bills. For example, when your paid multiple medical procedures with a single transaction. It will generate multiple bills for a single debit transaction. In this case, we try to combine bills and find debit transaction for them. This combination process is not required to find debit transaction because in that case the bill\u2019s groupAmount (see io.cozy.bills documentation ) can be used. The bills that are candidates to be combined are the ones that: Didn\u2019t match with a debit transaction Are health costs or are from a vendor that groups bills These bills are then grouped by date and vendor, so we don\u2019t mix bills that have nothing in common. Then all possible combinations are generated for each group. For each combination, a \u00ab meta bill \u00bb is created from the grouped bills and this meta bill is passed in the matching algorithm to find a debit transaction that matches with it. If a transaction is found, then all the bills making the meta bill are linked to it using the same logic as before.", "title": "Bills/transactions matching algorithm"}, {"location": "cozy-banks/docs/bills-matching/#billstransactions-matching-algorithm", "text": "The matching algorithm is in charge of finding matchings between io.cozy.bills and io.cozy.bank.operations documents. This document explains how the matching algorithm works.", "title": "Bills/transactions matching algorithm"}, {"location": "cozy-banks/docs/bills-matching/#what-are-matchings", "text": "Matchings are links that can be made between io.cozy.bills and io.cozy.bank.operations documents. For example, if the user ordered something on Amazon, his Amazon connector will import a io.cozy.bills document representing this order, and his banking connector will import a io.cozy.bank.operations representing the bank transaction associated to this order. In banks\u2019 UI, it is used to show a CTA with the transaction on which the user can click to show the linked bill PDF without leaving banks app.", "title": "What are matchings?"}, {"location": "cozy-banks/docs/bills-matching/#the-linker", "text": "The algorithm is held by the Linker , and more precisely its linkBillsToOperations method. This method takes 3 parameters: An array of io.cozy.bills objects An array of io.cozy.bank.operations objects An options object The options object can contain the following properties: amountLowerDelta : defaults to 0.001 amountUpperDelta : defaults to 0.001 dateLowerDelta : defaults to 15 (days) dateUpperDelta : defaults to 29 (days) These options will determine the default date and amount windows in which a transaction should be to match with a bill.", "title": "The Linker"}, {"location": "cozy-banks/docs/bills-matching/#general-flow", "text": "When called, this method will do the following (each part will be explained in details after): Filter bills that are declared as third party payer: these bills have no matching transation since it has been paid by somebody else Then for each bill: Try to find a matching debit transaction (amount < 0) Try to find a matching credit transaction (amount > 0) if the bill is a refund Try to combine bills that didn\u2019t match anything to see if they match something when combined Update transactions that matched in database", "title": "General flow"}, {"location": "cozy-banks/docs/bills-matching/#finding-debit-and-credit-operations-for-a-bill", "text": "The algorithm is globally the same to find a debit or a credit operation for a bill, but there are some differences at some steps. Each step is explained below.", "title": "Finding debit and credit operations for a bill"}, {"location": "cozy-banks/docs/bills-matching/#find-neighboring-transactions", "text": "First, we look for transactions that are \u00ab neighbors \u00bb of the bill. It means the ones that fits in the amount and date windows of the bill. The date window is [bill date - dateLowerDelta; bill date + dateUpperDelta] . Where: bill date is bill.date if we are looking for a credit; bill.originalDate with a fallback on bill.date if we are looking for a debit dateLowerDelta is bill.matchingCriterias.dateLowerDelta if it exists, options.dateLowerDelta otherwise dateUpperDelta is bill.matchingCriterias.dateUpperDelta if it exists, options.dateUpperDelta otherwise The amount window is [bill amount - amountLowerDelta; bill amount + amountUpperDelta] . Where: bill amount is bill.groupAmount with a fallback on bill.amount if we are looking for a credit; -bill.originalAmount with a fallback on -bill.amount if we are looking for a debit amountLowerDelta is bill.matchingCriterias.amountLowerDelta if it exists, options.minAmoutDelta otherwise amountUpperDelta is bill.matchingCriterias.amountUpperDelta if it exists, options.maxAmoutDelta otherwise All transactions that matches these two criterias are kept.", "title": "Find neighboring transactions"}, {"location": "cozy-banks/docs/bills-matching/#apply-filters-to-neighboring-transactions", "text": "There are other filters a transaction must pass to match with a bill.", "title": "Apply filters to neighboring transactions"}, {"location": "cozy-banks/docs/bills-matching/#category", "text": "Health bills are a little special because they can only match with health transactions. So if the bill is an health bill, we keep only health transactions. Otherwise, we keep all but health transactions. You can pass a allowUncategorized option to the algorithm, in which case uncategorized transactions will also be able to match bills.", "title": "Category"}, {"location": "cozy-banks/docs/bills-matching/#reimbursements", "text": "This filter is applied only if we are looking for a debit transactions. If we try to link a bill as a reimbursement to a debit transaction, we check that the bill\u2019s amount and transaction\u2019s reimbursements sum does not overflows the transaction\u2019s amount.", "title": "Reimbursements"}, {"location": "cozy-banks/docs/bills-matching/#label-regex", "text": "This filter is applied only if we are looking for a credit transaction or if the bill is not of health type. This filter checks if a transaction matches a regex that is built upon the bill\u2019s properties. Here is how the regexp is built: If the bill has a matchingCriterias.labelRegex property, this is used Otherwise we try to get the brand corresponding to the bill\u2019s vendor in our brands dictionary . If it exists, we use its regexp property Otherwise, we create a regexp containing the bill\u2019s vendor Lastly, if the bill has no vendor, we can\u2019t do anything and the filter will be false for every transaction and the bill will not match any transaction", "title": "Label regex"}, {"location": "cozy-banks/docs/bills-matching/#sort-remaining-transactions", "text": "A score is given to the remaining transactions according to their \u00ab distance \u00bb to the bill\u2019s date and amount. The closest one wins and continues through the algorithm.", "title": "Sort remaining transactions"}, {"location": "cozy-banks/docs/bills-matching/#link-bills-to-debit-and-credit-transactions", "text": "When transactions were found for a given bill, we need to link the bill to them, either as a bill or as a reimbursement . When a bill matched with a transaction (debit or credit), it is added to the transaction\u2019s bills array. When a bill matched with a debit and a credit transactions, it is also added to the debit transaction\u2019s reimbursements array. A last safety net is applied by checking if adding the bill to the transaction would make the bills sum overflowing the transaction amount or not. It it overflows, the bill is not added. For the bills property, a removed bill will be ignored. But for the reimbursements property, since we don\u2019t fetch the bill because the amount is already present in the transaction, a removed bill will not be ignored.", "title": "Link bills to debit and credit transactions"}, {"location": "cozy-banks/docs/bills-matching/#bills-combinations", "text": "Sometimes, bills need to be combined to match with a debit transaction. It is generally the case for health bills. For example, when your paid multiple medical procedures with a single transaction. It will generate multiple bills for a single debit transaction. In this case, we try to combine bills and find debit transaction for them. This combination process is not required to find debit transaction because in that case the bill\u2019s groupAmount (see io.cozy.bills documentation ) can be used. The bills that are candidates to be combined are the ones that: Didn\u2019t match with a debit transaction Are health costs or are from a vendor that groups bills These bills are then grouped by date and vendor, so we don\u2019t mix bills that have nothing in common. Then all possible combinations are generated for each group. For each combination, a \u00ab meta bill \u00bb is created from the grouped bills and this meta bill is passed in the matching algorithm to find a debit transaction that matches with it. If a transaction is found, then all the bills making the meta bill are linked to it using the same logic as before.", "title": "Bills combinations"}, {"location": "cozy-banks/docs/brand-dictionary/", "text": "Brand dictionary \u00b6 To be able to know which brands the user can connect, we use what we call the \u00ab brand dictionary \u00bb. This is a JSON file listing all the available brands with the following properties for each brand: name (string): the brand\u2019s name regexp (string): the regexp used to test if a given transaction label matches this brand or not konnectorSlug (string): the slug of the konnector for this brand health (boolean): whether this brand is in the health category or not maintenance (boolean): whether this brand is under maintenance or not (see below) Set a brand in maintenance \u00b6 When a given brand is under maintenance, its associated konnector can no longer be added and configured by the users. In this case, we want to stop proposing the user to add this konnector via the cozy-banks UI. To achieve that, you can turn the maintenance property of the given brand to true . Don\u2019t forget to update tests snapshots using yarn test -u .", "title": "Brand dictionary"}, {"location": "cozy-banks/docs/brand-dictionary/#brand-dictionary", "text": "To be able to know which brands the user can connect, we use what we call the \u00ab brand dictionary \u00bb. This is a JSON file listing all the available brands with the following properties for each brand: name (string): the brand\u2019s name regexp (string): the regexp used to test if a given transaction label matches this brand or not konnectorSlug (string): the slug of the konnector for this brand health (boolean): whether this brand is in the health category or not maintenance (boolean): whether this brand is under maintenance or not (see below)", "title": "Brand dictionary"}, {"location": "cozy-banks/docs/brand-dictionary/#set-a-brand-in-maintenance", "text": "When a given brand is under maintenance, its associated konnector can no longer be added and configured by the users. In this case, we want to stop proposing the user to add this konnector via the cozy-banks UI. To achieve that, you can turn the maintenance property of the given brand to true . Don\u2019t forget to update tests snapshots using yarn test -u .", "title": "Set a brand in maintenance"}, {"location": "cozy-banks/docs/categorization/", "text": "Categorization \u00b6 Concerning the categorization, we use two models (local and global), and a setting that the user can enable in his settings to send his bank transactions to an API via a remote doctype. Local model \u00b6 Presentation \u00b6 This model analyzes the transactions recategorized by the user to get his categorization habits and predict the category of some transactions based on this. This model is applied to transactions when the onOperationOrBillCreate service is run and write its results in the localCategoryId and localCategoryProba properties of the io.cozy.bank.operations documents. Implementation details \u00b6 Currently, the local categorization model fetches all the manually categorized transactions from the stack on every run. We decided it\u2019s the best for now to compute the entire model everytime because the pros/cons balance of saving the model in a specific doctype is not good for this model. Pros: Don\u2019t need to regenerate the whole model everytime the service is run Cons: Need to do some migrations if we want to update the model algorithm Since the CPU time needed to compute the whole model is low (users will never recategorize the majority of their transactions, as the global model has most of the time the correct category), the main advantage is weak in front of the disadvantage. Therefore we chose to recompute the model on every run. The solution of saving the model in the database was first implemented and then reverted following this decision. If we finally need to use this solution, we can find it in 9bbc96b0 which has been reverted by 77dd15ce Global model \u00b6 This model analyzes the category of transactions from instances that enabled the auto categorization setting in their Banks app. It is computed on a distant server, and we fetch it via the remote assets each time transactions are retrieved (learn more here and here ). The remote asset name used for this is bank_classifier_nb_and_voc . Its value should be an URL to a JSON file. This model is applied to transactions when the onOperationOrBillCreate service is run and writes its results in the cozyCategoryId and cozyCategoryProba properties of the io.cozy.bank.operations documents. Category choice \u00b6 After the categorization execution, we may have 4 different levels of categories for the transactions: manualCategoryId : the category manually chosen by the user. localCategoryId : computed by the local model. cozyCategoryId : computed by the global. automaticCategoryId : automatic category retrieved from our banking provider. To determine which category will be shown to the user, we use the following rules: If the manualCategoryId exists, use it. Else, use localCategoryId if localCategoryProba > LOCAL_MODEL_USAGE_THRESHOLD . Else, use cozyCategoryId if cozyCategoryProba > GLOBAL_MODEL_USAGE_THRESHOLD Else, use automaticCategoryId For more details, see the code . Auto categorization setting \u00b6 In banks, there is a setting that the user can enable (it is disabled by default) if he wants to share his bank transactions with us to improve our global categorization model. If this setting is enabled, when the onOperationOrBillCreate service is ran and the new transactions have been categorized using the global and local models, we anonymize the transactions and then send them to an API using the cc.cozycloud.autocategorization remote doctype. This API then uses the documents it receives to update the global categorization model. Service execution \u00b6 See the service documentation to know how the categorization is run and how to use it.", "title": "Categorization"}, {"location": "cozy-banks/docs/categorization/#categorization", "text": "Concerning the categorization, we use two models (local and global), and a setting that the user can enable in his settings to send his bank transactions to an API via a remote doctype.", "title": "Categorization"}, {"location": "cozy-banks/docs/categorization/#local-model", "text": "", "title": "Local model"}, {"location": "cozy-banks/docs/categorization/#presentation", "text": "This model analyzes the transactions recategorized by the user to get his categorization habits and predict the category of some transactions based on this. This model is applied to transactions when the onOperationOrBillCreate service is run and write its results in the localCategoryId and localCategoryProba properties of the io.cozy.bank.operations documents.", "title": "Presentation"}, {"location": "cozy-banks/docs/categorization/#implementation-details", "text": "Currently, the local categorization model fetches all the manually categorized transactions from the stack on every run. We decided it\u2019s the best for now to compute the entire model everytime because the pros/cons balance of saving the model in a specific doctype is not good for this model. Pros: Don\u2019t need to regenerate the whole model everytime the service is run Cons: Need to do some migrations if we want to update the model algorithm Since the CPU time needed to compute the whole model is low (users will never recategorize the majority of their transactions, as the global model has most of the time the correct category), the main advantage is weak in front of the disadvantage. Therefore we chose to recompute the model on every run. The solution of saving the model in the database was first implemented and then reverted following this decision. If we finally need to use this solution, we can find it in 9bbc96b0 which has been reverted by 77dd15ce", "title": "Implementation details"}, {"location": "cozy-banks/docs/categorization/#global-model", "text": "This model analyzes the category of transactions from instances that enabled the auto categorization setting in their Banks app. It is computed on a distant server, and we fetch it via the remote assets each time transactions are retrieved (learn more here and here ). The remote asset name used for this is bank_classifier_nb_and_voc . Its value should be an URL to a JSON file. This model is applied to transactions when the onOperationOrBillCreate service is run and writes its results in the cozyCategoryId and cozyCategoryProba properties of the io.cozy.bank.operations documents.", "title": "Global model"}, {"location": "cozy-banks/docs/categorization/#category-choice", "text": "After the categorization execution, we may have 4 different levels of categories for the transactions: manualCategoryId : the category manually chosen by the user. localCategoryId : computed by the local model. cozyCategoryId : computed by the global. automaticCategoryId : automatic category retrieved from our banking provider. To determine which category will be shown to the user, we use the following rules: If the manualCategoryId exists, use it. Else, use localCategoryId if localCategoryProba > LOCAL_MODEL_USAGE_THRESHOLD . Else, use cozyCategoryId if cozyCategoryProba > GLOBAL_MODEL_USAGE_THRESHOLD Else, use automaticCategoryId For more details, see the code .", "title": "Category choice"}, {"location": "cozy-banks/docs/categorization/#auto-categorization-setting", "text": "In banks, there is a setting that the user can enable (it is disabled by default) if he wants to share his bank transactions with us to improve our global categorization model. If this setting is enabled, when the onOperationOrBillCreate service is ran and the new transactions have been categorized using the global and local models, we anonymize the transactions and then send them to an API using the cc.cozycloud.autocategorization remote doctype. This API then uses the documents it receives to update the global categorization model.", "title": "Auto categorization setting"}, {"location": "cozy-banks/docs/categorization/#service-execution", "text": "See the service documentation to know how the categorization is run and how to use it.", "title": "Service execution"}, {"location": "cozy-banks/docs/category/", "text": "Categorization implementation solution \u00b6 We had a problem about categorization of bank operations since a manual categorization is always replaced by automatic categorization in the next linxo connector run The goal here was to find a way of defining and merging automatic categorization and manual categorization with the following constraints : 1) Manual categorization wins over automatic categorization and we do not want to spread this intelligence over all the actors 2) We want to keep a trace of manual categorization in each bank operation 3) We want to keep a trace of automatic categorization in each bank operation 4) Several actors can modify category : Banks application, linxo connector, a futur bank service which will handle automatic categorization for non-linxo bank connectors the Banks application will only modify the manual category the linxo connector and the bank service will only modify the automatic category 5) actors reading the category : Banks application, futur bank service for centralization of categorization data the Banks application needs the result of 1) the service needs automatic category and manual category Solutions \u00b6 We see that we can\u2019t avoid to keep to separated categories : manual and automatic, even if manual category can be null. As said in 4), Banks application will only modify \u2018manual category\u2019 fields and the others will only modify \u2018automatic category\u2019 fields. The only question remaining is where to put the intelligence of choosing manual category over automatic category for display : A) The automatic category modifiers could calculate a third \u2018category\u2019 field There is a case where this does not work, if the Banks application user changes the manual category, we need to wait a run of the bank connector or service to see the result of the change. Or the Banks application calculates the resulting category itself and we are in B). B) The Banks application could, for each operation choose itself the manual category, if any, over the automatic category (via an accessor or a conditional on display) Chosen solution \u00b6 There should be two category fields associated to each bank operation : manualCategoryId automaticCategoryId Each of them can be undefined and when displaying a category, the Banks application will calculated the resulting category by choosing manualCategoryId over automaticCategoryId. I do not see a need to keep the result of this computation in database.", "title": "Category"}, {"location": "cozy-banks/docs/category/#categorization-implementation-solution", "text": "We had a problem about categorization of bank operations since a manual categorization is always replaced by automatic categorization in the next linxo connector run The goal here was to find a way of defining and merging automatic categorization and manual categorization with the following constraints : 1) Manual categorization wins over automatic categorization and we do not want to spread this intelligence over all the actors 2) We want to keep a trace of manual categorization in each bank operation 3) We want to keep a trace of automatic categorization in each bank operation 4) Several actors can modify category : Banks application, linxo connector, a futur bank service which will handle automatic categorization for non-linxo bank connectors the Banks application will only modify the manual category the linxo connector and the bank service will only modify the automatic category 5) actors reading the category : Banks application, futur bank service for centralization of categorization data the Banks application needs the result of 1) the service needs automatic category and manual category", "title": "Categorization implementation solution"}, {"location": "cozy-banks/docs/category/#solutions", "text": "We see that we can\u2019t avoid to keep to separated categories : manual and automatic, even if manual category can be null. As said in 4), Banks application will only modify \u2018manual category\u2019 fields and the others will only modify \u2018automatic category\u2019 fields. The only question remaining is where to put the intelligence of choosing manual category over automatic category for display : A) The automatic category modifiers could calculate a third \u2018category\u2019 field There is a case where this does not work, if the Banks application user changes the manual category, we need to wait a run of the bank connector or service to see the result of the change. Or the Banks application calculates the resulting category itself and we are in B). B) The Banks application could, for each operation choose itself the manual category, if any, over the automatic category (via an accessor or a conditional on display)", "title": "Solutions"}, {"location": "cozy-banks/docs/category/#chosen-solution", "text": "There should be two category fields associated to each bank operation : manualCategoryId automaticCategoryId Each of them can be undefined and when displaying a category, the Banks application will calculated the resulting category by choosing manualCategoryId over automaticCategoryId. I do not see a need to keep the result of this computation in database.", "title": "Chosen solution"}, {"location": "cozy-banks/docs/code-conventions/", "text": "Code organisation \u00b6 Components \u00b6 If components have an associated style, group the style with the component into a folder. Ex: BackButton Ducks \u00b6 Ducks groups actions/reducers/views for a particular high-level function Sometimes you can have a duck without views, typically when it concerns a particular doctype. Code conventions \u00b6 Constructor \u00b6 Avoid constructor if you can by leveraging transform-class-properties \u274c Bad : class MyComponent extends Component { constructor () { super () this . state = { counter : 0 } } } \u2705 Good class MyComponent extends Component { state = { counter : 0 } } Binding event handlers \u00b6 Avoid binding event handlers in constructor , leverage transform-class-properties and arrow functions. \u274c Bad : class MyComponent extends Component { constructor () { super () this . onClick = this . onClick . bind ( this ) } onClick ( ev ) { ... } } \u2705 Good class MyComponent extends Component { onClick = ( ev ) => { ... } }", "title": "Code conventions"}, {"location": "cozy-banks/docs/code-conventions/#code-organisation", "text": "", "title": "Code organisation"}, {"location": "cozy-banks/docs/code-conventions/#components", "text": "If components have an associated style, group the style with the component into a folder. Ex: BackButton", "title": "Components"}, {"location": "cozy-banks/docs/code-conventions/#ducks", "text": "Ducks groups actions/reducers/views for a particular high-level function Sometimes you can have a duck without views, typically when it concerns a particular doctype.", "title": "Ducks"}, {"location": "cozy-banks/docs/code-conventions/#code-conventions", "text": "", "title": "Code conventions"}, {"location": "cozy-banks/docs/code-conventions/#constructor", "text": "Avoid constructor if you can by leveraging transform-class-properties \u274c Bad : class MyComponent extends Component { constructor () { super () this . state = { counter : 0 } } } \u2705 Good class MyComponent extends Component { state = { counter : 0 } }", "title": "Constructor"}, {"location": "cozy-banks/docs/code-conventions/#binding-event-handlers", "text": "Avoid binding event handlers in constructor , leverage transform-class-properties and arrow functions. \u274c Bad : class MyComponent extends Component { constructor () { super () this . onClick = this . onClick . bind ( this ) } onClick ( ev ) { ... } } \u2705 Good class MyComponent extends Component { onClick = ( ev ) => { ... } }", "title": "Binding event handlers"}, {"location": "cozy-banks/docs/credentials/", "text": "Credentials \u00b6 All credentials are encrypted in an archive file in scripts/encrypted.tar.gz.enc . Create encrypted file \u00b6 tar zcvf scripts/decrypted.tar.gz scripts/decrypted/ travis encrypt-file scripts/decrypted.tar.gz scripts/encrypted.tar.gz.enc -p You should save key and iv variables on pass. pass Gangsters/cozy-banks/ENCRYPTED_KEY pass Gangsters/cozy-banks/ENCRYPTED_IV Decrypt file \u00b6 export ENCRYPTED_KEY = ` pass Gangsters/cozy-banks/ENCRYPTED_KEY ` export ENCRYPTED_IV = ` pass Gangsters/cozy-banks/ENCRYPTED_IV ` yarn secrets:decrypt Update encrypt file \u00b6 If you want to update the credentials, you should update folder ./scripts/decrypted and launch these commands: export ENCRYPTED_KEY = ` pass Gangsters/cozy-banks/ENCRYPTED_KEY ` export ENCRYPTED_IV = ` pass Gangsters/cozy-banks/ENCRYPTED_IV ` yarn secrets:encrypt", "title": "Credentials"}, {"location": "cozy-banks/docs/credentials/#credentials", "text": "All credentials are encrypted in an archive file in scripts/encrypted.tar.gz.enc .", "title": "Credentials"}, {"location": "cozy-banks/docs/credentials/#create-encrypted-file", "text": "tar zcvf scripts/decrypted.tar.gz scripts/decrypted/ travis encrypt-file scripts/decrypted.tar.gz scripts/encrypted.tar.gz.enc -p You should save key and iv variables on pass. pass Gangsters/cozy-banks/ENCRYPTED_KEY pass Gangsters/cozy-banks/ENCRYPTED_IV", "title": "Create encrypted file"}, {"location": "cozy-banks/docs/credentials/#decrypt-file", "text": "export ENCRYPTED_KEY = ` pass Gangsters/cozy-banks/ENCRYPTED_KEY ` export ENCRYPTED_IV = ` pass Gangsters/cozy-banks/ENCRYPTED_IV ` yarn secrets:decrypt", "title": "Decrypt file"}, {"location": "cozy-banks/docs/credentials/#update-encrypt-file", "text": "If you want to update the credentials, you should update folder ./scripts/decrypted and launch these commands: export ENCRYPTED_KEY = ` pass Gangsters/cozy-banks/ENCRYPTED_KEY ` export ENCRYPTED_IV = ` pass Gangsters/cozy-banks/ENCRYPTED_IV ` yarn secrets:encrypt", "title": "Update encrypt file"}, {"location": "cozy-banks/docs/data-fetching/", "text": "This document lists data fetching strategies implemented in Banks. Doctypes used in Banks \u00b6 Accounts: io.cozy.bank.accounts Groups: io.cozy.bank.groups Accounts and groups are loaded right away and are necessary for most of the pages in Banks. No particular strategy for them is necessary since their general cardinality is low (a user has typically less than 100 accounts/groups). It is necessary for example to load account and groups to show the correct transactions when filter the transactions by account / group. Recurrence bundles: io.cozy.bank.recurrence Recurrence bundles are loaded on the recurrences page and could benefit from pagination if a user a more than 100 recurrence bundle. For the recurrence page where transactions pertaining to a particular recurrence bundle are shown, only its transactions are loaded. Triggers: io.cozy.triggers Necessary to display how fresh is the data for a particular account. Used in the balance page and the settings page. Transactions: io.cozy.bank.operations Transactions is the doctype with the highest cardinality and a user has typically several thousands of transactions. A banking transaction weigh less than a 1ko, but a user with 10 years of banking history with a mean of 3 transactions per days as 20000 transactions; in this case several Mo should be downloaded if we had stayed with querying all transactions at each page reload. This is why granular queries were implemented so that each page only loads what is necessary for its needs. Transactions fetching \u00b6 Since it is not performant to load all the transactions from a user at load, queries fetching a subset of the transactions are used. Filtering / indexing and paginated queries through fetchMore are used. Balances page \u00b6 On the balance page, we need account/groups and the transactions for the last year to draw the chart. Transactions are loaded with a subset of their fields so as to lower the data transmitted: only amount, account, date and currency are loaded. Transactions are fetched in batch of 1000 until no more data has been loaded. This is why if a user has more than 1000 transactions in the last year, the graph will be updated for each round of 1000 transactions being fetched. Transaction page \u00b6 The transaction query is based on the account/group filter to only fetch transactions pertaining to a group/account When the user jump from month to month, new queries are created that start at the selected month. This prevents easy infinite top scrolling since we cannot do fetchMore in reverse but this has been deemed OK functionally since the user can use the arrows after reaching the top Infinite fetching when reaching the bottom is implemented via the fetchMore function. Since we do not want data from other months to disturb one particular month, queries on the transactions pages are created with the query options { add: false }. This prevents transactions that have been fetched through the january query to end ud in the march query. This would prevent the infinite loading mechanism to work correctly (since we rely on a graphical element to trigger the fetchMore). Here are the different transaction queries that are made transactions- : transactions for a particular account when the user has not yet navigated in time. Transactions are fetched sorted by date, so we end up with the most recent transactions for a particular account. When the user scrolls down and we have more transactions (query.hasMore), we can request more transactions through query.fetchMore transactions-- When the user navigates from month to month via the date selector, we create a new query that contains the ending month ({ date: { $gt: endDate }}). This enables us to support the infinite loading through the previous mechanism of fetchMore. transactions- When the user selects a group. Very similar to the transactions- query but we fetch transactions for several accounts with a CouchDB $in query on the account attribute. transactions-- Similar to the transactions--endDate> , this is when the user has filtered by a group and has navigated to a month via the date selector. Date selector \u00b6 For the date selector to show the right available options, we need to have the full extent of dates that is available for the particular account/group that we have chosen. Here, we make 2 queries, one for the earliest transaction and one for the latest transaction and then we generate all the months between those two transactions to display the date selector options. Those queries are indexed by date and account and are quick (30ms). While those queries are in flight, the date selector is displayed but not functional. Categories page \u00b6 For this page, we do not need to support infinite loading since we stay in 1 particular month/year. Thus we end up with queries like transactions--- = queries only for the current month transactions, filtered by account and group. useFullyLoadedQuery is used to load all the documents via fetchMore since it is necessary to have all the docs to make aggregate statistics on them. Keeping previous data while loading next one \u00b6 To prevent a jarring loading screen while loading the month, the previous query\u2019s data is shown while the next query data is loading. While data is loading, a progress bar is shown below the transaction header.", "title": "Data fetching"}, {"location": "cozy-banks/docs/data-fetching/#doctypes-used-in-banks", "text": "Accounts: io.cozy.bank.accounts Groups: io.cozy.bank.groups Accounts and groups are loaded right away and are necessary for most of the pages in Banks. No particular strategy for them is necessary since their general cardinality is low (a user has typically less than 100 accounts/groups). It is necessary for example to load account and groups to show the correct transactions when filter the transactions by account / group. Recurrence bundles: io.cozy.bank.recurrence Recurrence bundles are loaded on the recurrences page and could benefit from pagination if a user a more than 100 recurrence bundle. For the recurrence page where transactions pertaining to a particular recurrence bundle are shown, only its transactions are loaded. Triggers: io.cozy.triggers Necessary to display how fresh is the data for a particular account. Used in the balance page and the settings page. Transactions: io.cozy.bank.operations Transactions is the doctype with the highest cardinality and a user has typically several thousands of transactions. A banking transaction weigh less than a 1ko, but a user with 10 years of banking history with a mean of 3 transactions per days as 20000 transactions; in this case several Mo should be downloaded if we had stayed with querying all transactions at each page reload. This is why granular queries were implemented so that each page only loads what is necessary for its needs.", "title": "Doctypes used in Banks"}, {"location": "cozy-banks/docs/data-fetching/#transactions-fetching", "text": "Since it is not performant to load all the transactions from a user at load, queries fetching a subset of the transactions are used. Filtering / indexing and paginated queries through fetchMore are used.", "title": "Transactions fetching"}, {"location": "cozy-banks/docs/data-fetching/#balances-page", "text": "On the balance page, we need account/groups and the transactions for the last year to draw the chart. Transactions are loaded with a subset of their fields so as to lower the data transmitted: only amount, account, date and currency are loaded. Transactions are fetched in batch of 1000 until no more data has been loaded. This is why if a user has more than 1000 transactions in the last year, the graph will be updated for each round of 1000 transactions being fetched.", "title": "Balances page"}, {"location": "cozy-banks/docs/data-fetching/#transaction-page", "text": "The transaction query is based on the account/group filter to only fetch transactions pertaining to a group/account When the user jump from month to month, new queries are created that start at the selected month. This prevents easy infinite top scrolling since we cannot do fetchMore in reverse but this has been deemed OK functionally since the user can use the arrows after reaching the top Infinite fetching when reaching the bottom is implemented via the fetchMore function. Since we do not want data from other months to disturb one particular month, queries on the transactions pages are created with the query options { add: false }. This prevents transactions that have been fetched through the january query to end ud in the march query. This would prevent the infinite loading mechanism to work correctly (since we rely on a graphical element to trigger the fetchMore). Here are the different transaction queries that are made transactions- : transactions for a particular account when the user has not yet navigated in time. Transactions are fetched sorted by date, so we end up with the most recent transactions for a particular account. When the user scrolls down and we have more transactions (query.hasMore), we can request more transactions through query.fetchMore transactions-- When the user navigates from month to month via the date selector, we create a new query that contains the ending month ({ date: { $gt: endDate }}). This enables us to support the infinite loading through the previous mechanism of fetchMore. transactions- When the user selects a group. Very similar to the transactions- query but we fetch transactions for several accounts with a CouchDB $in query on the account attribute. transactions-- Similar to the transactions--endDate> , this is when the user has filtered by a group and has navigated to a month via the date selector.", "title": "Transaction page"}, {"location": "cozy-banks/docs/data-fetching/#date-selector", "text": "For the date selector to show the right available options, we need to have the full extent of dates that is available for the particular account/group that we have chosen. Here, we make 2 queries, one for the earliest transaction and one for the latest transaction and then we generate all the months between those two transactions to display the date selector options. Those queries are indexed by date and account and are quick (30ms). While those queries are in flight, the date selector is displayed but not functional.", "title": "Date selector"}, {"location": "cozy-banks/docs/data-fetching/#categories-page", "text": "For this page, we do not need to support infinite loading since we stay in 1 particular month/year. Thus we end up with queries like transactions--- = queries only for the current month transactions, filtered by account and group. useFullyLoadedQuery is used to load all the documents via fetchMore since it is necessary to have all the docs to make aggregate statistics on them.", "title": "Categories page"}, {"location": "cozy-banks/docs/data-fetching/#keeping-previous-data-while-loading-next-one", "text": "To prevent a jarring loading screen while loading the month, the previous query\u2019s data is shown while the next query data is loading. While data is loading, a progress bar is shown below the transaction header.", "title": "Keeping previous data while loading next one"}, {"location": "cozy-banks/docs/demo/", "text": "Demo \u00b6 Fake connectors success state in Cozy Home \u00b6 On demo instances, we use fixtures, not real data. But we need to show some connectors successfully connected in Collect. Here is how to do that : Install a connector via the Store Configure an account that doesn\u2019t exist on this service In the Home, the connector shows an error, it\u2019s normal for the moment Connect to CouchDB of the environment the instance lives on Find the latest job for the connector and update its state to done and remove its error property Find the trigger for the connector and update its arguments to a yearly CRON. For example 0 0 0 15 1 * will run this trigger once every january 15th If the connector frequency is daily, you have to update the job one more time the next day. If the frequency is weekly, you have to update the job one more time the next week. After that, you don\u2019t have to update it before the next year", "title": "Demo"}, {"location": "cozy-banks/docs/demo/#demo", "text": "", "title": "Demo"}, {"location": "cozy-banks/docs/demo/#fake-connectors-success-state-in-cozy-home", "text": "On demo instances, we use fixtures, not real data. But we need to show some connectors successfully connected in Collect. Here is how to do that : Install a connector via the Store Configure an account that doesn\u2019t exist on this service In the Home, the connector shows an error, it\u2019s normal for the moment Connect to CouchDB of the environment the instance lives on Find the latest job for the connector and update its state to done and remove its error property Find the trigger for the connector and update its arguments to a yearly CRON. For example 0 0 0 15 1 * will run this trigger once every january 15th If the connector frequency is daily, you have to update the job one more time the next day. If the frequency is weekly, you have to update the job one more time the next week. After that, you don\u2019t have to update it before the next year", "title": "Fake connectors success state in Cozy Home"}, {"location": "cozy-banks/docs/dev/", "text": "Development \u00b6 Table of Contents \u00b6 Getting started Fixtures Doctypes Continuous build Release Start a release branch Workflow Publish manually on the Cozy registry Notifications How to develop on templates Under the covers Assets Debug notification triggers Emails Push notifications When creating a notification End to end tests Alert rules Automatic tests Manual insertion test Misc Icons Pouch On Web Important credentials Getting started \u00b6 You need to have yarn installed. If you don\u2019t, please check the official documentation and follow the instructions to install it on your system. Then you can install the dependencies: $ yarn Install the fixtures: $ yarn fixtures Build the app: $ yarn build And running the app: $ yarn start Please note that for the project to work, you will need to have a working cozy-stack. See how to run a cozy application for more information. When watching, you still need to have a cozy-stack running to serve the files of the app (do not use the webpack-dev-server directly). This is important as the stack injects through template variables the token and domain used to connect to the cozy. \u26a0\ufe0f CSPs must be disabled when working with the development server (as the index.html is served via the stack but the JS assets are served via webpack-dev-server). You can do this via a browser extension ( Chrome ) or you can tell the stack to disable CSPs via its config file ( disable_csp: true , check here for more info on the config file). See an example config file here . Fixtures \u00b6 While developing, it is convenient to be able to inject and remove arbitrary data on your local instance. You can add fixtures by installing ACH globally and using data from test/fixtures . We have a set of fake banking data in the test/fixtures/demo.json file that you can inject in your instance using the yarn fixtures command. If you want to inject other data or remove some data, you can use ACH . Doctypes \u00b6 The doctypes used in Banks are described in the cozy-doctypes repository. Continuous build \u00b6 The application is built automatically and published on Cozy Registry by Travis . Release \u00b6 A release consists in publishing the app on all platforms: web (via the Cozy Registry ), Android (via the Google Play Store, APKs are also linked to Github releases ) and iOS (via the App Store). Start a release branch \u00b6 When starting a release, start the checklist PR with: yarn release This will ask for the next version number and create a release branch with it. If you have Hub installed (recommended), it will also create the related pull request for you. Workflow \u00b6 When a release branch is created, features are frozen and the branch should only receive bugfixes. To create beta versions, you have to do two things: Commit it and create a tag with the X.Y.Z-beta.M scheme (for example 1.5.0-beta.1 ) and push them The web app beta version will be automatically built and published on the cozy registry. An APK for Android will also be automatically created. For iOS, you have to build the app and upload it on Testflight. Publish manually on the Cozy registry \u00b6 To publish manually on the Cozy registry, you need a token also stored in Cozy internal password store : export REGISTRY_TOKEN=`pass registry/spaces/banks/banks.token` After, you can use cozy-app-publish to push the app to the registry. More information : https://github.com/cozy/cozy-stack/blob/master/docs/registry-publish.md Notifications \u00b6 How to develop on templates \u00b6 With the TEST_TEMPLATES environment variable, an express server serving the HTML emails will be built. $ env TEST_TEMPLATES = true yarn watch:services $ node build/testTemplates.js Rendering emails at http://localhost:8081! You can open your browser to check the emails. The Preview feature in Mailchimp is also useful to check that everything is correctly rendered on the various email clients (just copy/paste the content of the page). Under the covers \u00b6 The templates are Handlebars templates using the mjml language. mjml greatly reduces the pains to develop an email template as it deals with a lot of quirks for you. It features ready-made components to make responsive email templates. Behind the scene, it uses React to implement custom components, and juice to inline the CSS into the HTML. The handlebars-layouts plugin is used to provide an easy way to extend a base template (\u00e0 la jinja ) Other templates : nodemon --exec \"node transactions-notification.js\" -e js,css,hbs,json Assets \u00b6 Assets in assets/ are uploaded to https://downcloud.cozycloud.cc on every deployment on CI. It can also be done manually with the yarn uploadStaticFiles script. Debug notification triggers \u00b6 To debug notifications, you have to launch a watch on the notifications.js and then launch it with cozy-run-dev . \u26a0\ufe0f You have to temporarily add io.cozy.accounts to your manifest so that you can create a dev account to test the service. \"type\": \"io.cozy.notifications\", \"verbs\": [\"POST\"] }, + \"account\": { + \"description\": \"Used to send notifications\", + \"type\": \"io.cozy.accounts\", + \"verbs\": [\"POST\"] + }, \"bank.settings\": { \"description\": \"Used to manage your bank settings\", \"type\": \"io.cozy.bank.settings\", $ yarn watch:services # will continuously build `build/notifications.js` $ nodemon --delay 1 -w build/notifications.js --exec \"cozy-konnector-dev -t /tmp/token.json -m manifest.webapp build/notifications.js\" # will launch build/notifications.js (and relaunch it when it changes) with the right COZY_CREDENTIALS, /tmp/token.json is where the token will be stored Emails \u00b6 To see the emails that the stack sends, launch a MailHog instance : docker run -p 1025:1025 -p 8025:8025 mailhog/mailhog The stack will send the emails through the SMTP port of MailHog and you will be able to see the mails in its web interface on http://localhost:8025. Push notifications \u00b6 Similarly, to debug push notifications, you can configure the stack to send push notifications to a local server, and launch a fake push notifications server locally. env PORT=3001 node test/e2e/mock-server.js To configure the stack, edit your cozy.yml config file: + notifications: + android_api_key: 'fake_android_api_key' + fcm_server: 'http://localhost:3001' https://github.com/cozy/cozy-banks/tree/master/src/ducks/notifications/html When creating a notification \u00b6 If you want to test the notifications in a workflow that is very close to the real one, you can import some fixtures to trigger the service execution. For that, you must open the test/fixtures/operations-notifs.json file and edit the following : the _id field of the documents, so they are unique and will create a new document the account field of the io.cozy.bank.operations documents to match an account id that exist on the instance you will import the fixtures to the dates and the labels to be able to see the imported documents easily Then you can use ACH to import the fixtures : ACH import test/fixtures/notifications-service/operations-notifs.json test/fixtures/helpers/index.js --url End to end tests \u00b6 Alert rules \u00b6 Automatic tests \u00b6 Alert rules are tested with automatic tests that Inserts data inside the local cozy-stack Launches the onOperationOrBillCreate service Checks on mailhog the emails received Checks on a mock push server the push notifications received $ export COZY_URL = http://cozy.tools:8080 $ export COZY_CREDENTIALS = $( cozy-stack instances token-app cozy.tools:8080 banks ) $ docker run -p 1025 :1025 -p 8025 :8025 mailhog/mailhog # Deactivate minification with minimize: false in webpack.optimize inside webpack.target.services.js $ env NODE_ENV = services:production yarn webpack --config webpack.config.js --bail --watch $ yarn test:e2e:alerts At the moment, it needs to be launched on the computer of the developer but should be done on the CI in the future. \u26a0\ufe0f You need to have the services built for production for E2E tests to work. \u26a0\ufe0f For push notifications tests to work, you need first to configure the stack so that it uses a fake server that will receive push notifications. Add this to your stack config file : notifications : android_api_key : 'fake_android_api_key' fcm_server : 'http://localhost:3001' Manual insertion test \u00b6 To test on a real Cozy, a script can insert fake transactions on accounts corresponding to alerts, for the onOperationOrBillCreate service to be started. # Insert fake transactions yarn test:e2e:alerts-existing-cozy --url https://mydemocozy.mycozy.cloud insert # Cleanup fake transactions yarn test:e2e:alerts-existing-cozy --url https://mydemocozy.mycozy.cloud cleanup Misc \u00b6 Icons \u00b6 \ud83d\uddbc The PNG icons that are included in the emails are generated manually from the SVG via scripts/icons-to-png.sh and uploaded automatically to files.cozycloud.cc via Jenkins (which follows the file files.cozycloud.cc at the root of the repo). Pouch On Web \u00b6 If you want activate Pouch on web app, you need: - a token - launch your build with FORCE_POUCH cozy-stack instances token-cli cozy.tools:8080 $(cat manifest.webapp | jq -r '[.permissions[] | .type] | join(\" \")') env FORCE_POUCH=true yarn start Launch your web application and in console javascript fill in the token and refresh the page: flag('cozyToken', ) Now you can play with replication: cozyClient.links[0].startReplication() cozyClient.links[0].stopReplication() Important credentials \u00b6 All important credentials are stored in Cozy internal password store .", "title": "Development"}, {"location": "cozy-banks/docs/dev/#development", "text": "", "title": "Development"}, {"location": "cozy-banks/docs/dev/#table-of-contents", "text": "Getting started Fixtures Doctypes Continuous build Release Start a release branch Workflow Publish manually on the Cozy registry Notifications How to develop on templates Under the covers Assets Debug notification triggers Emails Push notifications When creating a notification End to end tests Alert rules Automatic tests Manual insertion test Misc Icons Pouch On Web Important credentials", "title": "Table of Contents"}, {"location": "cozy-banks/docs/dev/#getting-started", "text": "You need to have yarn installed. If you don\u2019t, please check the official documentation and follow the instructions to install it on your system. Then you can install the dependencies: $ yarn Install the fixtures: $ yarn fixtures Build the app: $ yarn build And running the app: $ yarn start Please note that for the project to work, you will need to have a working cozy-stack. See how to run a cozy application for more information. When watching, you still need to have a cozy-stack running to serve the files of the app (do not use the webpack-dev-server directly). This is important as the stack injects through template variables the token and domain used to connect to the cozy. \u26a0\ufe0f CSPs must be disabled when working with the development server (as the index.html is served via the stack but the JS assets are served via webpack-dev-server). You can do this via a browser extension ( Chrome ) or you can tell the stack to disable CSPs via its config file ( disable_csp: true , check here for more info on the config file). See an example config file here .", "title": "Getting started"}, {"location": "cozy-banks/docs/dev/#fixtures", "text": "While developing, it is convenient to be able to inject and remove arbitrary data on your local instance. You can add fixtures by installing ACH globally and using data from test/fixtures . We have a set of fake banking data in the test/fixtures/demo.json file that you can inject in your instance using the yarn fixtures command. If you want to inject other data or remove some data, you can use ACH .", "title": "Fixtures"}, {"location": "cozy-banks/docs/dev/#doctypes", "text": "The doctypes used in Banks are described in the cozy-doctypes repository.", "title": "Doctypes"}, {"location": "cozy-banks/docs/dev/#continuous-build", "text": "The application is built automatically and published on Cozy Registry by Travis .", "title": "Continuous build"}, {"location": "cozy-banks/docs/dev/#release", "text": "A release consists in publishing the app on all platforms: web (via the Cozy Registry ), Android (via the Google Play Store, APKs are also linked to Github releases ) and iOS (via the App Store).", "title": "Release"}, {"location": "cozy-banks/docs/dev/#start-a-release-branch", "text": "When starting a release, start the checklist PR with: yarn release This will ask for the next version number and create a release branch with it. If you have Hub installed (recommended), it will also create the related pull request for you.", "title": "Start a release branch"}, {"location": "cozy-banks/docs/dev/#workflow", "text": "When a release branch is created, features are frozen and the branch should only receive bugfixes. To create beta versions, you have to do two things: Commit it and create a tag with the X.Y.Z-beta.M scheme (for example 1.5.0-beta.1 ) and push them The web app beta version will be automatically built and published on the cozy registry. An APK for Android will also be automatically created. For iOS, you have to build the app and upload it on Testflight.", "title": "Workflow"}, {"location": "cozy-banks/docs/dev/#publish-manually-on-the-cozy-registry", "text": "To publish manually on the Cozy registry, you need a token also stored in Cozy internal password store : export REGISTRY_TOKEN=`pass registry/spaces/banks/banks.token` After, you can use cozy-app-publish to push the app to the registry. More information : https://github.com/cozy/cozy-stack/blob/master/docs/registry-publish.md", "title": "Publish manually on the Cozy registry"}, {"location": "cozy-banks/docs/dev/#notifications", "text": "", "title": "Notifications"}, {"location": "cozy-banks/docs/dev/#how-to-develop-on-templates", "text": "With the TEST_TEMPLATES environment variable, an express server serving the HTML emails will be built. $ env TEST_TEMPLATES = true yarn watch:services $ node build/testTemplates.js Rendering emails at http://localhost:8081! You can open your browser to check the emails. The Preview feature in Mailchimp is also useful to check that everything is correctly rendered on the various email clients (just copy/paste the content of the page).", "title": "How to develop on templates"}, {"location": "cozy-banks/docs/dev/#under-the-covers", "text": "The templates are Handlebars templates using the mjml language. mjml greatly reduces the pains to develop an email template as it deals with a lot of quirks for you. It features ready-made components to make responsive email templates. Behind the scene, it uses React to implement custom components, and juice to inline the CSS into the HTML. The handlebars-layouts plugin is used to provide an easy way to extend a base template (\u00e0 la jinja ) Other templates : nodemon --exec \"node transactions-notification.js\" -e js,css,hbs,json", "title": "Under the covers"}, {"location": "cozy-banks/docs/dev/#assets", "text": "Assets in assets/ are uploaded to https://downcloud.cozycloud.cc on every deployment on CI. It can also be done manually with the yarn uploadStaticFiles script.", "title": "Assets"}, {"location": "cozy-banks/docs/dev/#debug-notification-triggers", "text": "To debug notifications, you have to launch a watch on the notifications.js and then launch it with cozy-run-dev . \u26a0\ufe0f You have to temporarily add io.cozy.accounts to your manifest so that you can create a dev account to test the service. \"type\": \"io.cozy.notifications\", \"verbs\": [\"POST\"] }, + \"account\": { + \"description\": \"Used to send notifications\", + \"type\": \"io.cozy.accounts\", + \"verbs\": [\"POST\"] + }, \"bank.settings\": { \"description\": \"Used to manage your bank settings\", \"type\": \"io.cozy.bank.settings\", $ yarn watch:services # will continuously build `build/notifications.js` $ nodemon --delay 1 -w build/notifications.js --exec \"cozy-konnector-dev -t /tmp/token.json -m manifest.webapp build/notifications.js\" # will launch build/notifications.js (and relaunch it when it changes) with the right COZY_CREDENTIALS, /tmp/token.json is where the token will be stored", "title": "Debug notification triggers"}, {"location": "cozy-banks/docs/dev/#emails", "text": "To see the emails that the stack sends, launch a MailHog instance : docker run -p 1025:1025 -p 8025:8025 mailhog/mailhog The stack will send the emails through the SMTP port of MailHog and you will be able to see the mails in its web interface on http://localhost:8025.", "title": "Emails"}, {"location": "cozy-banks/docs/dev/#push-notifications", "text": "Similarly, to debug push notifications, you can configure the stack to send push notifications to a local server, and launch a fake push notifications server locally. env PORT=3001 node test/e2e/mock-server.js To configure the stack, edit your cozy.yml config file: + notifications: + android_api_key: 'fake_android_api_key' + fcm_server: 'http://localhost:3001' https://github.com/cozy/cozy-banks/tree/master/src/ducks/notifications/html", "title": "Push notifications"}, {"location": "cozy-banks/docs/dev/#when-creating-a-notification", "text": "If you want to test the notifications in a workflow that is very close to the real one, you can import some fixtures to trigger the service execution. For that, you must open the test/fixtures/operations-notifs.json file and edit the following : the _id field of the documents, so they are unique and will create a new document the account field of the io.cozy.bank.operations documents to match an account id that exist on the instance you will import the fixtures to the dates and the labels to be able to see the imported documents easily Then you can use ACH to import the fixtures : ACH import test/fixtures/notifications-service/operations-notifs.json test/fixtures/helpers/index.js --url ", "title": "When creating a notification"}, {"location": "cozy-banks/docs/dev/#end-to-end-tests", "text": "", "title": "End to end tests"}, {"location": "cozy-banks/docs/dev/#alert-rules", "text": "", "title": "Alert rules"}, {"location": "cozy-banks/docs/dev/#automatic-tests", "text": "Alert rules are tested with automatic tests that Inserts data inside the local cozy-stack Launches the onOperationOrBillCreate service Checks on mailhog the emails received Checks on a mock push server the push notifications received $ export COZY_URL = http://cozy.tools:8080 $ export COZY_CREDENTIALS = $( cozy-stack instances token-app cozy.tools:8080 banks ) $ docker run -p 1025 :1025 -p 8025 :8025 mailhog/mailhog # Deactivate minification with minimize: false in webpack.optimize inside webpack.target.services.js $ env NODE_ENV = services:production yarn webpack --config webpack.config.js --bail --watch $ yarn test:e2e:alerts At the moment, it needs to be launched on the computer of the developer but should be done on the CI in the future. \u26a0\ufe0f You need to have the services built for production for E2E tests to work. \u26a0\ufe0f For push notifications tests to work, you need first to configure the stack so that it uses a fake server that will receive push notifications. Add this to your stack config file : notifications : android_api_key : 'fake_android_api_key' fcm_server : 'http://localhost:3001'", "title": "Automatic tests"}, {"location": "cozy-banks/docs/dev/#manual-insertion-test", "text": "To test on a real Cozy, a script can insert fake transactions on accounts corresponding to alerts, for the onOperationOrBillCreate service to be started. # Insert fake transactions yarn test:e2e:alerts-existing-cozy --url https://mydemocozy.mycozy.cloud insert # Cleanup fake transactions yarn test:e2e:alerts-existing-cozy --url https://mydemocozy.mycozy.cloud cleanup", "title": "Manual insertion test"}, {"location": "cozy-banks/docs/dev/#misc", "text": "", "title": "Misc"}, {"location": "cozy-banks/docs/dev/#icons", "text": "\ud83d\uddbc The PNG icons that are included in the emails are generated manually from the SVG via scripts/icons-to-png.sh and uploaded automatically to files.cozycloud.cc via Jenkins (which follows the file files.cozycloud.cc at the root of the repo).", "title": "Icons"}, {"location": "cozy-banks/docs/dev/#pouch-on-web", "text": "If you want activate Pouch on web app, you need: - a token - launch your build with FORCE_POUCH cozy-stack instances token-cli cozy.tools:8080 $(cat manifest.webapp | jq -r '[.permissions[] | .type] | join(\" \")') env FORCE_POUCH=true yarn start Launch your web application and in console javascript fill in the token and refresh the page: flag('cozyToken', ) Now you can play with replication: cozyClient.links[0].startReplication() cozyClient.links[0].stopReplication()", "title": "Pouch On Web"}, {"location": "cozy-banks/docs/dev/#important-credentials", "text": "All important credentials are stored in Cozy internal password store .", "title": "Important credentials"}, {"location": "cozy-banks/docs/notifications/", "text": "Notifications \u00b6 When you launch Cozy Banks mobile application (iOS and Android), the app asks the right to push notifications. You can configure notifications directly on your Settings. By example when movement amount is greater than 30\u20ac. Technique \u00b6 We use cordova plugin to make this possible. When the mobile app connects to your Cozy, it creates an oauth client with notificationPlatform: firebase parameter. So Cozy Stack know you can receive notification on your mobile. Test \u00b6 COZY_DOMAIN=recette.cozy.works && \\ curl -X POST \"https://$COZY_DOMAIN/jobs/queue/push\" \\ -H \"Authorization: Bearer $(cozy-stack instances token-cli $COZY_DOMAIN io.cozy.jobs)\" \\ -H \"Accept: text/event-stream\" \\ -H \"Content-Type: application-json\" \\ -d'{\"data\":{\"attributes\":{\"arguments\":{\"platform\": \"firebase\", \"source\": \"toto\", \"title\": \"Mon Titre\", \"message\": \"Mon message !!!\", \"data\": {\"foo\": \"bar\"}}}}}' How to test push notifications \u00b6 Edit your cozy.yaml (ex: ~/.cozy/cozy.yaml ) Add notifications contexts : dev : ... notifications : android_api_key : \"fake_android_api_key\" fcm_server : \"http://localhost:3001\" In Fauxton - \u2026/io-cozy-oauth-clients doctype Edit a document and add the fields: notification_platform and notification_device_token : ... \"software_id\" : \"...\" , \"notification_platform\" : \"android\" , \"notification_device_token\" : \"fake-token\" , ... Add a document in \u2026/io-cozy-bank-operations doctype Ex: To test TransactionGreater, create a document with an amount greater than your settings value. Using operation-generic.json might be useful. $ ach import test/fixtures/matching-service/operation-generic.json -u http://cozy.localhost:8080/ In a shell $ env PORT = 3001 node test/e2e/mock-server.js In an other shell $ yarn watch:services In an other shell $ export COZY_URL = http://cozy.localhost:8080 $ export COZY_CREDENTIALS = $( cozy-stack instances token-app cozy.localhost:8080 banks ) $ node build/onOperationOrBillCreate.js You should receive your notification : Received push notification { to: 'fake-token' , content_available: true, notification: { title: 'Transaction greater than 10\u20ac' , body: 'SNCF: +300EUR' } , data: { body: 'SNCF: +300EUR' , notId: 149956241 , route: '/balances/461ef7bdb566ef19d28d976a230162d8/details' , title: '1 Transaction greater than 10\u20ac' } }", "title": "Notifications"}, {"location": "cozy-banks/docs/notifications/#notifications", "text": "When you launch Cozy Banks mobile application (iOS and Android), the app asks the right to push notifications. You can configure notifications directly on your Settings. By example when movement amount is greater than 30\u20ac.", "title": "Notifications"}, {"location": "cozy-banks/docs/notifications/#technique", "text": "We use cordova plugin to make this possible. When the mobile app connects to your Cozy, it creates an oauth client with notificationPlatform: firebase parameter. So Cozy Stack know you can receive notification on your mobile.", "title": "Technique"}, {"location": "cozy-banks/docs/notifications/#test", "text": "COZY_DOMAIN=recette.cozy.works && \\ curl -X POST \"https://$COZY_DOMAIN/jobs/queue/push\" \\ -H \"Authorization: Bearer $(cozy-stack instances token-cli $COZY_DOMAIN io.cozy.jobs)\" \\ -H \"Accept: text/event-stream\" \\ -H \"Content-Type: application-json\" \\ -d'{\"data\":{\"attributes\":{\"arguments\":{\"platform\": \"firebase\", \"source\": \"toto\", \"title\": \"Mon Titre\", \"message\": \"Mon message !!!\", \"data\": {\"foo\": \"bar\"}}}}}'", "title": "Test"}, {"location": "cozy-banks/docs/notifications/#how-to-test-push-notifications", "text": "Edit your cozy.yaml (ex: ~/.cozy/cozy.yaml ) Add notifications contexts : dev : ... notifications : android_api_key : \"fake_android_api_key\" fcm_server : \"http://localhost:3001\" In Fauxton - \u2026/io-cozy-oauth-clients doctype Edit a document and add the fields: notification_platform and notification_device_token : ... \"software_id\" : \"...\" , \"notification_platform\" : \"android\" , \"notification_device_token\" : \"fake-token\" , ... Add a document in \u2026/io-cozy-bank-operations doctype Ex: To test TransactionGreater, create a document with an amount greater than your settings value. Using operation-generic.json might be useful. $ ach import test/fixtures/matching-service/operation-generic.json -u http://cozy.localhost:8080/ In a shell $ env PORT = 3001 node test/e2e/mock-server.js In an other shell $ yarn watch:services In an other shell $ export COZY_URL = http://cozy.localhost:8080 $ export COZY_CREDENTIALS = $( cozy-stack instances token-app cozy.localhost:8080 banks ) $ node build/onOperationOrBillCreate.js You should receive your notification : Received push notification { to: 'fake-token' , content_available: true, notification: { title: 'Transaction greater than 10\u20ac' , body: 'SNCF: +300EUR' } , data: { body: 'SNCF: +300EUR' , notId: 149956241 , route: '/balances/461ef7bdb566ef19d28d976a230162d8/details' , title: '1 Transaction greater than 10\u20ac' } }", "title": "How to test push notifications"}, {"location": "cozy-banks/docs/perfs/", "text": "Measuring Banks performance \u00b6 There is ongoing work on improving Banks performance for people for have a lot of banking data. Fixtures \u00b6 To test more easily performance and performance regressions, fixtures can be created with adjustable number of documents for each doctype. This will help us measure performances on large cozies and in the future have performance regression tests. Medium fixture \u00b6 100 io.cozy.bills 10 io.cozy.bank.accounts 3000 io.cozy.bank.operations 3 io.cozy.bank.groups Saved to fixtures-m.json Approximatively 3 years saved Size of the fixture file : 1.2M Large fixture \u00b6 1000 io.cozy.bills 50 io.cozy.bank.accounts 20000 io.cozy.bank.operations 15 io.cozy.bank.groups", "title": "Measuring Banks performance"}, {"location": "cozy-banks/docs/perfs/#measuring-banks-performance", "text": "There is ongoing work on improving Banks performance for people for have a lot of banking data.", "title": "Measuring Banks performance"}, {"location": "cozy-banks/docs/perfs/#fixtures", "text": "To test more easily performance and performance regressions, fixtures can be created with adjustable number of documents for each doctype. This will help us measure performances on large cozies and in the future have performance regression tests.", "title": "Fixtures"}, {"location": "cozy-banks/docs/perfs/#medium-fixture", "text": "100 io.cozy.bills 10 io.cozy.bank.accounts 3000 io.cozy.bank.operations 3 io.cozy.bank.groups Saved to fixtures-m.json Approximatively 3 years saved Size of the fixture file : 1.2M", "title": "Medium fixture"}, {"location": "cozy-banks/docs/perfs/#large-fixture", "text": "1000 io.cozy.bills 50 io.cozy.bank.accounts 20000 io.cozy.bank.operations 15 io.cozy.bank.groups", "title": "Large fixture"}, {"location": "cozy-banks/docs/services/", "text": "Services \u00b6 This document describes services running as part of the Banks application. Developing Services Categorization onOperationOrBillCreate Automatic groups Budget alerts Recurrences Konnector alerts I am writing a banking konnector, what should I do? Developing \u00b6 You can manually create an app token and launch the built service. # Watch services $ yarn watch $ export COZY_URL = 'http://cozy.localhost:8080' $ export COZY_CREDENTIALS = $( cozy-stack instances token-app cozy.localhost:8080 banks ) $ node build/services/budgetAlerts/banks.js Services \u00b6 Categorization \u00b6 slug: categorization This service role is to categorize transactions. It is bound to no event at all, so it\u2019s not automatically triggered and needs to be explicitly called by a konnector or another service. This service is called from konnectors so that transactions are categorized as soon as possible (no debounce involved). When this service is ran, it gets all io.cozy.bank.operations that has the toCategorize property with a true value. Then it slices it into chunks and categorizes the most chunks it can before the service is stopped by the stack. If there are some uncategorized transactions remaining, it restarts itself to finish the work. If all transactions have been categorized, it calls the onOperationOrBillCreate service to trigger all other features. See the categorization documentation for more details about the categorization implementation. onOperationOrBillCreate \u00b6 slug: onOperationOrBillCreate This service has many roles. It does: Bills matching Notifications (push & email) Apps suggestions A PR is opened to have stateful notifications, please check it before doing more work on notifications. It is bound to the io.cozy.bills creation only. The creation of io.cozy.bank.operations should be managed by calling the categorization service. See the next section for more precise informations about that. Automatic groups \u00b6 slug: autogroups Whenever an io.cozy.bank.accounts is created, we check if it could belong in an automatic group based on its type (checkings, savings, credit cards). These io.cozy.bank.groups documents are created with the auto: true attributes. \u2139\ufe0f This service can be run via CLI via yarn service:autogroups Budget alerts \u00b6 slug: budgetAlerts A user can configure alerts to be alerted whenever the sum of its expenses has gone past a maximum threshold per month. The notification is sent as part of the onOperationOrBillCreate service. It is configured from a io.cozy.bank.settings document and the last notification date and amount are saved. A debug service is built to be able to only run this particular part and not the whole onOperationOrBillCreate service. It is possible to run it from the Debug tab in the application (or via Bender). Recurrences \u00b6 slug: recurrence Tries to find recurrence groups when new operations are inserted in the Cozy. It either creates new recurrence groups or attaches transactions to existing recurrence groups. See Paper \u201cPaiements recurrents\u201d for more information on the service. \u2139\ufe0f This service can be run via CLI via yarn service recurrence Konnector alerts \u00b6 slug: konnectorAlerts It monitors the jobs and sends a notification when a konnector has failed. Here are the rules for those notifications: They should only be sent for LOGIN_FAILED and USER_ACTION_NEEDED errors They should only be sent for automatic jobs (not manual) We should not send a notification if the state stays the same The service also determines if a delayed notification schedule at D+3 and D+7 is necessary. When a notification is scheduled, if there are no future reminders, the service will create them. \u2139\ufe0f This service can be run via CLI via yarn service konnectorAlerts Import \u00b6 slug: import Allows you to import bank data into Cozy, from the Cozy bank export file (.csv format) This service is launched manually once the import of the file has been successful on the cozy. It also saves the number of imported transactions in the doctype io.cozy.bank.settings ( lastImportSuccess.savedTransactionsCount ) \u2139\ufe0f This service can be run via CLI via yarn service import I am writing a banking konnector, what should I do? \u00b6 If you want to benefit from all the features of these services, the most straightforward is to add toCategorize: true to the io.cozy.bank.operations your konnector creates, save these documents and then call the categorization service. Here is an example: const { cozyClient , BaseKonnector } = require ( 'cozy-konnector-libs' ) class MyKonnector extends BaseKonnector { async saveTransactions () { const transactions = await this . fetchTransactions () transactions . forEach ( t => ( t . toCategorize = true )) // save `transactions` await cozyClient . jobs . create ( 'service' , { name : 'categorization' , slug : 'banks' }) } } Finally, you will need a permission to create io.cozy.jobs document. Add the following permission to your manifest.konnector : { \"permissions\" : { \"jobs\" : { \"description\" : \"Required to run applications services\" , \"type\" : \"io.cozy.jobs\" } } } With this, the transactions you created will be categorized, then the onOperationOrBillCreate service will be launched and do its work.", "title": "Services"}, {"location": "cozy-banks/docs/services/#services", "text": "This document describes services running as part of the Banks application. Developing Services Categorization onOperationOrBillCreate Automatic groups Budget alerts Recurrences Konnector alerts I am writing a banking konnector, what should I do?", "title": "Services"}, {"location": "cozy-banks/docs/services/#developing", "text": "You can manually create an app token and launch the built service. # Watch services $ yarn watch $ export COZY_URL = 'http://cozy.localhost:8080' $ export COZY_CREDENTIALS = $( cozy-stack instances token-app cozy.localhost:8080 banks ) $ node build/services/budgetAlerts/banks.js", "title": "Developing"}, {"location": "cozy-banks/docs/services/#services_1", "text": "", "title": "Services"}, {"location": "cozy-banks/docs/services/#categorization", "text": "slug: categorization This service role is to categorize transactions. It is bound to no event at all, so it\u2019s not automatically triggered and needs to be explicitly called by a konnector or another service. This service is called from konnectors so that transactions are categorized as soon as possible (no debounce involved). When this service is ran, it gets all io.cozy.bank.operations that has the toCategorize property with a true value. Then it slices it into chunks and categorizes the most chunks it can before the service is stopped by the stack. If there are some uncategorized transactions remaining, it restarts itself to finish the work. If all transactions have been categorized, it calls the onOperationOrBillCreate service to trigger all other features. See the categorization documentation for more details about the categorization implementation.", "title": "Categorization"}, {"location": "cozy-banks/docs/services/#onoperationorbillcreate", "text": "slug: onOperationOrBillCreate This service has many roles. It does: Bills matching Notifications (push & email) Apps suggestions A PR is opened to have stateful notifications, please check it before doing more work on notifications. It is bound to the io.cozy.bills creation only. The creation of io.cozy.bank.operations should be managed by calling the categorization service. See the next section for more precise informations about that.", "title": "onOperationOrBillCreate"}, {"location": "cozy-banks/docs/services/#automatic-groups", "text": "slug: autogroups Whenever an io.cozy.bank.accounts is created, we check if it could belong in an automatic group based on its type (checkings, savings, credit cards). These io.cozy.bank.groups documents are created with the auto: true attributes. \u2139\ufe0f This service can be run via CLI via yarn service:autogroups", "title": "Automatic groups"}, {"location": "cozy-banks/docs/services/#budget-alerts", "text": "slug: budgetAlerts A user can configure alerts to be alerted whenever the sum of its expenses has gone past a maximum threshold per month. The notification is sent as part of the onOperationOrBillCreate service. It is configured from a io.cozy.bank.settings document and the last notification date and amount are saved. A debug service is built to be able to only run this particular part and not the whole onOperationOrBillCreate service. It is possible to run it from the Debug tab in the application (or via Bender).", "title": "Budget alerts"}, {"location": "cozy-banks/docs/services/#recurrences", "text": "slug: recurrence Tries to find recurrence groups when new operations are inserted in the Cozy. It either creates new recurrence groups or attaches transactions to existing recurrence groups. See Paper \u201cPaiements recurrents\u201d for more information on the service. \u2139\ufe0f This service can be run via CLI via yarn service recurrence", "title": "Recurrences"}, {"location": "cozy-banks/docs/services/#konnector-alerts", "text": "slug: konnectorAlerts It monitors the jobs and sends a notification when a konnector has failed. Here are the rules for those notifications: They should only be sent for LOGIN_FAILED and USER_ACTION_NEEDED errors They should only be sent for automatic jobs (not manual) We should not send a notification if the state stays the same The service also determines if a delayed notification schedule at D+3 and D+7 is necessary. When a notification is scheduled, if there are no future reminders, the service will create them. \u2139\ufe0f This service can be run via CLI via yarn service konnectorAlerts", "title": "Konnector alerts"}, {"location": "cozy-banks/docs/services/#import", "text": "slug: import Allows you to import bank data into Cozy, from the Cozy bank export file (.csv format) This service is launched manually once the import of the file has been successful on the cozy. It also saves the number of imported transactions in the doctype io.cozy.bank.settings ( lastImportSuccess.savedTransactionsCount ) \u2139\ufe0f This service can be run via CLI via yarn service import", "title": "Import"}, {"location": "cozy-banks/docs/services/#i-am-writing-a-banking-konnector-what-should-i-do", "text": "If you want to benefit from all the features of these services, the most straightforward is to add toCategorize: true to the io.cozy.bank.operations your konnector creates, save these documents and then call the categorization service. Here is an example: const { cozyClient , BaseKonnector } = require ( 'cozy-konnector-libs' ) class MyKonnector extends BaseKonnector { async saveTransactions () { const transactions = await this . fetchTransactions () transactions . forEach ( t => ( t . toCategorize = true )) // save `transactions` await cozyClient . jobs . create ( 'service' , { name : 'categorization' , slug : 'banks' }) } } Finally, you will need a permission to create io.cozy.jobs document. Add the following permission to your manifest.konnector : { \"permissions\" : { \"jobs\" : { \"description\" : \"Required to run applications services\" , \"type\" : \"io.cozy.jobs\" } } } With this, the transactions you created will be categorized, then the onOperationOrBillCreate service will be launched and do its work.", "title": "I am writing a banking konnector, what should I do?"}, {"location": "cozy-banks/docs/tracking/", "text": "Tracking events \u00b6 Bills matching service \u00b6 Event Category Event Action Event name Event value Description Banks BillsMatching BillWithoutId No value We tried to add a bill to a transaction, but it doesn\u2019t have an ID, so we couldn\u2019t Banks BillsMatching BillAmountOverflowingOperationAmount No value We tried to add a bill to a transaction, but the sum of its amount and already linked bills amounts would overflow the transaction amount, so we couldn\u2019t Banks BillsMatching BillsMatched Number of matched bills Some bills matched with operations", "title": "Tracking events"}, {"location": "cozy-banks/docs/tracking/#tracking-events", "text": "", "title": "Tracking events"}, {"location": "cozy-banks/docs/tracking/#bills-matching-service", "text": "Event Category Event Action Event name Event value Description Banks BillsMatching BillWithoutId No value We tried to add a bill to a transaction, but it doesn\u2019t have an ID, so we couldn\u2019t Banks BillsMatching BillAmountOverflowingOperationAmount No value We tried to add a bill to a transaction, but the sum of its amount and already linked bills amounts would overflow the transaction amount, so we couldn\u2019t Banks BillsMatching BillsMatched Number of matched bills Some bills matched with operations", "title": "Bills matching service"}, {"location": "cozy-banks/scripts/visualizer/", "text": "Link visualizer \u00b6 This is an express server that serves a webpage meant to show links that are found between bills and banking operations by our matching algorithm. To launch the server, run the following commands: yarn build yarn serve Then you can go to http://localhost:3000. There you have a minimal interface where you can trigger a search for links between bills and operations. Developing \u00b6 To develop, you can use watch mode. Client \u00b6 For the client, you can run yarn watch:client . This will watch front-end files and compile them to the dist folder served by the express server. Also, yarn build:client will compile the client one time. Server \u00b6 For the server, you can run yarn watch:server to compile the server on every change, and yarn serve:watch to restart the server everytime it has been compiled. yarn build:server will compile the server one time.", "title": "Index"}, {"location": "cozy-banks/scripts/visualizer/#link-visualizer", "text": "This is an express server that serves a webpage meant to show links that are found between bills and banking operations by our matching algorithm. To launch the server, run the following commands: yarn build yarn serve Then you can go to http://localhost:3000. There you have a minimal interface where you can trigger a search for links between bills and operations.", "title": "Link visualizer"}, {"location": "cozy-banks/scripts/visualizer/#developing", "text": "To develop, you can use watch mode.", "title": "Developing"}, {"location": "cozy-banks/scripts/visualizer/#client", "text": "For the client, you can run yarn watch:client . This will watch front-end files and compile them to the dist folder served by the express server. Also, yarn build:client will compile the client one time.", "title": "Client"}, {"location": "cozy-banks/scripts/visualizer/#server", "text": "For the server, you can run yarn watch:server to compile the server on every change, and yarn serve:watch to restart the server everytime it has been compiled. yarn build:server will compile the server one time.", "title": "Server"}, {"location": "cozy-banks/src/components/DisplayError/", "text": "< DisplayError error = { new Error ( 'Burrito does not have extra guacamole' ) } />", "title": "DisplayError"}, {"location": "cozy-banks/src/components/Select/", "text": "const Select = require ( './Select.jsx' ). default const options = [ { name : 'Burritos' , value : 'burritos' }, { name : 'Lasagnes' , value : 'lasagnes' }, { name : 'G\u00e2teau au chocolat' , value : 'gateau' } ] const log = function ( selectName , selectValue ) { console . log ( selectName , selectValue ) }; < Select name = 'nourriture' value = 'burritos' options = { options } onChange = { log } />", "title": "Select"}, {"location": "cozy-banks/src/components/Switch/", "text": "
    ", "title": "Switch"}, {"location": "cozy-banks/src/components/Chart/LineChart/", "text": "< LineChart width = { 300 } height = { 150 } data = {[ { x : 0 , y : 0 }, { x : 1 , y : 2 }, { x : 2 , y : 4 }, { x : 3 , y : 6 } ]} margin = {{ top : 0 , bottom : 20 , left : 10 , right : 10 }} showAxis /> const d3 = require ( 'd3' ); < LineChart width = { 300 } height = { 150 } data = {[ { x : new Date ( 2018 , 7 , 3 ), y : 0 }, { x : new Date ( 2018 , 7 , 2 ), y : 2 }, { x : new Date ( 2018 , 7 , 1 ), y : 4 }, { x : new Date ( 2018 , 6 , 31 ), y : 6 } ]} margin = {{ top : 0 , bottom : 20 , left : 10 , right : 10 }} nbTicks = { 2 } tickFormat = { d3 . timeFormat ( '%x' )} xScale = { d3 . scaleTime } showAxis /> const d3 = require ( 'd3' ); < LineChart width = { 300 } height = { 150 } data = {[ { x : new Date ( 2018 , 7 , 3 ), y : 0 }, { x : new Date ( 2018 , 7 , 2 ), y : 2 }, { x : new Date ( 2018 , 7 , 1 ), y : 4 }, { x : new Date ( 2018 , 6 , 31 ), y : 6 } ]} margin = {{ top : 0 , bottom : 20 , left : 10 , right : 10 }} nbTicks = { 2 } tickFormat = { d3 . timeFormat ( '%x' )} xScale = { d3 . scaleTime } gradient = {{ '0%' : 'steelblue' , '100%' : 'white' }} showAxis />", "title": "LineChart"}, {"location": "cozy-banks/src/components/KonnectorChip/readme/", "text": "
    ", "title": "Readme"}, {"location": "cozy-banks/src/components/Loading/Loading/", "text": "< Loading />", "title": "Loading"}, {"location": "cozy-banks/src/components/Select/Readme/", "text": "const Select = require('react-select').default const handleChangeMonth = value => { setState({ value }) }; ", "title": "Readme"}, {"location": "cozy-banks/src/components/SelectDates/Readme/", "text": "const SelectDates = require ( './SelectDates' ) . default ; initialState = { value : undefined } ; < SelectDates periods = { [ '2018-08' , '2018-07' , '2018-06' , '2017-05' ] } value = { state.value } onChange = { value => setState({ value } ) } show12months />", "title": "Readme"}, {"location": "cozy-banks/src/components/SharingIcon/SharingIcon/", "text": "< div > < SharingIcon to = 'Richard Stallman' />< br /> < SharingIcon from = 'Rob Pike' />< br /> < SharingIcon from = 'Ken Thompson' /> With text beside ", "title": "SharingIcon"}, {"location": "cozy-banks/src/components/Table/Readme/", "text": "const col1 = { 'flex-basis' : '35%' , 'max-width' : '35%' }; const col2 = { 'flex-basis' : '35%' , 'max-width' : '35%' }; const col3 = { 'flex-basis' : '30%' , 'max-width' : '30%' }; < Table > < thead > < tr > < th style = { col1 }> Pizzas < th style = { col2 }> Burritos < th style = { col3 }> Shawarma < tbody > < tr > < td style = { col1 }> 1 < td style = { col2 }> 2 < td style = { col3 }> 3 < tr > < td style = { col1 }> 4 < td style = { col2 }> 5 < td style = { col3 }> 6 ", "title": "Readme"}, {"location": "cozy-banks/src/ducks/balance/AccountRow/", "text": "", "title": "AccountRow"}, {"location": "cozy-banks/src/ducks/balance/History/", "text": "const data = require ( '../../../test/fixtures/unit-tests.json' ); < History accounts = { data [ 'io.cozy.bank.accounts' ]} chartProps = {{ data : [ { x : new Date ( 2018 , 7 , 3 ), y : 0 }, { x : new Date ( 2018 , 7 , 2 ), y : 2 }, { x : new Date ( 2018 , 7 , 1 ), y : 4 }, { x : new Date ( 2018 , 6 , 31 ), y : 6 } ], width : '100%' }} />", "title": "History"}, {"location": "cozy-banks/src/ducks/filters/Readme/", "text": "", "title": "Readme"}, {"location": "cozy-banks/src/targets/services/", "text": "See docs/service.md", "title": "Index"}, {"location": "cozy-banks/test/fixtures/", "text": "This fixtures contains bank operations linked to files. It will create a directory in your Cozy. Fichiers_de_d\u00e9mo/ \u251c\u2500\u2500 Free mobile \u2502 \u251c\u2500\u2500 Demo_cozy-freemobile_15082017.pdf \u2502 \u2514\u2500\u2500 Demo_cozy-freemobile_15092017.pdf \u251c\u2500\u2500 MAIF \u2502 \u2514\u2500\u2500 Demo_cozy-Appel_cotisation_MAIF_2017.pdf \u2514\u2500\u2500 Partag\u00e9 par Genevi\u00e8ve \u2514\u2500\u2500 Bouygues Telecom \u251c\u2500\u2500 Demo_cozy-Bouygues_Telecom_30072017.pdf \u2514\u2500\u2500 Demo_cozy-Bouygues_Telecom_30082017.pdf Usage \u00b6 ACH import demo.json helpers / index . js Other fixtures \u00b6 The reference file is demo.json . Other files should follow it. fixtures-l.json and fixtures-m.json are there if you want to test performance issue https://github.com/cozy/cozy-banks/blob/master/docs/perfs.md There are also more focused files that can be used to test specific usecases. See: Matching service Notifications service", "title": "Index"}, {"location": "cozy-banks/test/fixtures/#usage", "text": "ACH import demo.json helpers / index . js", "title": "Usage"}, {"location": "cozy-banks/test/fixtures/#other-fixtures", "text": "The reference file is demo.json . Other files should follow it. fixtures-l.json and fixtures-m.json are there if you want to test performance issue https://github.com/cozy/cozy-banks/blob/master/docs/perfs.md There are also more focused files that can be used to test specific usecases. See: Matching service Notifications service", "title": "Other fixtures"}, {"location": "cozy-banks/test/fixtures/matching-service/", "text": "Fixtures matching service \u00b6 Theses fixtures are useful to test the bills matching service. They cover the following cases. Classic matching \u00b6 Inject bill-generic.json and operation-generic.json . The service should run in the next 3 minutes (in you didn\u2019t customized the debounce time in manifest.webapp ). After that, if everything went well, you must have a link between the operation and the bill from the fixtures (ie. the operation has a bills array containing the bill ID). Health reimbursement \u00b6 Inject bill-reimbursement.json and operation-reimbursement.json . The service should run in the next 3 minutes (in you didn\u2019t customized the debounce time in manifest.webapp ). After that, if everything went well, you must have a link between the operation Visite chez le m\u00e9decin and the bill from the fixtures (ie. the operation has a reimbursement array containing the bill ID).", "title": "Fixtures matching service"}, {"location": "cozy-banks/test/fixtures/matching-service/#fixtures-matching-service", "text": "Theses fixtures are useful to test the bills matching service. They cover the following cases.", "title": "Fixtures matching service"}, {"location": "cozy-banks/test/fixtures/matching-service/#classic-matching", "text": "Inject bill-generic.json and operation-generic.json . The service should run in the next 3 minutes (in you didn\u2019t customized the debounce time in manifest.webapp ). After that, if everything went well, you must have a link between the operation and the bill from the fixtures (ie. the operation has a bills array containing the bill ID).", "title": "Classic matching"}, {"location": "cozy-banks/test/fixtures/matching-service/#health-reimbursement", "text": "Inject bill-reimbursement.json and operation-reimbursement.json . The service should run in the next 3 minutes (in you didn\u2019t customized the debounce time in manifest.webapp ). After that, if everything went well, you must have a link between the operation Visite chez le m\u00e9decin and the bill from the fixtures (ie. the operation has a reimbursement array containing the bill ID).", "title": "Health reimbursement"}, {"location": "cozy-banks/test/fixtures/notifications-service/", "text": "Fixtures notifications service \u00b6 Theses fixtures are useful to test the notifications service. They trigger all notifications types. Just make sure that you have enabled the types you want to test (check directly in Banks\u2019 settings page, or in the io.cozy.bank.settings database).", "title": "Fixtures notifications service"}, {"location": "cozy-banks/test/fixtures/notifications-service/#fixtures-notifications-service", "text": "Theses fixtures are useful to test the notifications service. They trigger all notifications types. Just make sure that you have enabled the types you want to test (check directly in Banks\u2019 settings page, or in the io.cozy.bank.settings database).", "title": "Fixtures notifications service"}, {"location": "cozy-client/architecture/", "text": "Cozy-client Architecture \u00b6 This is an overview of the cozy-client architecture: To explain the architecture, we will see how a request for data flows through cozy-client through links and finally how the data that has been fetched is stored in the redux store. Cozy-client Architecture Query definitions Links Store How does it works? Focus on receiveMutationResult : Query definitions \u00b6 To query data, we create a query definition : an object describing what documents to fetch. { doctype: \"io.cozy.todos\", selector: { \"finished\": true } } It is typically created via the helper Q that provides a fluid interface to create a Query Definition . const qdef = Q ( 'io.cozy.todos' ). where ({ finished : true }) Then we need to execute this query, fetch the data, and storing it. await client . query ( qdef ) Links \u00b6 When executed, Query definitions are passed down to Links . Links accept query definitions and can choose either to return a response or to pass the query definition down to the next link. \u2139\ufe0f This is how offline support is implemented: on mobile, a PouchLink (we use PouchDB under the hood) is added as a link to cozy-client, before the default StackLink. The PouchLink can decide: either to pass down the query definition to the next link (if the PouchLink has not been synchronized for example), or to respond to the request by communicating directly with PouchDB. At the moment there are only two links: StackLink : fetches data over HTTP by communicating to the Cozy\u2019s Stack via the StackClient. PouchLink : fetches data from a local PouchDB. Useful to have offline-ready applications. Store \u00b6 When links have responded with data, the data is stored inside the redux store that is internal to cozy-client. This redux store brings observability to cozy-client, and allows for connection of UI components to the data. \u2139\ufe0f You do not need to use Redux in your application to use cozy-client. \u2139\ufe0f You can connect your own store to cozy-client. It is useful for more advanced techniques where you create selectors directly on the data of cozy-client. The redux store is composed of two collections: documents and queries : documents stores the data indexed by doctype then _id queries store information for each query that has been done by cozy-client. ids of the documents that match the query whether the server has more documents that can be fetched (useful for pagination) whether the query is being loaded. { documents : { 'io.cozy.todos' : { 'todo-id-1' : { finished : true , label : \"Add architecture document for cozy-client\" } } }, queries : { finishedTodos : { data : [ 'todo-id-1' ] } } } \u26a0\ufe0f If queries are not named, a name is automatically generated, but this means that the queries collection can grow indefinitely. This is why you are encouraged to name your queries : client.query(qdef, { as: 'finishedTodos'}) . See these naming rules that are followed at Cozy. \u2139\ufe0f See the react integration for more insight about the glue between the redux store and the UI. React example \u00b6 Let\u2019s take a simple React example to demonstrate the connection of UI components to the data: const { data , fetchStatus } = useQuery ( Q ( 'io.cozy.todos' ), { 'as' : 'todoslist' }) if ( fetchStatus === 'loading' ) { return < Spinner /> } if ( fetchStatus === 'loaded' ) { return < TodoLists todos = { data } /> } if ( fetchStatus === 'failed' ) { return < Error /> } This way, a spinner will be displayed during the time the query is actually run. Once the query is done, data for this query is available and can be displayed. On this example, any data change on the io.cozy.todos doctype will be handled by cozy-client and reflected in the data array returned by useQuery . Thus, the app is reactive to any data change, with no hassle for the developer. See the auto query update mechanism for more insights about this mechanism. Queries \u00b6 Here, we describe what happens internally when a query is called from an app. First, it is important to understand that each query is stored in the store, in a queries associative array. Each query has a unique id, a set of metadata, and the list of retrieved document ids. For example: { query1 : { definition : { ... }, fetchStatus : \"loaded\" , lastFetch : 1716989816939 , lastUpdate : 1716989816939 , hasMore : false , count : 2 , bookmark : \"xyz\" , data : [ \"docId1\" , \"docId2\" ] // confusingly named `data`, but only stores ids } } Fetch status \u00b6 An important attribute used for the query lifecycle is the fetchStatus . It can take the following values: - pending : the query is about to be run for the first time. - loading : the query is currently running and might return results. From a UX perspective, it is often used by apps to display a spinner. - loaded : the query had been run and returned results. - failed : the last query execution failed. When a query is called for the first time, it is first initialized in the queries collection in the store, with the pending status. If the query already exists in the store, its status is checked to ensure that it is not already in a loading state. If it the case, a de-duplication mechanism is used to return the stored existing query. See the PR for more details. Then, the query is \u201cloaded\u201d, making its status on loading . Then, the query status is set on loading and the query actually run. When results are retrieved from the database, the status is set to loaded and some additional information are saved in the query store, such as lastFetch and lastUpdate . If any new data is retrieved by the query, all the documents ids retrieved by the query are then stored in the data array. Likewise, the documents collection is updated as well with the full documents content. Auto query update \u00b6 Since there is a link between queries and documents through the ids list in each query object, we need to be able to deal with changes occuring in the documents collection, i.e. when documents are added or deleted. For this, cozy-client has a mechanism called \u201cquery updater\u201d: each time a query is run, all the queries in the store are re-evaluated directly in the store. That means that for each query, we take its definition, convert it into a mango predicate (see here for details), and run it against the store\u2019s document collection. For each query result, we check if there is any change in the known ids list, and update it accordingly. Thanks to this, we ensure that all the queries are always up-to-date, and apps can be effectively rendered thanks to the react integration . Fetch policy and query naming \u00b6 The fetch policy is a useful mechanism to prevent excessive fetching. It is optionnaly defined for each query, to specify a minimum time between 2 actual fetches. It means that after a query is run, if it is called again within this time, it will not be executed. Here is an example to demonstrate how it works: const queryDef = Q ( 'io.cozy.todos' ). where ({ checked : true }) const queryOptions = { as : 'io.cozy.todos/checked/true' , // query unique name, to find it in the store fetchPolicy : CozyClient . fetchPolicies . olderThan ( 10 * 1000 ) // fetch policy, for 10 seconds } // First query let { data : result } = await client . query ( queryDef , queryOptions ) // result is filled // Second query, within the fetch policy time interval setTimeout ( async () => { { data : result } = await client . query ( queryDef , queryOptions ) // result is null }, 5000 ) // Third query, after the fetch policy time interval setTimeout ( async () => { { data : result } = await client . query ( queryDef , queryOptions ) // result is filled }, 10000 ) If the query had been run before the 10 seconds, an early return will happen and nothing will be updated in the store. \ud83d\udca1 In this example, we do not benefit from the React integration like demonstrated in this example with useQuery . When using it, the data is returned even though the fetch policy applies, by taking it directly from the store, to ensure the component is correctly rendered. \ud83d\udca1 In a React context, thanks to the auto-query updater, the data will not be stale if there is a data change in the app: indeed, any change on the documents will trigger the in-memory re-evaluation of the query and a render on the app if something is different. \u2139\ufe0f The as option is used to name the query, which is always a good idea to ensure that it has a unique name. When it\u2019s not specified, a random id is generated, resulting in potential query duplication in the store. Likewise, one must be very careful to prevent queries with the same name, as it would mixup results in the store. Note that you can easily view each query using Devtools to identify duplicates and follow the guidelines for the naming . Complete query flow \u00b6 --- title: Query with cozy-client --- sequenceDiagram participant App as App participant CC as cozy-client participant Store as Store participant Backend as Backend App->>CC: Query documents CC->>Store: Check query alt Query does not exist CC->>Store: Init query Store->>Store: Add query to collection else Query exists CC->>CC: Check fetch policy CC->>CC: Check loading status end CC->>Store: Load query Store->>Store: Update query status CC->>Backend: Execute query Backend->>CC: Data CC->>Store: Data Store->>Store: Update query status Store->>Store: Update data CC->>App: Results Store->>Store: Auto-update queries Persisted store and background fetching stategy \u00b6 An app can decide to persist its store in localstorage. See here for an example. When doing so, the app loads the store when it starts and benefit from the instant available cached data. But, the data could have significantly evolved between the last store save and the start, making the documents potentially stale. Hopefully, since the fetch policy is probably expired, queries will be run again, retrieving fresh data. Unfortunately, this might cause an immediate spinning display on the app when it starts, even though there is available data thanks to the persisted store. To solve this, a backgroundFetching option can be set, at the query level, or at the store level (enabled for all queries). When the query is loaded, it simply keeps the query status in loaded state (rather than setting a loading state) and set a new isFetching attribute, stored in the query. Thanks to this, the app can adapt its display to avoid the \u201cspinning effect\u201d, and might inform the user that data is being updated in the background, without refreshing the whole app. See this PR for more insights. Here is a simplified execution sequence with or without background fetching: --- title: Background fetching --- sequenceDiagram participant App as App participant CC as cozy-client participant Store as Store participant Backend as Backend App->>CC: Query documents CC->>Store: Load query alt Without background fetching Store->>Store: update query status Store->>App: Loading query status App->>App: Spinner else With background fetching Store->>Store: no change on query status Store->>App: isFetching status App->>App: Display persisted data end CC->>Backend: Execute query Backend->>CC: New data CC->>Store: Update store CC->>App: New data App->>App: Refresh display Updates \u00b6 Here, we detail what happens when a document is updated, i.e. a mutation happens, typically after a client.save . If the document _id does not exist in the store\u2019s documents collection, i.e. after the a creation, it is simply added. If it already exists, the document content is updated in this collection, after the backend response. Furthermore, just like with the queries, any mutation triggers the auto query updater , that can result in adding or removing document ids. Thanks to it, the app is guaranteed to have the up-to-date documents, returned from the documents collection. \u26a0\ufe0f As already mentioned, when a mutated document already exists in the store throught its _id , it is updated with the new content. However, this update never removes existing fields, it only merges or adds new fields. This is typically useful when two queries retrieve the same document, but not with all the fields. Let us illustrate with this example: const Q1 = { definition : Q ( 'io.cozy.todos' ). getById ( 'my-todo' ), options : { as : 'io.cozy.todos/my-todo' , fetchPolicy : lessThan30s }} const Q2 = { definition : Q ( 'io.cozy.todos' ). getById ( 'my-todo' ). select ([ 'label' ]), options : { as : 'io.cozy.todos/my-todo/withLabel' }} await client . query ( Q1 ) // returns { _id: 'my-todo', _type: 'io.cozy.todos', label: 'TODOTODO' }, from the database await client . query ( Q2 ) // returns { label: 'TODOTODO' }, from the database await client . query ( Q1 ) // returns { _id: 'my-todo', _type: 'io.cozy.todos', label: 'TODOTODO' }, from the store Q1 retrieves the full content of \u2018my-todo\u2019 while Q2 only retrieves its label. When Q2 is run, \u2018my-todo\u2019 already exists in the store, as Q1 was previsouly run. However, the fields retrieved by Q1 for \u2018my-todos\u2019 but absent from Q2 are not lost. This way, when Q1 is run again, the results fetched from the store (thanks to the fetch policy) will include all the fields. \u26a0\ufe0f The problem is when some fields are removed from a document: the store will not reflect this change and result in stale data. To avoid this side-effect, one could set an attribute to undefined instead of removing it, as a workaround. In-memory queries evaluation \u00b6 Each time a change occurs in the store\u2019s documents collection, either through a query or an update, all the stored queries are dynamically re-evaluated. As we do not want to request the actual database each time, we do the evaluation directly from the store, in memory. To achieve this, we need to evaluate queries the same way it would have been done on the database side. Our query system relies on mango, a mongo-like query system supported by CouchDB, the Cozy database. We rely on sift.js for the in-memory query evaluation. This library is able to take as input a mongo query definition and transform it into a javascript predicate. Then, all the queries are evaluated on the stores\u2019s documents , and efficiently updated accordingly to the results. \ud83d\udca1 If you want to know more about our query system and syntax, please check this documentation . \u26a0\ufe0f Please not that there is not a perfect matching between mango operators and sift, see this issue for instance.", "title": "Architecture"}, {"location": "cozy-client/architecture/#cozy-client-architecture", "text": "This is an overview of the cozy-client architecture: To explain the architecture, we will see how a request for data flows through cozy-client through links and finally how the data that has been fetched is stored in the redux store. Cozy-client Architecture Query definitions Links Store How does it works? Focus on receiveMutationResult :", "title": "Cozy-client Architecture"}, {"location": "cozy-client/architecture/#query-definitions", "text": "To query data, we create a query definition : an object describing what documents to fetch. { doctype: \"io.cozy.todos\", selector: { \"finished\": true } } It is typically created via the helper Q that provides a fluid interface to create a Query Definition . const qdef = Q ( 'io.cozy.todos' ). where ({ finished : true }) Then we need to execute this query, fetch the data, and storing it. await client . query ( qdef )", "title": "Query definitions"}, {"location": "cozy-client/architecture/#links", "text": "When executed, Query definitions are passed down to Links . Links accept query definitions and can choose either to return a response or to pass the query definition down to the next link. \u2139\ufe0f This is how offline support is implemented: on mobile, a PouchLink (we use PouchDB under the hood) is added as a link to cozy-client, before the default StackLink. The PouchLink can decide: either to pass down the query definition to the next link (if the PouchLink has not been synchronized for example), or to respond to the request by communicating directly with PouchDB. At the moment there are only two links: StackLink : fetches data over HTTP by communicating to the Cozy\u2019s Stack via the StackClient. PouchLink : fetches data from a local PouchDB. Useful to have offline-ready applications.", "title": "Links"}, {"location": "cozy-client/architecture/#store", "text": "When links have responded with data, the data is stored inside the redux store that is internal to cozy-client. This redux store brings observability to cozy-client, and allows for connection of UI components to the data. \u2139\ufe0f You do not need to use Redux in your application to use cozy-client. \u2139\ufe0f You can connect your own store to cozy-client. It is useful for more advanced techniques where you create selectors directly on the data of cozy-client. The redux store is composed of two collections: documents and queries : documents stores the data indexed by doctype then _id queries store information for each query that has been done by cozy-client. ids of the documents that match the query whether the server has more documents that can be fetched (useful for pagination) whether the query is being loaded. { documents : { 'io.cozy.todos' : { 'todo-id-1' : { finished : true , label : \"Add architecture document for cozy-client\" } } }, queries : { finishedTodos : { data : [ 'todo-id-1' ] } } } \u26a0\ufe0f If queries are not named, a name is automatically generated, but this means that the queries collection can grow indefinitely. This is why you are encouraged to name your queries : client.query(qdef, { as: 'finishedTodos'}) . See these naming rules that are followed at Cozy. \u2139\ufe0f See the react integration for more insight about the glue between the redux store and the UI.", "title": "Store"}, {"location": "cozy-client/architecture/#react-example", "text": "Let\u2019s take a simple React example to demonstrate the connection of UI components to the data: const { data , fetchStatus } = useQuery ( Q ( 'io.cozy.todos' ), { 'as' : 'todoslist' }) if ( fetchStatus === 'loading' ) { return < Spinner /> } if ( fetchStatus === 'loaded' ) { return < TodoLists todos = { data } /> } if ( fetchStatus === 'failed' ) { return < Error /> } This way, a spinner will be displayed during the time the query is actually run. Once the query is done, data for this query is available and can be displayed. On this example, any data change on the io.cozy.todos doctype will be handled by cozy-client and reflected in the data array returned by useQuery . Thus, the app is reactive to any data change, with no hassle for the developer. See the auto query update mechanism for more insights about this mechanism.", "title": "React example"}, {"location": "cozy-client/architecture/#queries", "text": "Here, we describe what happens internally when a query is called from an app. First, it is important to understand that each query is stored in the store, in a queries associative array. Each query has a unique id, a set of metadata, and the list of retrieved document ids. For example: { query1 : { definition : { ... }, fetchStatus : \"loaded\" , lastFetch : 1716989816939 , lastUpdate : 1716989816939 , hasMore : false , count : 2 , bookmark : \"xyz\" , data : [ \"docId1\" , \"docId2\" ] // confusingly named `data`, but only stores ids } }", "title": "Queries"}, {"location": "cozy-client/architecture/#fetch-status", "text": "An important attribute used for the query lifecycle is the fetchStatus . It can take the following values: - pending : the query is about to be run for the first time. - loading : the query is currently running and might return results. From a UX perspective, it is often used by apps to display a spinner. - loaded : the query had been run and returned results. - failed : the last query execution failed. When a query is called for the first time, it is first initialized in the queries collection in the store, with the pending status. If the query already exists in the store, its status is checked to ensure that it is not already in a loading state. If it the case, a de-duplication mechanism is used to return the stored existing query. See the PR for more details. Then, the query is \u201cloaded\u201d, making its status on loading . Then, the query status is set on loading and the query actually run. When results are retrieved from the database, the status is set to loaded and some additional information are saved in the query store, such as lastFetch and lastUpdate . If any new data is retrieved by the query, all the documents ids retrieved by the query are then stored in the data array. Likewise, the documents collection is updated as well with the full documents content.", "title": "Fetch status"}, {"location": "cozy-client/architecture/#auto-query-update", "text": "Since there is a link between queries and documents through the ids list in each query object, we need to be able to deal with changes occuring in the documents collection, i.e. when documents are added or deleted. For this, cozy-client has a mechanism called \u201cquery updater\u201d: each time a query is run, all the queries in the store are re-evaluated directly in the store. That means that for each query, we take its definition, convert it into a mango predicate (see here for details), and run it against the store\u2019s document collection. For each query result, we check if there is any change in the known ids list, and update it accordingly. Thanks to this, we ensure that all the queries are always up-to-date, and apps can be effectively rendered thanks to the react integration .", "title": "Auto query update"}, {"location": "cozy-client/architecture/#fetch-policy-and-query-naming", "text": "The fetch policy is a useful mechanism to prevent excessive fetching. It is optionnaly defined for each query, to specify a minimum time between 2 actual fetches. It means that after a query is run, if it is called again within this time, it will not be executed. Here is an example to demonstrate how it works: const queryDef = Q ( 'io.cozy.todos' ). where ({ checked : true }) const queryOptions = { as : 'io.cozy.todos/checked/true' , // query unique name, to find it in the store fetchPolicy : CozyClient . fetchPolicies . olderThan ( 10 * 1000 ) // fetch policy, for 10 seconds } // First query let { data : result } = await client . query ( queryDef , queryOptions ) // result is filled // Second query, within the fetch policy time interval setTimeout ( async () => { { data : result } = await client . query ( queryDef , queryOptions ) // result is null }, 5000 ) // Third query, after the fetch policy time interval setTimeout ( async () => { { data : result } = await client . query ( queryDef , queryOptions ) // result is filled }, 10000 ) If the query had been run before the 10 seconds, an early return will happen and nothing will be updated in the store. \ud83d\udca1 In this example, we do not benefit from the React integration like demonstrated in this example with useQuery . When using it, the data is returned even though the fetch policy applies, by taking it directly from the store, to ensure the component is correctly rendered. \ud83d\udca1 In a React context, thanks to the auto-query updater, the data will not be stale if there is a data change in the app: indeed, any change on the documents will trigger the in-memory re-evaluation of the query and a render on the app if something is different. \u2139\ufe0f The as option is used to name the query, which is always a good idea to ensure that it has a unique name. When it\u2019s not specified, a random id is generated, resulting in potential query duplication in the store. Likewise, one must be very careful to prevent queries with the same name, as it would mixup results in the store. Note that you can easily view each query using Devtools to identify duplicates and follow the guidelines for the naming .", "title": "Fetch policy and query naming"}, {"location": "cozy-client/architecture/#complete-query-flow", "text": "--- title: Query with cozy-client --- sequenceDiagram participant App as App participant CC as cozy-client participant Store as Store participant Backend as Backend App->>CC: Query documents CC->>Store: Check query alt Query does not exist CC->>Store: Init query Store->>Store: Add query to collection else Query exists CC->>CC: Check fetch policy CC->>CC: Check loading status end CC->>Store: Load query Store->>Store: Update query status CC->>Backend: Execute query Backend->>CC: Data CC->>Store: Data Store->>Store: Update query status Store->>Store: Update data CC->>App: Results Store->>Store: Auto-update queries", "title": "Complete query flow"}, {"location": "cozy-client/architecture/#persisted-store-and-background-fetching-stategy", "text": "An app can decide to persist its store in localstorage. See here for an example. When doing so, the app loads the store when it starts and benefit from the instant available cached data. But, the data could have significantly evolved between the last store save and the start, making the documents potentially stale. Hopefully, since the fetch policy is probably expired, queries will be run again, retrieving fresh data. Unfortunately, this might cause an immediate spinning display on the app when it starts, even though there is available data thanks to the persisted store. To solve this, a backgroundFetching option can be set, at the query level, or at the store level (enabled for all queries). When the query is loaded, it simply keeps the query status in loaded state (rather than setting a loading state) and set a new isFetching attribute, stored in the query. Thanks to this, the app can adapt its display to avoid the \u201cspinning effect\u201d, and might inform the user that data is being updated in the background, without refreshing the whole app. See this PR for more insights. Here is a simplified execution sequence with or without background fetching: --- title: Background fetching --- sequenceDiagram participant App as App participant CC as cozy-client participant Store as Store participant Backend as Backend App->>CC: Query documents CC->>Store: Load query alt Without background fetching Store->>Store: update query status Store->>App: Loading query status App->>App: Spinner else With background fetching Store->>Store: no change on query status Store->>App: isFetching status App->>App: Display persisted data end CC->>Backend: Execute query Backend->>CC: New data CC->>Store: Update store CC->>App: New data App->>App: Refresh display", "title": "Persisted store and background fetching stategy"}, {"location": "cozy-client/architecture/#updates", "text": "Here, we detail what happens when a document is updated, i.e. a mutation happens, typically after a client.save . If the document _id does not exist in the store\u2019s documents collection, i.e. after the a creation, it is simply added. If it already exists, the document content is updated in this collection, after the backend response. Furthermore, just like with the queries, any mutation triggers the auto query updater , that can result in adding or removing document ids. Thanks to it, the app is guaranteed to have the up-to-date documents, returned from the documents collection. \u26a0\ufe0f As already mentioned, when a mutated document already exists in the store throught its _id , it is updated with the new content. However, this update never removes existing fields, it only merges or adds new fields. This is typically useful when two queries retrieve the same document, but not with all the fields. Let us illustrate with this example: const Q1 = { definition : Q ( 'io.cozy.todos' ). getById ( 'my-todo' ), options : { as : 'io.cozy.todos/my-todo' , fetchPolicy : lessThan30s }} const Q2 = { definition : Q ( 'io.cozy.todos' ). getById ( 'my-todo' ). select ([ 'label' ]), options : { as : 'io.cozy.todos/my-todo/withLabel' }} await client . query ( Q1 ) // returns { _id: 'my-todo', _type: 'io.cozy.todos', label: 'TODOTODO' }, from the database await client . query ( Q2 ) // returns { label: 'TODOTODO' }, from the database await client . query ( Q1 ) // returns { _id: 'my-todo', _type: 'io.cozy.todos', label: 'TODOTODO' }, from the store Q1 retrieves the full content of \u2018my-todo\u2019 while Q2 only retrieves its label. When Q2 is run, \u2018my-todo\u2019 already exists in the store, as Q1 was previsouly run. However, the fields retrieved by Q1 for \u2018my-todos\u2019 but absent from Q2 are not lost. This way, when Q1 is run again, the results fetched from the store (thanks to the fetch policy) will include all the fields. \u26a0\ufe0f The problem is when some fields are removed from a document: the store will not reflect this change and result in stale data. To avoid this side-effect, one could set an attribute to undefined instead of removing it, as a workaround.", "title": "Updates"}, {"location": "cozy-client/architecture/#in-memory-queries-evaluation", "text": "Each time a change occurs in the store\u2019s documents collection, either through a query or an update, all the stored queries are dynamically re-evaluated. As we do not want to request the actual database each time, we do the evaluation directly from the store, in memory. To achieve this, we need to evaluate queries the same way it would have been done on the database side. Our query system relies on mango, a mongo-like query system supported by CouchDB, the Cozy database. We rely on sift.js for the in-memory query evaluation. This library is able to take as input a mongo query definition and transform it into a javascript predicate. Then, all the queries are evaluated on the stores\u2019s documents , and efficiently updated accordingly to the results. \ud83d\udca1 If you want to know more about our query system and syntax, please check this documentation . \u26a0\ufe0f Please not that there is not a perfect matching between mango operators and sift, see this issue for instance.", "title": "In-memory queries evaluation"}, {"location": "cozy-client/dev/", "text": "Publishing \u00b6 We use lerna for publishing. lerna publish These options are useful --scope to only care about one package lerna publish --scope cozy-client --npm-tag to change the default npm-tag (latest). Useful if you are testing and don\u2019t want your users to end up with your changes. $ lerna publish --scope cozy-client --npm-tag beta $ npm install cozy-client@beta \u26a0\ufe0f Even if you use an NPM tag, this creates a real version on NPM. If you want to create a beta version, change the version in the package.json of the package you are publishing and add for example beta.0 . This way, you do not take the space of the next version. --force-publish to force publication even if there were no changes lerna publish --scope cozy-client --force-publish cozy-client Linking \u00b6 Use yarn watch to watch on cozy-client side and yarn link on the app side. If you have a problem like \u201cReact is not found\u201d from cozy-client files, it may be because node is resolving the dependencies in cozy-client\u2019s node_modules , you may want to ln -s your app node_modules inside cozy-client\u2019s. $ ls code cozy-banks cozy-client $ cd cozy-client/packages/cozy-client $ rm -rf node_modules $ ln -s ~/code/cozy-banks/node_modules .", "title": "Dev"}, {"location": "cozy-client/dev/#publishing", "text": "We use lerna for publishing. lerna publish These options are useful --scope to only care about one package lerna publish --scope cozy-client --npm-tag to change the default npm-tag (latest). Useful if you are testing and don\u2019t want your users to end up with your changes. $ lerna publish --scope cozy-client --npm-tag beta $ npm install cozy-client@beta \u26a0\ufe0f Even if you use an NPM tag, this creates a real version on NPM. If you want to create a beta version, change the version in the package.json of the package you are publishing and add for example beta.0 . This way, you do not take the space of the next version. --force-publish to force publication even if there were no changes lerna publish --scope cozy-client --force-publish cozy-client", "title": "Publishing"}, {"location": "cozy-client/dev/#linking", "text": "Use yarn watch to watch on cozy-client side and yarn link on the app side. If you have a problem like \u201cReact is not found\u201d from cozy-client files, it may be because node is resolving the dependencies in cozy-client\u2019s node_modules , you may want to ln -s your app node_modules inside cozy-client\u2019s. $ ls code cozy-banks cozy-client $ cd cozy-client/packages/cozy-client $ rm -rf node_modules $ ln -s ~/code/cozy-banks/node_modules .", "title": "Linking"}, {"location": "cozy-client/devtools/", "text": "Devtools \u00b6 Cozy-client exposes a devtool that can be injected in an app for debug and better developer experience. It is inspired by the awesome devtools for react-query . To activate it, just run in your browser console: flag ( 'debug' , true ) Usage \u00b6 Before using the devtools, you need to install cozy-ui and react-inspector. yarn add cozy-ui # >= 48.0.0 yarn add react-inspector # >= 5.1.0 Next, you need to add it to your app, inside a CozyProvider. import CozyClient , { CozyProvider } from 'cozy-client' import CozyDevtools from 'cozy-client/dist/devtools' const App = () => { return < CozyProvider client = { client }> /* Your app is here */ { process . env . NODE_ENV !== 'production' ? < CozyDevtools /> : null } } Panels \u00b6 The devtools is made of several \u201cpanels\u201d. There are default panels and the app can also inject its own adhoc panels. Queries \u00b6 Shows current queries inside cozy-client cache. Allows to see the data of the query. The execution time is also shown, and is very valuable to track down performance issues. It uses the execution statistics collected from CouchDB. Flags \u00b6 Shows all the current flags and allow to modify them. Libraries \u00b6 Show library versions based on the global VERSIONS variable that should be injected by the app. If it is defined, the panel will be blank. PouchLink \u00b6 If you use the PouchLink to synchronize your data to PouchDB, you can use the optional devtool PouchLink devtool panel. Since PouchDB is optional, it is not available by default and you need to explicitly tell the Devtools to display it. import PouchDevtools from 'cozy-client/dist/devtools/Pouch' () => < CozyDevTools panels = {{ id : 'pouch' , Component : PouchDevtools }} /> Ideas for next features \u00b6 Performance tips in query panels Show index related tips Show slow queries Show repeating queries Show queries downloading too much data Actions on queries Reset data inside query Refetch Set to error Delete from store If you have any other idea, please open an issue \ud83d\udc4d", "title": "Devtools"}, {"location": "cozy-client/devtools/#devtools", "text": "Cozy-client exposes a devtool that can be injected in an app for debug and better developer experience. It is inspired by the awesome devtools for react-query . To activate it, just run in your browser console: flag ( 'debug' , true )", "title": "Devtools"}, {"location": "cozy-client/devtools/#usage", "text": "Before using the devtools, you need to install cozy-ui and react-inspector. yarn add cozy-ui # >= 48.0.0 yarn add react-inspector # >= 5.1.0 Next, you need to add it to your app, inside a CozyProvider. import CozyClient , { CozyProvider } from 'cozy-client' import CozyDevtools from 'cozy-client/dist/devtools' const App = () => { return < CozyProvider client = { client }> /* Your app is here */ { process . env . NODE_ENV !== 'production' ? < CozyDevtools /> : null } }", "title": "Usage"}, {"location": "cozy-client/devtools/#panels", "text": "The devtools is made of several \u201cpanels\u201d. There are default panels and the app can also inject its own adhoc panels.", "title": "Panels"}, {"location": "cozy-client/devtools/#queries", "text": "Shows current queries inside cozy-client cache. Allows to see the data of the query. The execution time is also shown, and is very valuable to track down performance issues. It uses the execution statistics collected from CouchDB.", "title": "Queries"}, {"location": "cozy-client/devtools/#flags", "text": "Shows all the current flags and allow to modify them.", "title": "Flags"}, {"location": "cozy-client/devtools/#libraries", "text": "Show library versions based on the global VERSIONS variable that should be injected by the app. If it is defined, the panel will be blank.", "title": "Libraries"}, {"location": "cozy-client/devtools/#pouchlink", "text": "If you use the PouchLink to synchronize your data to PouchDB, you can use the optional devtool PouchLink devtool panel. Since PouchDB is optional, it is not available by default and you need to explicitly tell the Devtools to display it. import PouchDevtools from 'cozy-client/dist/devtools/Pouch' () => < CozyDevTools panels = {{ id : 'pouch' , Component : PouchDevtools }} />", "title": "PouchLink"}, {"location": "cozy-client/devtools/#ideas-for-next-features", "text": "Performance tips in query panels Show index related tips Show slow queries Show repeating queries Show queries downloading too much data Actions on queries Reset data inside query Refetch Set to error Delete from store If you have any other idea, please open an issue \ud83d\udc4d", "title": "Ideas for next features"}, {"location": "cozy-client/entrypoints/", "text": "Different entrypoints for node/browser \u00b6 cozy-client has different entry points for browser and node (the node version does not export React components). It is implemented by using fields in package.json : browser field is the entrypoint for browsers main field is for node It causes an issue when writing tests that use React components from cozy-client ( Provider for example) since Jest does not support the browser field (contrary to webpack). \u26a0\ufe0f If you use react APIs, you should configure Jest with the browser option in your package.json or jest.config.js : \"jest\": { + \"browser\": true } There can be some problems since the browser field can clash with other node detection mechanism in other libraries (for example iconv-lite , see this PR ), an alternative is to use the moduleNameMapper option to point Jest to the correct entrypoint only for cozy-client . \"moduleNameMapper\": { \"^cozy-client$\": \"cozy-client/dist/index\" } This will force Jest to use the browser entry point. See this page for another alternative solution that overrides the jest resolver so that it supports the browser field.", "title": "Entrypoints"}, {"location": "cozy-client/entrypoints/#different-entrypoints-for-nodebrowser", "text": "cozy-client has different entry points for browser and node (the node version does not export React components). It is implemented by using fields in package.json : browser field is the entrypoint for browsers main field is for node It causes an issue when writing tests that use React components from cozy-client ( Provider for example) since Jest does not support the browser field (contrary to webpack). \u26a0\ufe0f If you use react APIs, you should configure Jest with the browser option in your package.json or jest.config.js : \"jest\": { + \"browser\": true } There can be some problems since the browser field can clash with other node detection mechanism in other libraries (for example iconv-lite , see this PR ), an alternative is to use the moduleNameMapper option to point Jest to the correct entrypoint only for cozy-client . \"moduleNameMapper\": { \"^cozy-client$\": \"cozy-client/dist/index\" } This will force Jest to use the browser entry point. See this page for another alternative solution that overrides the jest resolver so that it supports the browser field.", "title": "Different entrypoints for node/browser"}, {"location": "cozy-client/getting-started/", "text": "cozy-client is the sdk to interact with the cozy stack from a Javascript application. It aims at hiding all low level details and providing a simple high level API to fetch and cache documents. Main features: Authentication with a Cozy Querying and caching documents Transparent relations between couchdb documents Updates metadata in couch documents Offline: any data can be stored in a local PouchDB that is persisted across page loads React integration to connect your components to remote data Additional features with plugins: Realtime : Be notified when changes occur on the server side InterApp : Interact with other apps (example : file picking within your app) Flag : Use feature flags The following guide is an overview of a cozy-client integration to help you to get started. Install \u00b6 npm install --save cozy-client # or yarn add cozy-client \u26a0\ufe0f If you use Jest, you should also add a bit of configuration for imports to work properly, see this document for more information . Usage \u00b6 import CozyClient from 'cozy-client' const schema = { todos : { doctype : 'io.cozy.todos' , attributes : {...}, relationships : {...} } } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , schema , token : '...' }) Usually, the token and URI are provided by the stack on the DOM node
    . When using this, you can instantiate a client with: const client = CozyClient.fromDOM({ schema }) // Note how token and uri are not passed, instead they are taken from the DOM If you need guidance to get the URI of your instance and/or the token, see the app tutorial . Every doctype accessed in cozy-client needs to be declared in the schema section of the options. See how to use the schema features Fetch data \u00b6 To fetch data, we first build a QueryDefinition with the Q helper: import { Q } from 'cozy-client' const allTodosQuery = Q ( 'io.cozy.todos' ) const singleTodoQuery = Q ( 'io.cozy.todos' ). getById ( '5fcbbf2cb171b1d5c3bc6df3d4affb32' ) QueryDefinition s describe which documents to be fetched from CouchDB. It uses a fluent interface: Q ( 'io.cozy.todos' ) . select ([ 'title' , 'checked' ]) . where ({ checked : false }) . include ([ 'dependencies' ]) . sortBy ([{ 'cozyMetadata.updatedAt' : 'desc' }]) . limitBy ( 20 ) select() lists the fields you want in the response (all by default) where() allows a mango selector include() will cause the query to fetch the related documents (see relationships ) sortBy sorts the documents by their updatedAt metadata in descending order limitBy limits the number of results to 20 By default, all fields in the where() are automatically indexed. You can turn off this behavior by specifying explicitly the list of fields to be indexed in indexFields() . Finally, client.query() will execute your query and return a promise with a data attribute containing the requested documents. import CozyClient from 'cozy-client' const client = new CozyClient ({ /*...*/ }) const { data } = await client . query ( Q ( 'io.cozy.todos' ). where ({ checked : false })) console . log ( data ) \u2705 Inside a React application, instead of using directly client.query , please use useQuery , or queryConnect to connect your components to cozy-client queries . \u2139\ufe0f Check out our dedicated query documentation to know more about querying with cozy-client and avoid common traps that can dramatically impact your app performances. \ud83d\ude80 Cozy-client\u2019s devtools allows to monitor your queries data and performance. Mutate the data \u00b6 An instance of CozyClient allows you to query and mutate (update) data, here\u2019s how it looks: import CozyClient from 'cozy-client' const client = new CozyClient ({ /*...*/ }) // create a new io.cozy.todo await client . save ({ _type : 'io.cozy.todos' , label : 'Buy bread' , checked : false }) const qdef = Q ( 'io.cozy.todos' ). where ({ checked : false }) const { data : todos } = await client . query ( qdef ) const doc = todos [ 0 ] // modify existing io.cozy.todo (will make an update if _rev is present inside the doc) await client . save ({... doc , checked : true }) save() will return a Promise with a data attribute containing the saved document. \u2139\ufe0f When mutating data, queries that depend on the mutated document(s) will automatically be refreshed: components that depend on these queries will be re-rendered. Mutate several documents in batch \u00b6 The saveAll() method can be used to save multiple documents in one request. const { data : updatedDocs } = await client . saveAll ([ { _type : 'io.cozy.todos' , checked : true , label : 'Buy milk' }, { _type : 'io.cozy.todos' , checked : false , label : 'Make dinner' } ])", "title": "Getting started"}, {"location": "cozy-client/getting-started/#install", "text": "npm install --save cozy-client # or yarn add cozy-client \u26a0\ufe0f If you use Jest, you should also add a bit of configuration for imports to work properly, see this document for more information .", "title": "Install"}, {"location": "cozy-client/getting-started/#usage", "text": "import CozyClient from 'cozy-client' const schema = { todos : { doctype : 'io.cozy.todos' , attributes : {...}, relationships : {...} } } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , schema , token : '...' }) Usually, the token and URI are provided by the stack on the DOM node
    . When using this, you can instantiate a client with: const client = CozyClient.fromDOM({ schema }) // Note how token and uri are not passed, instead they are taken from the DOM If you need guidance to get the URI of your instance and/or the token, see the app tutorial . Every doctype accessed in cozy-client needs to be declared in the schema section of the options. See how to use the schema features", "title": "Usage"}, {"location": "cozy-client/getting-started/#fetch-data", "text": "To fetch data, we first build a QueryDefinition with the Q helper: import { Q } from 'cozy-client' const allTodosQuery = Q ( 'io.cozy.todos' ) const singleTodoQuery = Q ( 'io.cozy.todos' ). getById ( '5fcbbf2cb171b1d5c3bc6df3d4affb32' ) QueryDefinition s describe which documents to be fetched from CouchDB. It uses a fluent interface: Q ( 'io.cozy.todos' ) . select ([ 'title' , 'checked' ]) . where ({ checked : false }) . include ([ 'dependencies' ]) . sortBy ([{ 'cozyMetadata.updatedAt' : 'desc' }]) . limitBy ( 20 ) select() lists the fields you want in the response (all by default) where() allows a mango selector include() will cause the query to fetch the related documents (see relationships ) sortBy sorts the documents by their updatedAt metadata in descending order limitBy limits the number of results to 20 By default, all fields in the where() are automatically indexed. You can turn off this behavior by specifying explicitly the list of fields to be indexed in indexFields() . Finally, client.query() will execute your query and return a promise with a data attribute containing the requested documents. import CozyClient from 'cozy-client' const client = new CozyClient ({ /*...*/ }) const { data } = await client . query ( Q ( 'io.cozy.todos' ). where ({ checked : false })) console . log ( data ) \u2705 Inside a React application, instead of using directly client.query , please use useQuery , or queryConnect to connect your components to cozy-client queries . \u2139\ufe0f Check out our dedicated query documentation to know more about querying with cozy-client and avoid common traps that can dramatically impact your app performances. \ud83d\ude80 Cozy-client\u2019s devtools allows to monitor your queries data and performance.", "title": "Fetch data"}, {"location": "cozy-client/getting-started/#mutate-the-data", "text": "An instance of CozyClient allows you to query and mutate (update) data, here\u2019s how it looks: import CozyClient from 'cozy-client' const client = new CozyClient ({ /*...*/ }) // create a new io.cozy.todo await client . save ({ _type : 'io.cozy.todos' , label : 'Buy bread' , checked : false }) const qdef = Q ( 'io.cozy.todos' ). where ({ checked : false }) const { data : todos } = await client . query ( qdef ) const doc = todos [ 0 ] // modify existing io.cozy.todo (will make an update if _rev is present inside the doc) await client . save ({... doc , checked : true }) save() will return a Promise with a data attribute containing the saved document. \u2139\ufe0f When mutating data, queries that depend on the mutated document(s) will automatically be refreshed: components that depend on these queries will be re-rendered.", "title": "Mutate the data"}, {"location": "cozy-client/getting-started/#mutate-several-documents-in-batch", "text": "The saveAll() method can be used to save multiple documents in one request. const { data : updatedDocs } = await client . saveAll ([ { _type : 'io.cozy.todos' , checked : true , label : 'Buy milk' }, { _type : 'io.cozy.todos' , checked : false , label : 'Make dinner' } ])", "title": "Mutate several documents in batch"}, {"location": "cozy-client/hooks/", "text": "Embedded hooks \u00b6 In addition to our React Integration , Cozy Client comes with several hooks. useAppLinkWithStoreFallback : Returns the URL of an app if this app is installed. If not, returns the URL to the store to install it. useCapabilities : Returns the capabilities for an instance useFetchShortcut : Returns the data for a shortcut useClient : Returns client of actual context useFetchJSON : Hook to use the generic fetchJSON method. Returns object with the same keys { data, fetchStatus, error } as useQuery useQuery : Returns the queryState after fetching a queryDefinition useSettings : Query the cozy-app settings corresponding to the given slug Accessing and Mutating cozy-app settings with useSettings \u00b6 Sometimes cozy-apps need to access settings related data Those settings can be specific to the cozy-app, or global to the Cozy\u2019s instance In order to ease manipulating those settings we provide the hook useSettings This hook is based on useQuery and useMutation to provide the setting\u2019s values and a save method that allow to mutate the settings Additionally, the query and mutation object are provided in order to react to their corresponding states (fetch status, mutation status, etc) import { hasQueryBeenLoaded , useSettings } from 'cozy-client' function DefaultRedirectionSetting () { const [ inputValue , setInputValue ] = useState ( '' ) const { values , save , query , mutation } = useSettings ( 'instance' , // slug for acessing the global settings [ 'default_redirection' ], // setting names ) const handleChange = event => { setInputValue ( event . target . value ) } const handleBlur = () => { save ({ default_redirection : inputValue }) } useEffect (() => { setInputValue ( values . default_redirection ) }, [ values ]) return ( < div style = {{ display : 'flex' }}> < input type = \"text\" aria - label = \"Setting\" style = {{ marginRight : '1rem' }} value = { inputValue } onChange = { handleChange } onBlur = { handleBlur } disabled = { ! hasQueryBeenLoaded ( query )} /> { mutation . mutationStatus === 'loaded' ? '\u2713' : null } { mutation . mutationStatus === 'failed' ? '\u2717' : null } ) }", "title": "Hooks"}, {"location": "cozy-client/hooks/#embedded-hooks", "text": "In addition to our React Integration , Cozy Client comes with several hooks. useAppLinkWithStoreFallback : Returns the URL of an app if this app is installed. If not, returns the URL to the store to install it. useCapabilities : Returns the capabilities for an instance useFetchShortcut : Returns the data for a shortcut useClient : Returns client of actual context useFetchJSON : Hook to use the generic fetchJSON method. Returns object with the same keys { data, fetchStatus, error } as useQuery useQuery : Returns the queryState after fetching a queryDefinition useSettings : Query the cozy-app settings corresponding to the given slug", "title": "Embedded hooks"}, {"location": "cozy-client/hooks/#accessing-and-mutating-cozy-app-settings-with-usesettings", "text": "Sometimes cozy-apps need to access settings related data Those settings can be specific to the cozy-app, or global to the Cozy\u2019s instance In order to ease manipulating those settings we provide the hook useSettings This hook is based on useQuery and useMutation to provide the setting\u2019s values and a save method that allow to mutate the settings Additionally, the query and mutation object are provided in order to react to their corresponding states (fetch status, mutation status, etc) import { hasQueryBeenLoaded , useSettings } from 'cozy-client' function DefaultRedirectionSetting () { const [ inputValue , setInputValue ] = useState ( '' ) const { values , save , query , mutation } = useSettings ( 'instance' , // slug for acessing the global settings [ 'default_redirection' ], // setting names ) const handleChange = event => { setInputValue ( event . target . value ) } const handleBlur = () => { save ({ default_redirection : inputValue }) } useEffect (() => { setInputValue ( values . default_redirection ) }, [ values ]) return ( < div style = {{ display : 'flex' }}> < input type = \"text\" aria - label = \"Setting\" style = {{ marginRight : '1rem' }} value = { inputValue } onChange = { handleChange } onBlur = { handleBlur } disabled = { ! hasQueryBeenLoaded ( query )} /> { mutation . mutationStatus === 'loaded' ? '\u2713' : null } { mutation . mutationStatus === 'failed' ? '\u2717' : null } ) }", "title": "Accessing and Mutating cozy-app settings with useSettings"}, {"location": "cozy-client/link-authoring/", "text": "What is it ? Authoring a link What is it ? \u00b6 Cozy Link is a simple yet powerful way to describe how you want to get the result of a query. Think of it as a sort of \u201cmiddleware\u201d. Links are units that you can chain together to define how each query should be handled: this allows us to use different sources of data, or to control the request lifecycle in a way that makes sense for your app. The first link operates on an operation object and each subsequent link operates on the result of the previous link: In the chain example pictured above, the Dedup link would avoid re-fetching the same query, the PouchDB link would try to get the data from a local Pouch instance, and fallback to the Stack link, assisted by the Retry link that will try to fetch again the query in case of a network error. Authoring a link \u00b6 There are two ways of creating a new link. First, you can instantiate a CozyLink and pass a request handling function to its constructor: const logLink = new CozyLink (( operation , result , forward ) => { console . log ( JSON . stringify ( operation )) return forward ( operation , result ) }) Or you can subclass CozyLink : class LogLink extends CozyLink { request ( operation , result , forward ) { console . log ( JSON . stringify ( operation )) return forward ( operation , result ) } } At the core of a link is the request method. It takes the following arguments: - operation : the operation definition being passed through the link ; - result : the (maybe incomplete) result processed by the previous link ; - forward : (optional) specifies the next link in the chain of links. When the request method is called, the link has to return data back. Depending on where the link is in the chain, and its ability to provide the requested data, it will either use the forward callback to defer to the next link the task of providing (or completing) the data, or return back a result on its own.", "title": "Link authoring"}, {"location": "cozy-client/link-authoring/#what-is-it", "text": "Cozy Link is a simple yet powerful way to describe how you want to get the result of a query. Think of it as a sort of \u201cmiddleware\u201d. Links are units that you can chain together to define how each query should be handled: this allows us to use different sources of data, or to control the request lifecycle in a way that makes sense for your app. The first link operates on an operation object and each subsequent link operates on the result of the previous link: In the chain example pictured above, the Dedup link would avoid re-fetching the same query, the PouchDB link would try to get the data from a local Pouch instance, and fallback to the Stack link, assisted by the Retry link that will try to fetch again the query in case of a network error.", "title": "What is it ?"}, {"location": "cozy-client/link-authoring/#authoring-a-link", "text": "There are two ways of creating a new link. First, you can instantiate a CozyLink and pass a request handling function to its constructor: const logLink = new CozyLink (( operation , result , forward ) => { console . log ( JSON . stringify ( operation )) return forward ( operation , result ) }) Or you can subclass CozyLink : class LogLink extends CozyLink { request ( operation , result , forward ) { console . log ( JSON . stringify ( operation )) return forward ( operation , result ) } } At the core of a link is the request method. It takes the following arguments: - operation : the operation definition being passed through the link ; - result : the (maybe incomplete) result processed by the previous link ; - forward : (optional) specifies the next link in the chain of links. When the request method is called, the link has to return data back. Depending on where the link is in the chain, and its ability to provide the requested data, it will either use the forward callback to defer to the next link the task of providing (or completing) the data, or return back a result on its own.", "title": "Authoring a link"}, {"location": "cozy-client/logging/", "text": "How to activate logging ? \u00b6 Cozy-client libs use minilog for internal logging. If you need to see those logs, you need to tell minilog to show them, they are filtered by default. Each lib has a different namespace that can be enabled/disabled. For example if you want to allow cozy-pouch-link logs at debug level, you can do: // In your app , make sure to attach minilog to window for cozy - client to use it import minilog from 'minilog' window . minilog = minilog minilog . enable () // You can enable / disable loggers via minilog filters require ( 'minilog' ) . suggest . allow ( 'cozy-pouch-link' , 'debug' ) If you want to see everything : require('minilog').suggest.clear() More info on minilog docs .", "title": "Logging"}, {"location": "cozy-client/logging/#how-to-activate-logging", "text": "Cozy-client libs use minilog for internal logging. If you need to see those logs, you need to tell minilog to show them, they are filtered by default. Each lib has a different namespace that can be enabled/disabled. For example if you want to allow cozy-pouch-link logs at debug level, you can do: // In your app , make sure to attach minilog to window for cozy - client to use it import minilog from 'minilog' window . minilog = minilog minilog . enable () // You can enable / disable loggers via minilog filters require ( 'minilog' ) . suggest . allow ( 'cozy-pouch-link' , 'debug' ) If you want to see everything : require('minilog').suggest.clear() More info on minilog docs .", "title": "How to activate logging ?"}, {"location": "cozy-client/metadata/", "text": "Cozy documents have a cozyMetadata block with metadata about the document, like its schema version, its creation date, its source, etc. { \"_id\" : \"xxxx\" , \"cozyMetadata\" : { \"doctypeVersion\" : 4 , \"metadataVersion\" : 1 , \"createdAt\" : \"xxxxx\" , \"createdByApp\" : \"xxxx\" , \"createdByAppVersion\" : \"xxxx\" , \"updatedAt\" : \"xxxxx\" , \"updatedByApps\" : [ { \"slug\" : \"xxxxx\" , \"date\" : \"xxxxx\" , \"version\" : 3 } ], \"sourceAccount\" : \"xxxxx\" } } Options for cozy-client \u00b6 This cozyMetadata block is managed by the apps themselves. Cozy-Client is able to manage some parts of cozyMetadata automatically. For this it needs an appMetadata parameter with a few informations: slug : the slug of the app or konnector (will be used in createdByApp and updatedByApps ) version : version of the app (will be used in createdByAppVersion and updatedByApps ) when in a konnector, sourceAccount : the id of the io.cozy.accounts document that triggered the current execution (it will help to know which documents belong or are created by which account) when in a konnector, sourceAccountIdentifier : identifier unique to the account targetted by the konnector. It is the user login most of the time const client = new CozyClient({ appMetadata: { slug: 'banks', version: '1.27.1' } }) When you provide this information, cozy-client will automatically update metadata when it saves a document. For new documents \u00b6 Cozy-Client will set: metadataVersion : to the last version known to Cozy-Client. It\u2019s the version of the schema for the metadata block itself. doctypeVersion : if it\u2019s provided in the schema at Cozy-Client initialization slug : Slug of the app sourceAccount : : if it\u2019s provided in the appMetadata at initialization. Note it won\u2019t work for files (see below). creation date, app and version updated date, app and version const client = new CozyClient({ appMetadata: { slug: 'banks', version: '1.27.1' }, schema: { bankAccounts: { doctypeVersion: '1.0.0' } } }) If any of these fields already exists in the document you try to save, these values will override the defaults. This allows you to import a document with an existing history. For existing documents \u00b6 Cozy-Client will: Set the updated date Add your app and version in the updatedByApps list \u26a0\ufe0f These values will override any values that your document may already have. Specific case of io.cozy.files \u00b6 The io.cozy.files doctype is protected by cozy-stack, that restricts the attributes that can be saved by the client, including the cozyMetadata. This is the case for : * cozyMetadata.sourceAccount * cozyMetadata.sourceAccountIdentifier To save those attributes, you can pass them directly to the save method, like this: const client = new client() client.save({ _type: 'io.cozy.files', sourceAccount: '12ab3c', sourceAccountIdentifier: 'john@example.org', ... })", "title": "Metadata"}, {"location": "cozy-client/metadata/#options-for-cozy-client", "text": "This cozyMetadata block is managed by the apps themselves. Cozy-Client is able to manage some parts of cozyMetadata automatically. For this it needs an appMetadata parameter with a few informations: slug : the slug of the app or konnector (will be used in createdByApp and updatedByApps ) version : version of the app (will be used in createdByAppVersion and updatedByApps ) when in a konnector, sourceAccount : the id of the io.cozy.accounts document that triggered the current execution (it will help to know which documents belong or are created by which account) when in a konnector, sourceAccountIdentifier : identifier unique to the account targetted by the konnector. It is the user login most of the time const client = new CozyClient({ appMetadata: { slug: 'banks', version: '1.27.1' } }) When you provide this information, cozy-client will automatically update metadata when it saves a document.", "title": "Options for cozy-client"}, {"location": "cozy-client/metadata/#for-new-documents", "text": "Cozy-Client will set: metadataVersion : to the last version known to Cozy-Client. It\u2019s the version of the schema for the metadata block itself. doctypeVersion : if it\u2019s provided in the schema at Cozy-Client initialization slug : Slug of the app sourceAccount : : if it\u2019s provided in the appMetadata at initialization. Note it won\u2019t work for files (see below). creation date, app and version updated date, app and version const client = new CozyClient({ appMetadata: { slug: 'banks', version: '1.27.1' }, schema: { bankAccounts: { doctypeVersion: '1.0.0' } } }) If any of these fields already exists in the document you try to save, these values will override the defaults. This allows you to import a document with an existing history.", "title": "For new documents"}, {"location": "cozy-client/metadata/#for-existing-documents", "text": "Cozy-Client will: Set the updated date Add your app and version in the updatedByApps list \u26a0\ufe0f These values will override any values that your document may already have.", "title": "For existing documents"}, {"location": "cozy-client/metadata/#specific-case-of-iocozyfiles", "text": "The io.cozy.files doctype is protected by cozy-stack, that restricts the attributes that can be saved by the client, including the cozyMetadata. This is the case for : * cozyMetadata.sourceAccount * cozyMetadata.sourceAccountIdentifier To save those attributes, you can pass them directly to the save method, like this: const client = new client() client.save({ _type: 'io.cozy.files', sourceAccount: '12ab3c', sourceAccountIdentifier: 'john@example.org', ... })", "title": "Specific case of io.cozy.files"}, {"location": "cozy-client/mobile-guide/", "text": "Using CozyClient on a mobile app Configuration \ud83d\udee0 Starting the OAuth flow \ud83c\udfc4\u200d\u2642\ufe0f How to restore a previous token ? How to logout the client ? Support offline for some doctypes with cozy-pouch-link Using CozyClient on a mobile app \u00b6 Configuration \ud83d\udee0 \u00b6 On the web, the server pass the token and the domain to the page directly through template variables. This is not possible on mobile as there is no server to serve the page. CozyClient supports connecting to a Cozy via OAtuh. To get started, configure the OAuth settings when creating the client: import CozyClient from 'cozy-client' const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , scope : [ 'io.cozy.mydoctype' ], oauth : { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } }) scope is an array of permissions you require for your client oauth is a list of fields that identify your client for the user and the server. The complete list of field can be found here , although they should be camel-cased instead of snake-cased. Starting the OAuth flow \ud83c\udfc4\u200d\u2642\ufe0f \u00b6 Before you can start making requests to the server, you will need to get a token. cozy-client will provide a URL to a page where the user is shown what data you want to access, and asking for his or her permission. After the user accepts these permissions, he or she is redirected to the oauth.redirectURI that you declared earlier. You will then have to give this redirected URL back to cozy-client as it contains a code, that will be exchanged for the token. To get started, you call client.startOAuthFlow like this: import CozyClient from 'cozy-client' const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , scope : [ 'io.cozy.mydoctype' ], oauth : { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } }) client . startOAuthFlow ( openURL ) The openURL parameter is a callback. It will receive the URL to the page as a parameter, and it must return a Promise that resolves with the redirected URL. How exactly you do this depends on your environment \u2014 for a mobile app you may use a WebView, in a browser maybe a new tab\u2026 Here is an example that uses the browser\u2019s console and an experienced user: const openURL = url => { console . log ( 'Please visit the following URL, accept the permissions and copy the URL you are redirected to, then come back here. you have 10 seconds.' , url ) return new Promise ( resolve => { setTimeout ( async () => { const returnUrl = prompt ( 'Paste the new URL here.' ) resolve ( returnUrl ) }, 10000 ) }) } And that\u2019s it! After the promise is resolved, cozy-client finishes the OAuth flow and you can start using it. How to restore a previous token ? \u00b6 Nobody likes to enter passwords, and you don\u2019t want to make your user go through this whole process every time your app starts. In order to restore the client from a previous version, you need to give it a token and some extra information about itself. Both of these are returned by the openURL function, so you can store them wherever you see fit \u2014 in this example we\u2019ll use the localStorage API. import CozyClient from 'cozy-client' const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , scope : [ 'io.cozy.mydoctype' ], oauth : { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } }) const { token , infos } = client . startOAuthFlow ( openURL ) localStorage . setItem ( 'token' , token ) localStorage . setItem ( 'infos' , JSON . stringify ( infos )) Next time your app starts, you can pass these informations to the constructor. Here is a complete example of the OAuth client initilisation: const storedToken = localStorage . getItem ( 'token' ) || null const storedInfos = JSON . parse ( localStorage . getItem ( 'infos' )) || { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , oauth : storedInfos , token : storedToken , scope : [ 'io.cozy.mydoctype' ] }); if ( ! storedToken ) { const { token , infos } = await client . startOAuthFlow ( openURL ) localStorage . setItem ( 'token' , token ) localStorage . setItem ( 'infos' , JSON . stringify ( infos )) } How to logout the client ? \u00b6 When a user logout, we would like remove all references on this instance and remove all user data. You can just use cozyClient.logout() . Support offline for some doctypes with cozy-pouch-link \u00b6 If you are already using cozy-client and the StackLink , you may want to go further and store some documents locally so you can retrieve them even while being offline. Currently, you have a code like this one : import CozyClient , { StackLink } from 'cozy-client' const stackLink = new StackLink () const client = new CozyClient ({ // ... links : [ stackLink ] }) To manage the offline aspect, we provide the cozy-pouch-link . First, let\u2019s install it : # using npm npm install cozy-pouch-link # using yarn yarn add cozy-pouch-link Then, we will create a new instance of this link and give it the list of doctypes that we want to access offline. We have to put the PouchLink first, so it is reached first when we query the link chain : import CozyClient , { StackLink } from 'cozy-client' import PouchLink from 'cozy-pouch-link' const stackLink = new StackLink () const offlineDoctypes = [ 'io.cozy.todos' ] const pouchLink = new PouchLink ({ doctypes : offlineDoctypes , initialSync : true // whether you want to trigger the synchronization on login or not }) const client = new CozyClient ({ // ... links : [ pouchLink , stackLink ] }) The PouchLink will create the PouchDB databases for all offline doctypes and synchronize them with the distant CouchDB. All doctypes that are not managed by the PouchLink will be passed to the next link in the chain (in the previous example, the StackLink ). Additionally, it is possible to replicate some doctypes only in a specific direction: const pouchLink = new PouchLink ({ doctypes : [ 'io.cozy.todos' , 'io.cozy.files' , 'io.cozy.localtype' ], doctypesReplicationOptions : { 'io.cozy.todos' : { strategy : 'sync' // default, replicate both ways }, 'io.cozy.files' : { strategy : 'fromRemote' // replicate changes from the remote locally, but don't push any changes }, 'io.cozy.localtype' : { strategy : 'toRemote' // push changes to remote, but don't replicate changes from it } } initialSync : true }) If you choose the fromRemote strategy, the cozy-client mutation will not be executed on the PouchLink but rather on the StackLink. Since making the first query can be long (PouchDB will create the index first), you can specify the queries you want to be \u201cwarmed up\u201d. It means that, those queries will be executed by CozyClient during the PouchLink\u2019s instanciation, but CozyClient will use PouchDB only if those queries have been resolved at least one time. const buildRecentQuery = () => ({ definition : () => Q ( 'io.cozy.files' ) . where ({ type : 'file' , trashed : false , updated_at : { $gt : null } }) options : { as : 'recent-view-query' , fetchPolicy : defaultFetchPolicy , } }) const pouchLink = new PouchLink ({ doctypes : [ 'io.cozy.todos' , 'io.cozy.files' , 'io.cozy.localtype' ], doctypesReplicationOptions : { 'io.cozy.files' : { warmupQueries : [ buildRecentQuery () ] } } initialSync : true })", "title": "Mobile guide"}, {"location": "cozy-client/mobile-guide/#using-cozyclient-on-a-mobile-app", "text": "", "title": "Using CozyClient on a mobile app"}, {"location": "cozy-client/mobile-guide/#configuration", "text": "On the web, the server pass the token and the domain to the page directly through template variables. This is not possible on mobile as there is no server to serve the page. CozyClient supports connecting to a Cozy via OAtuh. To get started, configure the OAuth settings when creating the client: import CozyClient from 'cozy-client' const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , scope : [ 'io.cozy.mydoctype' ], oauth : { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } }) scope is an array of permissions you require for your client oauth is a list of fields that identify your client for the user and the server. The complete list of field can be found here , although they should be camel-cased instead of snake-cased.", "title": "Configuration \ud83d\udee0"}, {"location": "cozy-client/mobile-guide/#starting-the-oauth-flow", "text": "Before you can start making requests to the server, you will need to get a token. cozy-client will provide a URL to a page where the user is shown what data you want to access, and asking for his or her permission. After the user accepts these permissions, he or she is redirected to the oauth.redirectURI that you declared earlier. You will then have to give this redirected URL back to cozy-client as it contains a code, that will be exchanged for the token. To get started, you call client.startOAuthFlow like this: import CozyClient from 'cozy-client' const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , scope : [ 'io.cozy.mydoctype' ], oauth : { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } }) client . startOAuthFlow ( openURL ) The openURL parameter is a callback. It will receive the URL to the page as a parameter, and it must return a Promise that resolves with the redirected URL. How exactly you do this depends on your environment \u2014 for a mobile app you may use a WebView, in a browser maybe a new tab\u2026 Here is an example that uses the browser\u2019s console and an experienced user: const openURL = url => { console . log ( 'Please visit the following URL, accept the permissions and copy the URL you are redirected to, then come back here. you have 10 seconds.' , url ) return new Promise ( resolve => { setTimeout ( async () => { const returnUrl = prompt ( 'Paste the new URL here.' ) resolve ( returnUrl ) }, 10000 ) }) } And that\u2019s it! After the promise is resolved, cozy-client finishes the OAuth flow and you can start using it.", "title": "Starting the OAuth flow \ud83c\udfc4\u200d\u2642\ufe0f"}, {"location": "cozy-client/mobile-guide/#how-to-restore-a-previous-token", "text": "Nobody likes to enter passwords, and you don\u2019t want to make your user go through this whole process every time your app starts. In order to restore the client from a previous version, you need to give it a token and some extra information about itself. Both of these are returned by the openURL function, so you can store them wherever you see fit \u2014 in this example we\u2019ll use the localStorage API. import CozyClient from 'cozy-client' const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , scope : [ 'io.cozy.mydoctype' ], oauth : { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } }) const { token , infos } = client . startOAuthFlow ( openURL ) localStorage . setItem ( 'token' , token ) localStorage . setItem ( 'infos' , JSON . stringify ( infos )) Next time your app starts, you can pass these informations to the constructor. Here is a complete example of the OAuth client initilisation: const storedToken = localStorage . getItem ( 'token' ) || null const storedInfos = JSON . parse ( localStorage . getItem ( 'infos' )) || { clientName : 'MyClient' , softwareID : 'MyAppId' , redirectURI : 'http://localhost' } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , oauth : storedInfos , token : storedToken , scope : [ 'io.cozy.mydoctype' ] }); if ( ! storedToken ) { const { token , infos } = await client . startOAuthFlow ( openURL ) localStorage . setItem ( 'token' , token ) localStorage . setItem ( 'infos' , JSON . stringify ( infos )) }", "title": "How to restore a previous token ?"}, {"location": "cozy-client/mobile-guide/#how-to-logout-the-client", "text": "When a user logout, we would like remove all references on this instance and remove all user data. You can just use cozyClient.logout() .", "title": "How to logout the client ?"}, {"location": "cozy-client/mobile-guide/#support-offline-for-some-doctypes-with-cozy-pouch-link", "text": "If you are already using cozy-client and the StackLink , you may want to go further and store some documents locally so you can retrieve them even while being offline. Currently, you have a code like this one : import CozyClient , { StackLink } from 'cozy-client' const stackLink = new StackLink () const client = new CozyClient ({ // ... links : [ stackLink ] }) To manage the offline aspect, we provide the cozy-pouch-link . First, let\u2019s install it : # using npm npm install cozy-pouch-link # using yarn yarn add cozy-pouch-link Then, we will create a new instance of this link and give it the list of doctypes that we want to access offline. We have to put the PouchLink first, so it is reached first when we query the link chain : import CozyClient , { StackLink } from 'cozy-client' import PouchLink from 'cozy-pouch-link' const stackLink = new StackLink () const offlineDoctypes = [ 'io.cozy.todos' ] const pouchLink = new PouchLink ({ doctypes : offlineDoctypes , initialSync : true // whether you want to trigger the synchronization on login or not }) const client = new CozyClient ({ // ... links : [ pouchLink , stackLink ] }) The PouchLink will create the PouchDB databases for all offline doctypes and synchronize them with the distant CouchDB. All doctypes that are not managed by the PouchLink will be passed to the next link in the chain (in the previous example, the StackLink ). Additionally, it is possible to replicate some doctypes only in a specific direction: const pouchLink = new PouchLink ({ doctypes : [ 'io.cozy.todos' , 'io.cozy.files' , 'io.cozy.localtype' ], doctypesReplicationOptions : { 'io.cozy.todos' : { strategy : 'sync' // default, replicate both ways }, 'io.cozy.files' : { strategy : 'fromRemote' // replicate changes from the remote locally, but don't push any changes }, 'io.cozy.localtype' : { strategy : 'toRemote' // push changes to remote, but don't replicate changes from it } } initialSync : true }) If you choose the fromRemote strategy, the cozy-client mutation will not be executed on the PouchLink but rather on the StackLink. Since making the first query can be long (PouchDB will create the index first), you can specify the queries you want to be \u201cwarmed up\u201d. It means that, those queries will be executed by CozyClient during the PouchLink\u2019s instanciation, but CozyClient will use PouchDB only if those queries have been resolved at least one time. const buildRecentQuery = () => ({ definition : () => Q ( 'io.cozy.files' ) . where ({ type : 'file' , trashed : false , updated_at : { $gt : null } }) options : { as : 'recent-view-query' , fetchPolicy : defaultFetchPolicy , } }) const pouchLink = new PouchLink ({ doctypes : [ 'io.cozy.todos' , 'io.cozy.files' , 'io.cozy.localtype' ], doctypesReplicationOptions : { 'io.cozy.files' : { warmupQueries : [ buildRecentQuery () ] } } initialSync : true })", "title": "Support offline for some doctypes with cozy-pouch-link"}, {"location": "cozy-client/node/", "text": "How to use the client on Node environment ( ReferenceError: fetch is not defined ) ? \u00b6 Cozy-Client relies on the fetch function included in browsers (or polyfilled). This function does not exist on Node environments so we have to provide a polyfill. An example using node-fetch : import fetch from 'node-fetch' import CozyClient from 'cozy-client' global . fetch = fetch Then you will be able to use all the client methods and fetch data correctly. When using cozy-client on Node environment, you don\u2019t have access to all React specific APIs. If, for any reason, you want to access these APIs, you can still import them from cozy-client/dist/react .", "title": "Node"}, {"location": "cozy-client/node/#how-to-use-the-client-on-node-environment-referenceerror-fetch-is-not-defined", "text": "Cozy-Client relies on the fetch function included in browsers (or polyfilled). This function does not exist on Node environments so we have to provide a polyfill. An example using node-fetch : import fetch from 'node-fetch' import CozyClient from 'cozy-client' global . fetch = fetch Then you will be able to use all the client methods and fetch data correctly. When using cozy-client on Node environment, you don\u2019t have access to all React specific APIs. If, for any reason, you want to access these APIs, you can still import them from cozy-client/dist/react .", "title": "How to use the client on Node environment (ReferenceError: fetch is not defined) ?"}, {"location": "cozy-client/react-integration/", "text": "What is the Cozy-Client React Integration? \u00b6 In addition to the Javascript client, Cozy-Client provides a way to connect directly the data from your Cozy instance to your React components. Once connected, your components will receive the requesting data and a fetch status in their props. The data will automatically be refreshed upon modification. 1. Setup 1.a Initialize a CozyClient provider 1.b Use your own Redux store 2. Usage 2.a Requesting data with useQuery 2.b Requesting data with the queryConnect HOC 2.c Using a fetch policy to decrease network requests 2.d Keeping data up to date in real time 3. Mutating data 3.a Mutating data with useMutation 3.b Mutating data with Query 4. Testing 1. Setup \u00b6 The following procedure requires you to already know how to initialize a CozyClient instance and create a query to fetch documents. \u26a0\ufe0f The fromDOM instantiation method assumes the page you use is served by the Cozy Stack, and that there is a DOM node with the stack info. See how the application works for more information.
    1.a Initialize a CozyClient provider \u00b6 Import CozyClient and CozyProvider import CozyClient , { CozyProvider } from 'cozy-client' Initialize a CozyClient instance (see the CozyClient() documentation for additional parameters, for example to provide a schema) const client = CozyClient . fromDOM () Then wrap you React application inside a CozyProvider component with your newly instance of CozyClient in its props as client . function MyCozyApp ( props ) { return < CozyProvider client = { client }> < MyApp { ...props } /> } ReactDOM . render (< MyCozyApp />, document . getElementById ( 'main' ) ) The CozyClient will be available for consumption to all components inside your wrapped application. 1.b Use your own Redux store \u00b6 cozy-client uses redux internally to centralize the statuses of the various fetches and replications triggered by the library, and to store locally the data in a normalized way. If you already have a redux store in your app, you can configure cozy-client to use this existing store: import CozyClient , { CozyProvider } from 'cozy-client' import { combineReducers , createStore , applyMiddleware } from 'redux' const client = CozyClient . fromDOM ({ store : false // Important, otherwise a default store is created }) const store = createStore ( combineReducers ({ ... myReducers , cozy : client . reducer () }), applyMiddleware ( myMiddleware ) ) function MyCozyApp ( props ) { return < CozyProvider client = { client } store = { store }> < MyApp { ...props } /> } ReactDOM . render (< MyCozyApp />, document . getElementById ( 'main' ) ) 2. Usage \u00b6 2.a Requesting data with useQuery \u00b6 useQuery is the most straightforward to fetch data from the Cozy. Query results are cached and can be reused across components, you just have to name the query results (\u201cchecked-todos\u201d) below. import CozyClient , { useQuery , isQueryLoading , Q } from 'cozy-client' const client = CozyClient . fromDOM () client . ensureStore () const todos = 'io.cozy.todos' const checked = { checked : false } // Use the Q helper to build queries const queryDefinition = Q ( todos ). where ( checked ) function TodoList ( props ) { const queryResult = useQuery ( queryDefinition , { as : 'checked-todos' , fetchPolicy : CozyClient . fetchPolicies . olderThan ( 30 * 1000 ) }) return <> { queryResult => isQueryLoading ( queryResult ) ? < h1 > Loading ... : < ul >{ queryResult . data . map ( todo => < li >{ todo . label })} } < /> } function App () { return < CozyProvider client = { client }> < TodoList /> } useQuery also supports a \u201cdisabled\u201d parameter: if set to false the query won\u2019t be executed. This is useful when you have dependent queries that rely on the results of another query to have been fetched. 2.b Requesting data with \u00b6 If you cannot use a hook, you can use the Query render-prop component. Basic example of usage: import { Query , isQueryLoading , Q } from 'cozy-client' import React from 'react' const todos = 'io.cozy.todos' const checked = { checked : false } // Use the Q helper to build queries const queryDefinition = Q ( todos ). where ( checked ) const TodoList = () => ( < Query query = { queryDefinition }> { queryResult => isQueryLoading ( queryResult ) ? < h1 > Loading ... : < ul >{ queryResult . data . map ( todo => < li >{ todo . label })} } ) When we use Query to \u201cwrap\u201d a component, three things happen: - The query passed as a prop will be executed when Query mounts, resulting in the loading of data from the local Pouchdb (if any) or from the server; in the future it may load the data directly from the client-side store; - Query subscribes to the store, so that it is updated if the data changes; - Query passes the result of the query as props to the children function. The following props will be given to your wrapped component: - data : an array of documents - fetchStatus : the status of the fetch ( pending , loading , loaded or error ) - lastFetch : when the last fetch occurred - hasMore : the fetches being paginated, this property indicates if there are more documents to load You can also pass a function instead of a direct query definition. Your function will be given the props of the component and should return the requested query definition: import { Query , Q } from 'cozy-client' import React from 'react' const queryDefinition = function ( props ) { const todos = 'io.cozy.todos' const where = { checked : props . checked } return Q ( todos ). where ( where ) } const TodoList = ({ props }) => ( < Query query = { queryDefinition } checked = { props . checked }> {({ data , fetchStatus }) => ( fetchStatus !== 'loaded' ? < h1 > Loading ... : < ul >{ data . map ( todo => < li >{ todo . label })} ) } ) // use Note: Your query definition will be bound when the component mounts. Future changes in props will not modify the query. 2.c Requesting data with the queryConnect HOC \u00b6 At your preference, you can use a higher-order component. queryConnect will take the name of the props field where it should send the result of the query and the actual query: import { queryConnect , Q } from 'cozy-client' function TodoList ( props ) { const { data , fetchStatus } = props . result if ( fetchStatus !== 'loaded' ) { return < h1 > Loading ... } else { return < ul >{ data . map ( todo => < li >{ todo . label })} } } const ConnectedTodoList = queryConnect ({ result : { query : Q ( 'io.cozy.todos' ). where ({ checked : false }) } })( TodoList ) queryConnect will use internally, so you will inherit the same behaviour. With the same syntax, you may register multiple queries to run: import { queryConnect , Q } from 'cozy-client' function TodoList ( props ) { const { data , fetchStatus } = props . checked if ( fetchStatus !== 'loaded' ) { return < h1 > Loading ... } else { return < ul >{ data . map ( todo => < li >{ todo . label })} } } const todos = 'io.cozy.todos' const checked = { query : Q ( todos ). where ({ checked : false }) } const archived = { query : Q ( todos ). where ({ archive : false }) } const queries = { checked , archived } const ConnectedTodoList = queryConnect ( queries )( TodoList ) 2.d Using a fetch policy to decrease network requests \u00b6 When multiple components share the same data, you might want to share the data between the two components. In this case, you do not want to execute 2 network requests for the same data, the two components should share the same data and only 1 network request should be executed. There are two solutions: 1) Lift the data fetching up the React tree: make a parent of the two components be the responsible for the data. 2) Using fetch policies to prevent re-fetching of the data 1 can be a good solution but sometimes the components needing the data are too far down the tree and/or too decoupled; it might not make sense to lift the data fetching up only to have to drill the data down the tree again. Using useQuery , Query and queryConnect , you can declare a fetch policy . It tells cozy-client if it should execute the query at componentDidMount time. It enables N components to be connected to the same query without triggering N requests. A fetch policy is a function receiving the state of the current query and returning true if it should be fetched and false otherwise. It is important to name the query with as when using fetch policies otherwise query data cannot be shared across components. import { Q } from 'cozy-client' const queryDefinition = () => Q ( 'io.cozy.todos' ) const MyComponent = () => { // io.cozy.todos will not be refetched if there are already io.cozy.todos // in the store and the data is fresh (updated less than 30s ago). const fetchPolicy = CozyClient . olderThan ( 30 * 1000 ) const as = 'my-query' // With Query and a render prop return (< Query as = { as } query = { queryDefinition } fetchPolicy = { fetchPolicy }>{ ({ data : todos }) => {< TodoList todos = { todos } />} }) } // With queryConnect queryConnect ({ todos : { as , query , fetchPolicy } })( TodoList ) See CozyClient::fetchPolicies for the API documentation. 2.e Keeping data up to date in real time \u00b6 Sometimes the data you are displaying will be changed from other places than your app. Maybe the data is shared and someone else has updated it, or maybe it simply changes over time. You can however keep your UI always up to date without constantly re-running your queries, by subscribing to changes in real time. This is done with the RealTimeQueries component: import { RealTimeQueries } from 'cozy-client' function MyParentComponent ( props ) { return ( <> < ConnectedTodoList /> < RealTimeQueries doctype = \"io.cozy.todos\" /> < /> ) } You subscribe to changes for an entire doctype using RealTimeQueries , and as long as that component is rendered all documents from the given doctype in your queries will automatically stay up to date. 3. Mutating data \u00b6 The simplest way is to use the hook useClient to get the CozyClient instance you gave to the upper. import { useClient } from 'cozy-client' function TodoList ( props ) { const client = useClient () const createNewTodo = e => client . create ( 'io.cozy.todos' , { label : e . target . elements [ 'new-todo' ], checked : false } ) return ( <> < ul > { /* todo items */ } < form onSubmit = { createNewTodo }> < label htmlFor = \"new-todo\" > Todo < input id = \"new-todo\" name = \"new-todo\" /> < button type = \"submit\" > Add todo < /> ) } 3.a Mutating data with useMutation \u00b6 We also provides a hook to manage client.save mutation state called useMutation . import { useMutation } from 'cozy-client' function TodoLabelInlineEdit ({ todo }) { const [ label , setLabel ] = useState ( todo . label ) const { mutate , mutationStatus } = useMutation () const handleChange = event => { setLabel ( event . target . value ) } const handleBlur = () => { mutate ({ ... todo , label }) } return ( < div style = {{ display : 'flex' }}> < input type = \"text\" aria - label = \"Label\" style = {{ marginRight : '1rem' }} value = { label } onChange = { handleChange } onBlur = { handleBlur } /> { mutationStatus === 'loaded' ? '\u2713' : null } { mutationStatus === 'failed' ? '\u2717' : null } ) } 3.b Mutating data with Query \u00b6 also takes a mutations optional props. It should have a function that will receive the CozyClient instance, the query requested and the rest of props given to the component, and should return a keyed object which will be added to the props of your wrapped component. import { Query } from 'cozy-client' const todos = 'io.cozy.todos' const checked = { checked : false } const queryDefinition = Q ( todos ). where ( checked ) const mutations = client => ({ createDocument : client . create . bind ( client ) }) function TodoList () { return < Query query = { queryDefinition } mutations = { mutations }> { ({ data , fetchStatus }) => fetchStatus !== 'loaded' ? < h1 > Loading ... : < ul >{ data . map ( todo => < li >{ todo . label })} } } 4. Testing \u00b6 When testing, it is useful to prefill the client with data and mock the network. You can use createMockClient for this. Say we want to test the following component: import React from 'react' import { useQuery , Q } from 'cozy-client' function TodoList () { const { data , fetchStatus , lastError } = useQuery ( Q ( 'io.cozy.todos' ), { as : 'todos' }) if ( fetchStatus === 'failed' ) { return < h1 > An error occurred : { lastError . message } } else if ( fetchStatus !== 'loaded' ) { return < h1 > Loading ... } else { return ( <> < h1 id = \"todos-heading\" > Todos < ul aria - labelledby = \"todos-heading\" > { data . map ( todo => ( < li key = { todo . id }>{ todo . label } ))} < /> ) } } export default TodoList We want to make sure the component renders correctly. In our test, we can create a mocked client with predefined data for the todos query, and test it with testing-library : import React from 'react' import { createMockClient , CozyProvider } from 'cozy-client' import { render , screen , within } from '@testing-library/react' import TodoList from './TodoList' describe ( 'TodoList' , () => { const setup = client => { return render ( < CozyProvider client = { client }> < TodoList /> ) } it ( 'should show the todos' , () => { const mockClient = createMockClient ({ queries : { todos : { doctype : 'io.cozy.todos' , data : [ { id : 'todo1' , name : 'Write tests' , done : true }, { id : 'todo2' , name : 'Write code' , done : true }, { id : 'todo3' , name : 'Take breaks' , done : true }, { id : 'todo4' , name : 'Write documentation' , done : false } ] } } }) setup ( mockClient ) const list = screen . getByRole ( 'list' , { name : /todos/i }) const { getAllByRole } = within ( list ) const items = getAllByRole ( 'listitem' ) expect ( items . length ). toBe ( 4 ) }) it ( 'should display the error message' , () => { const mockClient = createMockClient ({ queries : { todos : { doctype : 'io.cozy.todos' , queryError : new Error ( 'Network error' ) } } }) setup ( mockClient ) expect ( screen . getByText ( /network error/i )). toBeDefined () }) })", "title": "React integration"}, {"location": "cozy-client/react-integration/#what-is-the-cozy-client-react-integration", "text": "In addition to the Javascript client, Cozy-Client provides a way to connect directly the data from your Cozy instance to your React components. Once connected, your components will receive the requesting data and a fetch status in their props. The data will automatically be refreshed upon modification. 1. Setup 1.a Initialize a CozyClient provider 1.b Use your own Redux store 2. Usage 2.a Requesting data with useQuery 2.b Requesting data with the queryConnect HOC 2.c Using a fetch policy to decrease network requests 2.d Keeping data up to date in real time 3. Mutating data 3.a Mutating data with useMutation 3.b Mutating data with Query 4. Testing", "title": "What is the Cozy-Client React Integration?"}, {"location": "cozy-client/react-integration/#1-setup", "text": "The following procedure requires you to already know how to initialize a CozyClient instance and create a query to fetch documents. \u26a0\ufe0f The fromDOM instantiation method assumes the page you use is served by the Cozy Stack, and that there is a DOM node with the stack info. See how the application works for more information.
    ", "title": "1. Setup"}, {"location": "cozy-client/react-integration/#1a-initialize-a-cozyclient-provider", "text": "Import CozyClient and CozyProvider import CozyClient , { CozyProvider } from 'cozy-client' Initialize a CozyClient instance (see the CozyClient() documentation for additional parameters, for example to provide a schema) const client = CozyClient . fromDOM () Then wrap you React application inside a CozyProvider component with your newly instance of CozyClient in its props as client . function MyCozyApp ( props ) { return < CozyProvider client = { client }> < MyApp { ...props } /> } ReactDOM . render (< MyCozyApp />, document . getElementById ( 'main' ) ) The CozyClient will be available for consumption to all components inside your wrapped application.", "title": "1.a Initialize a CozyClient provider"}, {"location": "cozy-client/react-integration/#1b-use-your-own-redux-store", "text": "cozy-client uses redux internally to centralize the statuses of the various fetches and replications triggered by the library, and to store locally the data in a normalized way. If you already have a redux store in your app, you can configure cozy-client to use this existing store: import CozyClient , { CozyProvider } from 'cozy-client' import { combineReducers , createStore , applyMiddleware } from 'redux' const client = CozyClient . fromDOM ({ store : false // Important, otherwise a default store is created }) const store = createStore ( combineReducers ({ ... myReducers , cozy : client . reducer () }), applyMiddleware ( myMiddleware ) ) function MyCozyApp ( props ) { return < CozyProvider client = { client } store = { store }> < MyApp { ...props } /> } ReactDOM . render (< MyCozyApp />, document . getElementById ( 'main' ) )", "title": "1.b Use your own Redux store"}, {"location": "cozy-client/react-integration/#2-usage", "text": "", "title": "2. Usage"}, {"location": "cozy-client/react-integration/#2a-requesting-data-with-usequery", "text": "useQuery is the most straightforward to fetch data from the Cozy. Query results are cached and can be reused across components, you just have to name the query results (\u201cchecked-todos\u201d) below. import CozyClient , { useQuery , isQueryLoading , Q } from 'cozy-client' const client = CozyClient . fromDOM () client . ensureStore () const todos = 'io.cozy.todos' const checked = { checked : false } // Use the Q helper to build queries const queryDefinition = Q ( todos ). where ( checked ) function TodoList ( props ) { const queryResult = useQuery ( queryDefinition , { as : 'checked-todos' , fetchPolicy : CozyClient . fetchPolicies . olderThan ( 30 * 1000 ) }) return <> { queryResult => isQueryLoading ( queryResult ) ? < h1 > Loading ... : < ul >{ queryResult . data . map ( todo => < li >{ todo . label })} } < /> } function App () { return < CozyProvider client = { client }> < TodoList /> } useQuery also supports a \u201cdisabled\u201d parameter: if set to false the query won\u2019t be executed. This is useful when you have dependent queries that rely on the results of another query to have been fetched.", "title": "2.a Requesting data with useQuery"}, {"location": "cozy-client/react-integration/#2b-requesting-data-with-ltquery-gt", "text": "If you cannot use a hook, you can use the Query render-prop component. Basic example of usage: import { Query , isQueryLoading , Q } from 'cozy-client' import React from 'react' const todos = 'io.cozy.todos' const checked = { checked : false } // Use the Q helper to build queries const queryDefinition = Q ( todos ). where ( checked ) const TodoList = () => ( < Query query = { queryDefinition }> { queryResult => isQueryLoading ( queryResult ) ? < h1 > Loading ... : < ul >{ queryResult . data . map ( todo => < li >{ todo . label })} } ) When we use Query to \u201cwrap\u201d a component, three things happen: - The query passed as a prop will be executed when Query mounts, resulting in the loading of data from the local Pouchdb (if any) or from the server; in the future it may load the data directly from the client-side store; - Query subscribes to the store, so that it is updated if the data changes; - Query passes the result of the query as props to the children function. The following props will be given to your wrapped component: - data : an array of documents - fetchStatus : the status of the fetch ( pending , loading , loaded or error ) - lastFetch : when the last fetch occurred - hasMore : the fetches being paginated, this property indicates if there are more documents to load You can also pass a function instead of a direct query definition. Your function will be given the props of the component and should return the requested query definition: import { Query , Q } from 'cozy-client' import React from 'react' const queryDefinition = function ( props ) { const todos = 'io.cozy.todos' const where = { checked : props . checked } return Q ( todos ). where ( where ) } const TodoList = ({ props }) => ( < Query query = { queryDefinition } checked = { props . checked }> {({ data , fetchStatus }) => ( fetchStatus !== 'loaded' ? < h1 > Loading ... : < ul >{ data . map ( todo => < li >{ todo . label })} ) } ) // use Note: Your query definition will be bound when the component mounts. Future changes in props will not modify the query.", "title": "2.b Requesting data with &lt;Query /&gt;"}, {"location": "cozy-client/react-integration/#2c-requesting-data-with-the-queryconnect-hoc", "text": "At your preference, you can use a higher-order component. queryConnect will take the name of the props field where it should send the result of the query and the actual query: import { queryConnect , Q } from 'cozy-client' function TodoList ( props ) { const { data , fetchStatus } = props . result if ( fetchStatus !== 'loaded' ) { return < h1 > Loading ... } else { return < ul >{ data . map ( todo => < li >{ todo . label })} } } const ConnectedTodoList = queryConnect ({ result : { query : Q ( 'io.cozy.todos' ). where ({ checked : false }) } })( TodoList ) queryConnect will use internally, so you will inherit the same behaviour. With the same syntax, you may register multiple queries to run: import { queryConnect , Q } from 'cozy-client' function TodoList ( props ) { const { data , fetchStatus } = props . checked if ( fetchStatus !== 'loaded' ) { return < h1 > Loading ... } else { return < ul >{ data . map ( todo => < li >{ todo . label })} } } const todos = 'io.cozy.todos' const checked = { query : Q ( todos ). where ({ checked : false }) } const archived = { query : Q ( todos ). where ({ archive : false }) } const queries = { checked , archived } const ConnectedTodoList = queryConnect ( queries )( TodoList )", "title": "2.c Requesting data with the queryConnect HOC"}, {"location": "cozy-client/react-integration/#2d-using-a-fetch-policy-to-decrease-network-requests", "text": "When multiple components share the same data, you might want to share the data between the two components. In this case, you do not want to execute 2 network requests for the same data, the two components should share the same data and only 1 network request should be executed. There are two solutions: 1) Lift the data fetching up the React tree: make a parent of the two components be the responsible for the data. 2) Using fetch policies to prevent re-fetching of the data 1 can be a good solution but sometimes the components needing the data are too far down the tree and/or too decoupled; it might not make sense to lift the data fetching up only to have to drill the data down the tree again. Using useQuery , Query and queryConnect , you can declare a fetch policy . It tells cozy-client if it should execute the query at componentDidMount time. It enables N components to be connected to the same query without triggering N requests. A fetch policy is a function receiving the state of the current query and returning true if it should be fetched and false otherwise. It is important to name the query with as when using fetch policies otherwise query data cannot be shared across components. import { Q } from 'cozy-client' const queryDefinition = () => Q ( 'io.cozy.todos' ) const MyComponent = () => { // io.cozy.todos will not be refetched if there are already io.cozy.todos // in the store and the data is fresh (updated less than 30s ago). const fetchPolicy = CozyClient . olderThan ( 30 * 1000 ) const as = 'my-query' // With Query and a render prop return (< Query as = { as } query = { queryDefinition } fetchPolicy = { fetchPolicy }>{ ({ data : todos }) => {< TodoList todos = { todos } />} }) } // With queryConnect queryConnect ({ todos : { as , query , fetchPolicy } })( TodoList ) See CozyClient::fetchPolicies for the API documentation.", "title": "2.d Using a fetch policy to decrease network requests"}, {"location": "cozy-client/react-integration/#2e-keeping-data-up-to-date-in-real-time", "text": "Sometimes the data you are displaying will be changed from other places than your app. Maybe the data is shared and someone else has updated it, or maybe it simply changes over time. You can however keep your UI always up to date without constantly re-running your queries, by subscribing to changes in real time. This is done with the RealTimeQueries component: import { RealTimeQueries } from 'cozy-client' function MyParentComponent ( props ) { return ( <> < ConnectedTodoList /> < RealTimeQueries doctype = \"io.cozy.todos\" /> < /> ) } You subscribe to changes for an entire doctype using RealTimeQueries , and as long as that component is rendered all documents from the given doctype in your queries will automatically stay up to date.", "title": "2.e Keeping data up to date in real time"}, {"location": "cozy-client/react-integration/#3-mutating-data", "text": "The simplest way is to use the hook useClient to get the CozyClient instance you gave to the upper. import { useClient } from 'cozy-client' function TodoList ( props ) { const client = useClient () const createNewTodo = e => client . create ( 'io.cozy.todos' , { label : e . target . elements [ 'new-todo' ], checked : false } ) return ( <> < ul > { /* todo items */ } < form onSubmit = { createNewTodo }> < label htmlFor = \"new-todo\" > Todo < input id = \"new-todo\" name = \"new-todo\" /> < button type = \"submit\" > Add todo < /> ) }", "title": "3. Mutating data"}, {"location": "cozy-client/react-integration/#3a-mutating-data-with-usemutation", "text": "We also provides a hook to manage client.save mutation state called useMutation . import { useMutation } from 'cozy-client' function TodoLabelInlineEdit ({ todo }) { const [ label , setLabel ] = useState ( todo . label ) const { mutate , mutationStatus } = useMutation () const handleChange = event => { setLabel ( event . target . value ) } const handleBlur = () => { mutate ({ ... todo , label }) } return ( < div style = {{ display : 'flex' }}> < input type = \"text\" aria - label = \"Label\" style = {{ marginRight : '1rem' }} value = { label } onChange = { handleChange } onBlur = { handleBlur } /> { mutationStatus === 'loaded' ? '\u2713' : null } { mutationStatus === 'failed' ? '\u2717' : null } ) }", "title": "3.a Mutating data with useMutation"}, {"location": "cozy-client/react-integration/#3b-mutating-data-with-query", "text": " also takes a mutations optional props. It should have a function that will receive the CozyClient instance, the query requested and the rest of props given to the component, and should return a keyed object which will be added to the props of your wrapped component. import { Query } from 'cozy-client' const todos = 'io.cozy.todos' const checked = { checked : false } const queryDefinition = Q ( todos ). where ( checked ) const mutations = client => ({ createDocument : client . create . bind ( client ) }) function TodoList () { return < Query query = { queryDefinition } mutations = { mutations }> { ({ data , fetchStatus }) => fetchStatus !== 'loaded' ? < h1 > Loading ... : < ul >{ data . map ( todo => < li >{ todo . label })} } }", "title": "3.b Mutating data with Query"}, {"location": "cozy-client/react-integration/#4-testing", "text": "When testing, it is useful to prefill the client with data and mock the network. You can use createMockClient for this. Say we want to test the following component: import React from 'react' import { useQuery , Q } from 'cozy-client' function TodoList () { const { data , fetchStatus , lastError } = useQuery ( Q ( 'io.cozy.todos' ), { as : 'todos' }) if ( fetchStatus === 'failed' ) { return < h1 > An error occurred : { lastError . message } } else if ( fetchStatus !== 'loaded' ) { return < h1 > Loading ... } else { return ( <> < h1 id = \"todos-heading\" > Todos < ul aria - labelledby = \"todos-heading\" > { data . map ( todo => ( < li key = { todo . id }>{ todo . label } ))} < /> ) } } export default TodoList We want to make sure the component renders correctly. In our test, we can create a mocked client with predefined data for the todos query, and test it with testing-library : import React from 'react' import { createMockClient , CozyProvider } from 'cozy-client' import { render , screen , within } from '@testing-library/react' import TodoList from './TodoList' describe ( 'TodoList' , () => { const setup = client => { return render ( < CozyProvider client = { client }> < TodoList /> ) } it ( 'should show the todos' , () => { const mockClient = createMockClient ({ queries : { todos : { doctype : 'io.cozy.todos' , data : [ { id : 'todo1' , name : 'Write tests' , done : true }, { id : 'todo2' , name : 'Write code' , done : true }, { id : 'todo3' , name : 'Take breaks' , done : true }, { id : 'todo4' , name : 'Write documentation' , done : false } ] } } }) setup ( mockClient ) const list = screen . getByRole ( 'list' , { name : /todos/i }) const { getAllByRole } = within ( list ) const items = getAllByRole ( 'listitem' ) expect ( items . length ). toBe ( 4 ) }) it ( 'should display the error message' , () => { const mockClient = createMockClient ({ queries : { todos : { doctype : 'io.cozy.todos' , queryError : new Error ( 'Network error' ) } } }) setup ( mockClient ) expect ( screen . getByText ( /network error/i )). toBeDefined () }) })", "title": "4. Testing"}, {"location": "cozy-client/relationships/", "text": "What are relations in Cozy-Client? \u00b6 CouchDB is a document store. It does not materialize relations between documents. We do, however, have a standardized way of describing relations between cozy documents. This allows Cozy-Client to give us some automation. In CouchDB \u00b6 Relations between documents are materialized under a relationships object at the root of the document. Relations are referenced by their names, e.g. authors . Each relation is an object with a data property, containing either one reference , or an array of references . A reference is an object containing at least: * _type : the name of the referenced doctype, e.g. io.cozy.contacts * _id : the id of the referenced document. For instance, a book -> authors relationship might be represented like this: { \"_id\" : \"mobydick\" , \"relationships\" : { \"authors\" : { \"data\" : [{ \"_id\" : \"hermanmelville\" , \"_type\" : \"io.cozy.contacts\" }] } } } Please see the cozy-doctypes documentation for more insights about the syntax. In the Cozy-Client schema \u00b6 Cozy-client knows how to handle these relations thanks to the schema you provide at initialization: const schema = { books : { doctype : 'io.cozy.books' , attributes : {}, relationships : { authors : { doctype : 'io.cozy.contacts' , type : 'has-many' } } } } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , token : '...' , schema }) We explain below what are the different types of relations. Relation types \u00b6 Cozy-Client predefines two basic relation types that must be specified in the schema: 'has-one' : the relation has a unique reference. 'has-many' : the relation can have several references. Files relations \u00b6 The files implements a special type of relation: 'io.cozy.files:has-many' . This relation name is referenced_by , which is an array of references, just like the 'has-many' relation. The stack implements routes to handle this kind of relation on the /files endpoint. See the stack documentation . Note specific view index are defined on referenced_by relationships, allowing fast queries on it. Customize relations \u00b6 You are free to create your own relation type if you need a special behaviour. For instance, Banks doctypes implements HasManyBills or HasManyReimbursements . Old relation types \u00b6 Note there are two others basic relations, that are here for backward compatibility: 'has-one-in-place' 'has-many-in-place' \u26a0\ufe0f For new doctypes, you should not use those relations, prefer 'has-one' or 'has-many' . With these relations, instead of using the relationships attribute, you reference directly the ids of linked documents at the root of your data: const schema = { books : { doctype : 'io.cozy.books' , attributes : {}, relationships : { authors : { doctype : 'io.cozy.contacts' , type : 'has-many-in-place' } } } } const book = { \"_id\" : \"mobydick\" , \"authors\" : [ \"hermanmelville\" ] } Metadata \u00b6 It is possible to assign metadatas to relationships. You need to modify the content of the document relationships somehow and save the modified document. const doc = { _id : \"mobydick\" , relationships : { authors : { data : [{ _id : \"hermanmelville\" , _type : \"io.cozy.contacts\" }] } } } doc . relationships . authors . data [ 0 ]. metadata = { addressId : \"123\" } await client . save ( doc ) Usage \u00b6 Include relations in your query \u00b6 Relations are not loaded eagerly by default. If you want your query to load your relations for you, you will have to name them in an include() request. const query = Q ( 'io.cozy.books' ) . include ([ 'authors' ]) . limitBy ( 20 ) You will then find your relations under the data attribute: const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] const firstAuthors = firstDoc . authors . data Add a relation to an existing document \u00b6 When the relationship is a has-many type, you can call the add(docs) to create the relationship: const otherAuthors = [{ _id : 'Rivest' }, { _id : 'Shamir' }] const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . authors . add ( otherAuthors ) add also accepts single document: firstDoc . authors . add ({ _id : 'Adleman' }) Likewise, when the relationship is a has-one , use add(doc) : const printer = { _id : 'abc123' , _type : 'io.cozy.company' , name : 'Harper & Brothers' } const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . printingCompany . add ( printer ) Remove a relation to an existing document \u00b6 For has-many relationships, use the remove(docs) method: const wrongAuthors = [{ _id : 'James Wrong' }, { _id : 'Henry Mistake' }] const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . authors . remove ( wrongAuthors ) Just like add , remove accepts a single document. For has-one relationships, just use remove() , with no argument: const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . printingCompany . remove () Create a new file with existing relations \u00b6 Simply pass the reference to your file as a third parameter to create() : const photo = { _id : \"sunset.jpg\" } const reference = { _id : \"1324\" , _type : \"io.cozy.photos.albums\" } const albumReference = { albums : [ albumReference ] } await client . create ( 'io.cozy.files' , photo , albumReference )", "title": "Using relationships"}, {"location": "cozy-client/relationships/#what-are-relations-in-cozy-client", "text": "CouchDB is a document store. It does not materialize relations between documents. We do, however, have a standardized way of describing relations between cozy documents. This allows Cozy-Client to give us some automation.", "title": "What are relations in Cozy-Client?"}, {"location": "cozy-client/relationships/#in-couchdb", "text": "Relations between documents are materialized under a relationships object at the root of the document. Relations are referenced by their names, e.g. authors . Each relation is an object with a data property, containing either one reference , or an array of references . A reference is an object containing at least: * _type : the name of the referenced doctype, e.g. io.cozy.contacts * _id : the id of the referenced document. For instance, a book -> authors relationship might be represented like this: { \"_id\" : \"mobydick\" , \"relationships\" : { \"authors\" : { \"data\" : [{ \"_id\" : \"hermanmelville\" , \"_type\" : \"io.cozy.contacts\" }] } } } Please see the cozy-doctypes documentation for more insights about the syntax.", "title": "In CouchDB"}, {"location": "cozy-client/relationships/#in-the-cozy-client-schema", "text": "Cozy-client knows how to handle these relations thanks to the schema you provide at initialization: const schema = { books : { doctype : 'io.cozy.books' , attributes : {}, relationships : { authors : { doctype : 'io.cozy.contacts' , type : 'has-many' } } } } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , token : '...' , schema }) We explain below what are the different types of relations.", "title": "In the Cozy-Client schema"}, {"location": "cozy-client/relationships/#relation-types", "text": "Cozy-Client predefines two basic relation types that must be specified in the schema: 'has-one' : the relation has a unique reference. 'has-many' : the relation can have several references.", "title": "Relation types"}, {"location": "cozy-client/relationships/#files-relations", "text": "The files implements a special type of relation: 'io.cozy.files:has-many' . This relation name is referenced_by , which is an array of references, just like the 'has-many' relation. The stack implements routes to handle this kind of relation on the /files endpoint. See the stack documentation . Note specific view index are defined on referenced_by relationships, allowing fast queries on it.", "title": "Files relations"}, {"location": "cozy-client/relationships/#customize-relations", "text": "You are free to create your own relation type if you need a special behaviour. For instance, Banks doctypes implements HasManyBills or HasManyReimbursements .", "title": "Customize relations"}, {"location": "cozy-client/relationships/#old-relation-types", "text": "Note there are two others basic relations, that are here for backward compatibility: 'has-one-in-place' 'has-many-in-place' \u26a0\ufe0f For new doctypes, you should not use those relations, prefer 'has-one' or 'has-many' . With these relations, instead of using the relationships attribute, you reference directly the ids of linked documents at the root of your data: const schema = { books : { doctype : 'io.cozy.books' , attributes : {}, relationships : { authors : { doctype : 'io.cozy.contacts' , type : 'has-many-in-place' } } } } const book = { \"_id\" : \"mobydick\" , \"authors\" : [ \"hermanmelville\" ] }", "title": "Old relation types"}, {"location": "cozy-client/relationships/#metadata", "text": "It is possible to assign metadatas to relationships. You need to modify the content of the document relationships somehow and save the modified document. const doc = { _id : \"mobydick\" , relationships : { authors : { data : [{ _id : \"hermanmelville\" , _type : \"io.cozy.contacts\" }] } } } doc . relationships . authors . data [ 0 ]. metadata = { addressId : \"123\" } await client . save ( doc )", "title": "Metadata"}, {"location": "cozy-client/relationships/#usage", "text": "", "title": "Usage"}, {"location": "cozy-client/relationships/#include-relations-in-your-query", "text": "Relations are not loaded eagerly by default. If you want your query to load your relations for you, you will have to name them in an include() request. const query = Q ( 'io.cozy.books' ) . include ([ 'authors' ]) . limitBy ( 20 ) You will then find your relations under the data attribute: const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] const firstAuthors = firstDoc . authors . data", "title": "Include relations in your query"}, {"location": "cozy-client/relationships/#add-a-relation-to-an-existing-document", "text": "When the relationship is a has-many type, you can call the add(docs) to create the relationship: const otherAuthors = [{ _id : 'Rivest' }, { _id : 'Shamir' }] const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . authors . add ( otherAuthors ) add also accepts single document: firstDoc . authors . add ({ _id : 'Adleman' }) Likewise, when the relationship is a has-one , use add(doc) : const printer = { _id : 'abc123' , _type : 'io.cozy.company' , name : 'Harper & Brothers' } const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . printingCompany . add ( printer )", "title": "Add a relation to an existing document"}, {"location": "cozy-client/relationships/#remove-a-relation-to-an-existing-document", "text": "For has-many relationships, use the remove(docs) method: const wrongAuthors = [{ _id : 'James Wrong' }, { _id : 'Henry Mistake' }] const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . authors . remove ( wrongAuthors ) Just like add , remove accepts a single document. For has-one relationships, just use remove() , with no argument: const response = await client . query ( query ) const docs = response . data const firstDoc = docs [ 0 ] firstDoc . printingCompany . remove ()", "title": "Remove a relation to an existing document"}, {"location": "cozy-client/relationships/#create-a-new-file-with-existing-relations", "text": "Simply pass the reference to your file as a third parameter to create() : const photo = { _id : \"sunset.jpg\" } const reference = { _id : \"1324\" , _type : \"io.cozy.photos.albums\" } const albumReference = { albums : [ albumReference ] } await client . create ( 'io.cozy.files' , photo , albumReference )", "title": "Create a new file with existing relations"}, {"location": "cozy-client/schema/", "text": "What is a Cozy-Client schema? \u00b6 Schemas help Cozy-Client to know about the structure of your documents. With schemas, Cozy-Client may automatically fill the version attributes in cozyMetadata , it will allows traversal of links between documents, and it will help you validate your document before saving them in the CouchDB database. Structure of a schema \u00b6 A schema for a doctype is an object with the following attributes: doctype : the actual doctype name in cozy doctypeVersion : the version of the schema for this doctype ; it will help you to manage documents from different versions or migrate documents from a version to another attributes : the list of attributes with their constraints relationships : the description of the relations between documents All attributes but the doctype one are entirely optional. { \"doctype\" : \"io.cozy.todos\" , \"doctypeVersion\" : 45 , \"attributes\" : { \"label\" : { \"unique\" : true }, }, \"relationships\" : { \"tasks\" : { \"doctype\" : \"io.cozy.tasks\" , \"type\" : \"has-many\" } } } Today, attributes have only a unique property which, when at true will validate the uniqueness of the value. Other properties will be added in the future. You do not need to list every attribute you use. You may only add those for which you have a constraint to list. Relations are described in the \u201cUsing relationship\u201d document. Providing schemas \u00b6 Schemas are provided with a keyed object in the schema parameter at CozyClient initialization: const schema = { todos : { doctype : 'io.cozy.books' , attributes : {}, relationships : { items : { doctype : 'io.cozy.contact' , type : 'has-many' } } } } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , token : '...' , schema }) Adding a schema to an already initialized CozyClient instance \u00b6 Provide your schemas to the addSchema() method, in the same form as for initialization: const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , token : '...' , schema : { } }) const additionalSchema = { todos : { doctype : 'io.cozy.books' , attributes : {}, relationships : { items : { doctype : 'io.cozy.contact' , type : 'has-many' } } } } client . addSchema ( additionalSchema ) Validation \u00b6 Today Cozy-Client only validates uniqueness of fields described as is in the schema. If you provide a schema, Cozy-Client will automatically try to validate your documents when you save them. An exception will be thrown if the validation fails. You can validate a document explicitly with validate() . Be sure the document has a _type attribute with the doctype name if it has never been saved to CouchDB. const book = { _type : 'io.cozy.books' , name : 'La horde de contrevent' } if ( ! client . validate ( book )) { throw new Error ( 'Something is wrong with this book document' ) }", "title": "Schema"}, {"location": "cozy-client/schema/#what-is-a-cozy-client-schema", "text": "Schemas help Cozy-Client to know about the structure of your documents. With schemas, Cozy-Client may automatically fill the version attributes in cozyMetadata , it will allows traversal of links between documents, and it will help you validate your document before saving them in the CouchDB database.", "title": "What is a Cozy-Client schema?"}, {"location": "cozy-client/schema/#structure-of-a-schema", "text": "A schema for a doctype is an object with the following attributes: doctype : the actual doctype name in cozy doctypeVersion : the version of the schema for this doctype ; it will help you to manage documents from different versions or migrate documents from a version to another attributes : the list of attributes with their constraints relationships : the description of the relations between documents All attributes but the doctype one are entirely optional. { \"doctype\" : \"io.cozy.todos\" , \"doctypeVersion\" : 45 , \"attributes\" : { \"label\" : { \"unique\" : true }, }, \"relationships\" : { \"tasks\" : { \"doctype\" : \"io.cozy.tasks\" , \"type\" : \"has-many\" } } } Today, attributes have only a unique property which, when at true will validate the uniqueness of the value. Other properties will be added in the future. You do not need to list every attribute you use. You may only add those for which you have a constraint to list. Relations are described in the \u201cUsing relationship\u201d document.", "title": "Structure of a schema"}, {"location": "cozy-client/schema/#providing-schemas", "text": "Schemas are provided with a keyed object in the schema parameter at CozyClient initialization: const schema = { todos : { doctype : 'io.cozy.books' , attributes : {}, relationships : { items : { doctype : 'io.cozy.contact' , type : 'has-many' } } } } const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , token : '...' , schema })", "title": "Providing schemas"}, {"location": "cozy-client/schema/#adding-a-schema-to-an-already-initialized-cozyclient-instance", "text": "Provide your schemas to the addSchema() method, in the same form as for initialization: const client = new CozyClient ({ uri : 'http://cozy.tools:8080' , token : '...' , schema : { } }) const additionalSchema = { todos : { doctype : 'io.cozy.books' , attributes : {}, relationships : { items : { doctype : 'io.cozy.contact' , type : 'has-many' } } } } client . addSchema ( additionalSchema )", "title": "Adding a schema to an already initialized CozyClient instance"}, {"location": "cozy-client/schema/#validation", "text": "Today Cozy-Client only validates uniqueness of fields described as is in the schema. If you provide a schema, Cozy-Client will automatically try to validate your documents when you save them. An exception will be thrown if the validation fails. You can validate a document explicitly with validate() . Be sure the document has a _type attribute with the doctype name if it has never been saved to CouchDB. const book = { _type : 'io.cozy.books' , name : 'La horde de contrevent' } if ( ! client . validate ( book )) { throw new Error ( 'Something is wrong with this book document' ) }", "title": "Validation"}, {"location": "cozy-client/timeseries/", "text": "How-to manipulate time series \u00b6 Save time series \u00b6 This example shows how to save a time series of an electrical consumption: const electricalConsumption = { dataType : 'electricity' , startDate : \"2021-02-14T00:30:00+01:00\" , endDate : \"2021-02-14T02:30:00+01:00\" , source : \"enedis.fr\" , theme : \"energy\" series : [ { date : \"2021-02-14T00:30:00+01:00\" , consumption : 474 }, { date : \"2021-02-14T01:30:00+01:00\" , consumption : 184 }, { date : \"2021-02-14T02:30:00+01:00\" , consumption : 152 } ] } await saveTimeSerie ( client , electricalConsumption ) Retrieve time series \u00b6 This example shows how to fetch time series of an electrical consumption, for a specific time interval and data source: const params = { dataType : 'electricity' , startDate : \"2021-02-14\" , endDate : \"2021-02-15\" , source : \"enedis.fr\" , limit : 100 } const electricalConsumption = await fetchTimeSerieByIntervalAndSource ( client , params )", "title": "Using time series"}, {"location": "cozy-client/timeseries/#how-to-manipulate-time-series", "text": "", "title": "How-to manipulate time series"}, {"location": "cozy-client/timeseries/#save-time-series", "text": "This example shows how to save a time series of an electrical consumption: const electricalConsumption = { dataType : 'electricity' , startDate : \"2021-02-14T00:30:00+01:00\" , endDate : \"2021-02-14T02:30:00+01:00\" , source : \"enedis.fr\" , theme : \"energy\" series : [ { date : \"2021-02-14T00:30:00+01:00\" , consumption : 474 }, { date : \"2021-02-14T01:30:00+01:00\" , consumption : 184 }, { date : \"2021-02-14T02:30:00+01:00\" , consumption : 152 } ] } await saveTimeSerie ( client , electricalConsumption )", "title": "Save time series"}, {"location": "cozy-client/timeseries/#retrieve-time-series", "text": "This example shows how to fetch time series of an electrical consumption, for a specific time interval and data source: const params = { dataType : 'electricity' , startDate : \"2021-02-14\" , endDate : \"2021-02-15\" , source : \"enedis.fr\" , limit : 100 } const electricalConsumption = await fetchTimeSerieByIntervalAndSource ( client , params )", "title": "Retrieve time series"}, {"location": "cozy-client/api/cozy-pouch-link/", "text": "Classes \u00b6 PouchLink Link to be passed to a CozyClient instance to support CouchDB. It instantiates PouchDB collections for each doctype that it supports and knows how to respond to queries and mutations. Loop Utility to call a function (task) periodically and on demand immediately. Public API start stop scheduleImmediateTask waitForCurrentTask PouchManager Handles the lifecycle of several pouches Creates/Destroys the pouches Replicates periodically Constants \u00b6 persistLastReplicatedDocID Persist the last replicated doc id for a doctype getLastReplicatedDocID \u21d2 string Get the last replicated doc id for a doctype destroyAllLastReplicatedDocID Destroy all the replicated doc id getPersistedSyncedDoctypes \u21d2 object Get the persisted doctypes destroySyncedDoctypes Destroy the synced doctypes persistDoctypeLastSequence Persist the last CouchDB sequence for a synced doctype getDoctypeLastSequence \u21d2 string Get the last CouchDB sequence for a doctype destroyAllDoctypeLastSequence Destroy all the last sequence destroyDoctypeLastSequence Destroy the last sequence for a doctype persistWarmedUpQueries Persist the warmed up queries getPersistedWarmedUpQueries \u21d2 object Get the warmed up queries destroyWarmedUpQueries Destroy the warmed queries getAdapterName \u21d2 string Get the adapter name persistAdapterName Persist the adapter name fetchRemoteInstance \u21d2 object Fetch remote instance fetchRemoteLastSequence \u21d2 string Fetch last sequence from remote instance replicateAllDocs \u21d2 Array Replicate all docs locally from a remote URL. It uses the _all_docs view, and bulk insert the docs. Note it saves the last replicated _id for each run and starts from there in case the process stops before the end. getDatabaseName \u21d2 string Get the database name based on prefix and doctype getPrefix \u21d2 string Get the URI prefix Functions \u00b6 getQueryAlias(query) \u21d2 string Typedefs \u00b6 SyncStatus : \"idle\" | \"replicating\" MigrationParams : object Migrate the current adapter SyncInfo : object Persist the synchronized doctypes MigrationParams \u21d2 object Migrate a PouchDB database to a new adapter. PouchLink \u00b6 Link to be passed to a CozyClient instance to support CouchDB. It instantiates PouchDB collections for each doctype that it supports and knows how to respond to queries and mutations. Kind : global class PouchLink new PouchLink([opts]) .replicationStatus : Record. .getPouchAdapterName \u21d2 string .handleOnSync() .startReplication() \u21d2 void .stopReplication() \u21d2 void .needsToWaitWarmup(doctype) \u21d2 boolean new PouchLink([opts]) \u00b6 constructor - Initializes a new PouchLink Returns : object - The PouchLink instance Param Type Default Description [opts] object [opts.replicationInterval] number Milliseconds between replications opts.doctypes Array. Doctypes to replicate opts.doctypesReplicationOptions Array. A mapping from doctypes to replication options. All pouch replication options can be used, as well as the \u201cstrategy\u201d option that determines which way the replication is done (can be \u201csync\u201d, \u201cfromRemote\u201d or \u201ctoRemote\u201d) pouchLink.replicationStatus : Record. \u00b6 Stores replication states per doctype Kind : instance property of PouchLink pouchLink.getPouchAdapterName \u21d2 string \u00b6 Return the PouchDB adapter name. Should be IndexedDB for newest adapters. Kind : instance property of PouchLink Returns : string - The adapter name pouchLink.handleOnSync() \u00b6 Receives PouchDB updates (documents grouped by doctype). Normalizes the data (.id -> ._id, .rev -> _rev). Passes the data to the client and to the onSync handler. Emits an event (pouchlink:sync:end) when the sync (all doctypes) is done Kind : instance method of PouchLink pouchLink.startReplication() \u21d2 void \u00b6 User of the link can call this to start ongoing replications. Typically, it can be used when the application regains focus. Emits pouchlink:sync:start event when the replication begins Kind : instance method of PouchLink Access : public pouchLink.stopReplication() \u21d2 void \u00b6 User of the link can call this to stop ongoing replications. Typically, it can be used when the applications loses focus. Emits pouchlink:sync:stop event Kind : instance method of PouchLink Access : public pouchLink.needsToWaitWarmup(doctype) \u21d2 boolean \u00b6 Check if there is warmup queries for this doctype and return if those queries are already warmed up or not Kind : instance method of PouchLink Returns : boolean - the need to wait for the warmup Param Type Description doctype string Doctype to check Loop \u00b6 Utility to call a function (task) periodically and on demand immediately. Public API start stop scheduleImmediateTask waitForCurrentTask Kind : global class Loop .start() .stop() .runImmediateTasks() .scheduleImmediateTask(task) .runTask() .round() loop.start() \u00b6 Starts the loop. Will run the task periodically each this.delay ms. Ignores multiple starts. Kind : instance method of Loop loop.stop() \u00b6 Stops the loop, clears immediate tasks. Cancels current task if possible Kind : instance method of Loop loop.runImmediateTasks() \u00b6 Flushes the immediate tasks list and calls each task. Each task is awaited before the next is started. Kind : instance method of Loop loop.scheduleImmediateTask(task) \u00b6 Schedules a task to be run immediately at next round. Ignored if loop is not started. If not task is passed, the default task from the loop is used. Kind : instance method of Loop Param Type Default Description task function Optional custom function to be run immediately loop.runTask() \u00b6 Calls and saves current task. Stops loop in case of error of the task. Kind : instance method of Loop loop.round() \u00b6 Runs immediate tasks and then schedule the next round. Immediate tasks are called sequentially without delay There is a delay between immediate tasks and normal periodic tasks. Kind : instance method of Loop PouchManager \u00b6 Handles the lifecycle of several pouches Creates/Destroys the pouches Replicates periodically Kind : global class PouchManager .ensureDatabasesExist() .startReplicationLoop() .stopReplicationLoop() .syncImmediately() .replicateOnce() pouchManager.ensureDatabasesExist() \u00b6 Via a call to info() we ensure the database exist on the remote side. This is done only once since after the first call, we are sure that the databases have been created. Kind : instance method of PouchManager pouchManager.startReplicationLoop() \u00b6 Starts periodic syncing of the pouches Kind : instance method of PouchManager pouchManager.stopReplicationLoop() \u00b6 Stop periodic syncing of the pouches Kind : instance method of PouchManager pouchManager.syncImmediately() \u00b6 If a replication is currently ongoing, will start a replication just after it has finished. Otherwise it will start a replication immediately Kind : instance method of PouchManager pouchManager.replicateOnce() \u00b6 Starts replication Kind : instance method of PouchManager persistLastReplicatedDocID \u00b6 Persist the last replicated doc id for a doctype Kind : global constant Param Type Description doctype string The replicated doctype id string The docid getLastReplicatedDocID \u21d2 string \u00b6 Get the last replicated doc id for a doctype Kind : global constant Returns : string - The last replicated docid Param Type Description doctype string The doctype destroyAllLastReplicatedDocID \u00b6 Destroy all the replicated doc id Kind : global constant getPersistedSyncedDoctypes \u21d2 object \u00b6 Get the persisted doctypes Kind : global constant Returns : object - The synced doctypes destroySyncedDoctypes \u00b6 Destroy the synced doctypes Kind : global constant persistDoctypeLastSequence \u00b6 Persist the last CouchDB sequence for a synced doctype Kind : global constant Param Type Description doctype string The synced doctype sequence string The sequence hash getDoctypeLastSequence \u21d2 string \u00b6 Get the last CouchDB sequence for a doctype Kind : global constant Returns : string - the last sequence Param Type Description doctype string The doctype destroyAllDoctypeLastSequence \u00b6 Destroy all the last sequence Kind : global constant destroyDoctypeLastSequence \u00b6 Destroy the last sequence for a doctype Kind : global constant Param Type Description doctype string The doctype persistWarmedUpQueries \u00b6 Persist the warmed up queries Kind : global constant Param Type Description warmedUpQueries object The warmedup queries getPersistedWarmedUpQueries \u21d2 object \u00b6 Get the warmed up queries Kind : global constant Returns : object - the warmed up queries destroyWarmedUpQueries \u00b6 Destroy the warmed queries Kind : global constant getAdapterName \u21d2 string \u00b6 Get the adapter name Kind : global constant Returns : string - The adapter name persistAdapterName \u00b6 Persist the adapter name Kind : global constant Param Type Description adapter string The adapter name fetchRemoteInstance \u21d2 object \u00b6 Fetch remote instance Kind : global constant Returns : object - The instance response Param Type Description url URL The remote instance URL, including the credentials params object The params to query the remote instance fetchRemoteLastSequence \u21d2 string \u00b6 Fetch last sequence from remote instance Kind : global constant Returns : string - The last sequence Param Type Description baseUrl string The base URL of the remote instance replicateAllDocs \u21d2 Array \u00b6 Replicate all docs locally from a remote URL. It uses the _all_docs view, and bulk insert the docs. Note it saves the last replicated _id for each run and starts from there in case the process stops before the end. Kind : global constant Returns : Array - The retrieved documents Param Type Description db object Pouch instance baseUrl string The remote instance doctype string The doctype to replicate getDatabaseName \u21d2 string \u00b6 Get the database name based on prefix and doctype Kind : global constant Returns : string - The database name Param Type Description prefix string The URL prefix doctype string The database doctype getPrefix \u21d2 string \u00b6 Get the URI prefix Kind : global constant Returns : string - The URI prefix Param Type Description uri string The Cozy URI getQueryAlias(query) \u21d2 string \u00b6 Kind : global function Returns : string - alias Param Type Description query QueryDefinition The query definition whose name we\u2019re getting SyncStatus : \"idle\" | \"replicating\" \u00b6 Kind : global typedef MigrationParams : object \u00b6 Migrate the current adapter Kind : global typedef Param Type Description params MigrationParams Migration params Properties Name Type Description [fromAdapter] string The current adapter type, e.g. \u2018idb\u2019 [toAdapter] string The new adapter type, e.g. \u2018indexeddb\u2019 [url] string The Cozy URL [plugins] Array. The PouchDB plugins SyncInfo : object \u00b6 Persist the synchronized doctypes Kind : global typedef Param Type Description syncedDoctypes Record. The sync doctypes Properties Name Type Date string MigrationParams \u21d2 object \u00b6 Migrate a PouchDB database to a new adapter. Kind : global typedef Returns : object - - The migrated pouch Param Type Description params MigrationParams The migration params Properties Name Type Description [dbName] string The database name [fromAdapter] string The current adapter type, e.g. \u2018idb\u2019 [toAdapter] string The new adapter type, e.g. \u2018indexeddb\u2019", "title": "Cozy Pouch Link API"}, {"location": "cozy-client/api/cozy-pouch-link/#classes", "text": "PouchLink Link to be passed to a CozyClient instance to support CouchDB. It instantiates PouchDB collections for each doctype that it supports and knows how to respond to queries and mutations. Loop Utility to call a function (task) periodically and on demand immediately. Public API start stop scheduleImmediateTask waitForCurrentTask PouchManager Handles the lifecycle of several pouches Creates/Destroys the pouches Replicates periodically", "title": "Classes"}, {"location": "cozy-client/api/cozy-pouch-link/#constants", "text": "persistLastReplicatedDocID Persist the last replicated doc id for a doctype getLastReplicatedDocID \u21d2 string Get the last replicated doc id for a doctype destroyAllLastReplicatedDocID Destroy all the replicated doc id getPersistedSyncedDoctypes \u21d2 object Get the persisted doctypes destroySyncedDoctypes Destroy the synced doctypes persistDoctypeLastSequence Persist the last CouchDB sequence for a synced doctype getDoctypeLastSequence \u21d2 string Get the last CouchDB sequence for a doctype destroyAllDoctypeLastSequence Destroy all the last sequence destroyDoctypeLastSequence Destroy the last sequence for a doctype persistWarmedUpQueries Persist the warmed up queries getPersistedWarmedUpQueries \u21d2 object Get the warmed up queries destroyWarmedUpQueries Destroy the warmed queries getAdapterName \u21d2 string Get the adapter name persistAdapterName Persist the adapter name fetchRemoteInstance \u21d2 object Fetch remote instance fetchRemoteLastSequence \u21d2 string Fetch last sequence from remote instance replicateAllDocs \u21d2 Array Replicate all docs locally from a remote URL. It uses the _all_docs view, and bulk insert the docs. Note it saves the last replicated _id for each run and starts from there in case the process stops before the end. getDatabaseName \u21d2 string Get the database name based on prefix and doctype getPrefix \u21d2 string Get the URI prefix", "title": "Constants"}, {"location": "cozy-client/api/cozy-pouch-link/#functions", "text": "getQueryAlias(query) \u21d2 string", "title": "Functions"}, {"location": "cozy-client/api/cozy-pouch-link/#typedefs", "text": "SyncStatus : \"idle\" | \"replicating\" MigrationParams : object Migrate the current adapter SyncInfo : object Persist the synchronized doctypes MigrationParams \u21d2 object Migrate a PouchDB database to a new adapter.", "title": "Typedefs"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchlink", "text": "Link to be passed to a CozyClient instance to support CouchDB. It instantiates PouchDB collections for each doctype that it supports and knows how to respond to queries and mutations. Kind : global class PouchLink new PouchLink([opts]) .replicationStatus : Record. .getPouchAdapterName \u21d2 string .handleOnSync() .startReplication() \u21d2 void .stopReplication() \u21d2 void .needsToWaitWarmup(doctype) \u21d2 boolean", "title": "PouchLink"}, {"location": "cozy-client/api/cozy-pouch-link/#new-pouchlinkopts", "text": "constructor - Initializes a new PouchLink Returns : object - The PouchLink instance Param Type Default Description [opts] object [opts.replicationInterval] number Milliseconds between replications opts.doctypes Array. Doctypes to replicate opts.doctypesReplicationOptions Array. A mapping from doctypes to replication options. All pouch replication options can be used, as well as the \u201cstrategy\u201d option that determines which way the replication is done (can be \u201csync\u201d, \u201cfromRemote\u201d or \u201ctoRemote\u201d)", "title": "new PouchLink([opts])"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchlinkreplicationstatus-recordstring-syncstatus", "text": "Stores replication states per doctype Kind : instance property of PouchLink", "title": "pouchLink.replicationStatus : Record.<string, SyncStatus>"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchlinkgetpouchadaptername-string", "text": "Return the PouchDB adapter name. Should be IndexedDB for newest adapters. Kind : instance property of PouchLink Returns : string - The adapter name", "title": "pouchLink.getPouchAdapterName \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchlinkhandleonsync", "text": "Receives PouchDB updates (documents grouped by doctype). Normalizes the data (.id -> ._id, .rev -> _rev). Passes the data to the client and to the onSync handler. Emits an event (pouchlink:sync:end) when the sync (all doctypes) is done Kind : instance method of PouchLink", "title": "pouchLink.handleOnSync()"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchlinkstartreplication-void", "text": "User of the link can call this to start ongoing replications. Typically, it can be used when the application regains focus. Emits pouchlink:sync:start event when the replication begins Kind : instance method of PouchLink Access : public", "title": "pouchLink.startReplication() \u21d2 void"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchlinkstopreplication-void", "text": "User of the link can call this to stop ongoing replications. Typically, it can be used when the applications loses focus. Emits pouchlink:sync:stop event Kind : instance method of PouchLink Access : public", "title": "pouchLink.stopReplication() \u21d2 void"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchlinkneedstowaitwarmupdoctype-boolean", "text": "Check if there is warmup queries for this doctype and return if those queries are already warmed up or not Kind : instance method of PouchLink Returns : boolean - the need to wait for the warmup Param Type Description doctype string Doctype to check", "title": "pouchLink.needsToWaitWarmup(doctype) \u21d2 boolean"}, {"location": "cozy-client/api/cozy-pouch-link/#loop", "text": "Utility to call a function (task) periodically and on demand immediately. Public API start stop scheduleImmediateTask waitForCurrentTask Kind : global class Loop .start() .stop() .runImmediateTasks() .scheduleImmediateTask(task) .runTask() .round()", "title": "Loop"}, {"location": "cozy-client/api/cozy-pouch-link/#loopstart", "text": "Starts the loop. Will run the task periodically each this.delay ms. Ignores multiple starts. Kind : instance method of Loop", "title": "loop.start()"}, {"location": "cozy-client/api/cozy-pouch-link/#loopstop", "text": "Stops the loop, clears immediate tasks. Cancels current task if possible Kind : instance method of Loop", "title": "loop.stop()"}, {"location": "cozy-client/api/cozy-pouch-link/#looprunimmediatetasks", "text": "Flushes the immediate tasks list and calls each task. Each task is awaited before the next is started. Kind : instance method of Loop", "title": "loop.runImmediateTasks()"}, {"location": "cozy-client/api/cozy-pouch-link/#loopscheduleimmediatetasktask", "text": "Schedules a task to be run immediately at next round. Ignored if loop is not started. If not task is passed, the default task from the loop is used. Kind : instance method of Loop Param Type Default Description task function Optional custom function to be run immediately", "title": "loop.scheduleImmediateTask(task)"}, {"location": "cozy-client/api/cozy-pouch-link/#loopruntask", "text": "Calls and saves current task. Stops loop in case of error of the task. Kind : instance method of Loop", "title": "loop.runTask()"}, {"location": "cozy-client/api/cozy-pouch-link/#loopround", "text": "Runs immediate tasks and then schedule the next round. Immediate tasks are called sequentially without delay There is a delay between immediate tasks and normal periodic tasks. Kind : instance method of Loop", "title": "loop.round()"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchmanager", "text": "Handles the lifecycle of several pouches Creates/Destroys the pouches Replicates periodically Kind : global class PouchManager .ensureDatabasesExist() .startReplicationLoop() .stopReplicationLoop() .syncImmediately() .replicateOnce()", "title": "PouchManager"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchmanagerensuredatabasesexist", "text": "Via a call to info() we ensure the database exist on the remote side. This is done only once since after the first call, we are sure that the databases have been created. Kind : instance method of PouchManager", "title": "pouchManager.ensureDatabasesExist()"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchmanagerstartreplicationloop", "text": "Starts periodic syncing of the pouches Kind : instance method of PouchManager", "title": "pouchManager.startReplicationLoop()"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchmanagerstopreplicationloop", "text": "Stop periodic syncing of the pouches Kind : instance method of PouchManager", "title": "pouchManager.stopReplicationLoop()"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchmanagersyncimmediately", "text": "If a replication is currently ongoing, will start a replication just after it has finished. Otherwise it will start a replication immediately Kind : instance method of PouchManager", "title": "pouchManager.syncImmediately()"}, {"location": "cozy-client/api/cozy-pouch-link/#pouchmanagerreplicateonce", "text": "Starts replication Kind : instance method of PouchManager", "title": "pouchManager.replicateOnce()"}, {"location": "cozy-client/api/cozy-pouch-link/#persistlastreplicateddocid", "text": "Persist the last replicated doc id for a doctype Kind : global constant Param Type Description doctype string The replicated doctype id string The docid", "title": "persistLastReplicatedDocID"}, {"location": "cozy-client/api/cozy-pouch-link/#getlastreplicateddocid-string", "text": "Get the last replicated doc id for a doctype Kind : global constant Returns : string - The last replicated docid Param Type Description doctype string The doctype", "title": "getLastReplicatedDocID \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#destroyalllastreplicateddocid", "text": "Destroy all the replicated doc id Kind : global constant", "title": "destroyAllLastReplicatedDocID"}, {"location": "cozy-client/api/cozy-pouch-link/#getpersistedsynceddoctypes-object", "text": "Get the persisted doctypes Kind : global constant Returns : object - The synced doctypes", "title": "getPersistedSyncedDoctypes \u21d2 object"}, {"location": "cozy-client/api/cozy-pouch-link/#destroysynceddoctypes", "text": "Destroy the synced doctypes Kind : global constant", "title": "destroySyncedDoctypes"}, {"location": "cozy-client/api/cozy-pouch-link/#persistdoctypelastsequence", "text": "Persist the last CouchDB sequence for a synced doctype Kind : global constant Param Type Description doctype string The synced doctype sequence string The sequence hash", "title": "persistDoctypeLastSequence"}, {"location": "cozy-client/api/cozy-pouch-link/#getdoctypelastsequence-string", "text": "Get the last CouchDB sequence for a doctype Kind : global constant Returns : string - the last sequence Param Type Description doctype string The doctype", "title": "getDoctypeLastSequence \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#destroyalldoctypelastsequence", "text": "Destroy all the last sequence Kind : global constant", "title": "destroyAllDoctypeLastSequence"}, {"location": "cozy-client/api/cozy-pouch-link/#destroydoctypelastsequence", "text": "Destroy the last sequence for a doctype Kind : global constant Param Type Description doctype string The doctype", "title": "destroyDoctypeLastSequence"}, {"location": "cozy-client/api/cozy-pouch-link/#persistwarmedupqueries", "text": "Persist the warmed up queries Kind : global constant Param Type Description warmedUpQueries object The warmedup queries", "title": "persistWarmedUpQueries"}, {"location": "cozy-client/api/cozy-pouch-link/#getpersistedwarmedupqueries-object", "text": "Get the warmed up queries Kind : global constant Returns : object - the warmed up queries", "title": "getPersistedWarmedUpQueries \u21d2 object"}, {"location": "cozy-client/api/cozy-pouch-link/#destroywarmedupqueries", "text": "Destroy the warmed queries Kind : global constant", "title": "destroyWarmedUpQueries"}, {"location": "cozy-client/api/cozy-pouch-link/#getadaptername-string", "text": "Get the adapter name Kind : global constant Returns : string - The adapter name", "title": "getAdapterName \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#persistadaptername", "text": "Persist the adapter name Kind : global constant Param Type Description adapter string The adapter name", "title": "persistAdapterName"}, {"location": "cozy-client/api/cozy-pouch-link/#fetchremoteinstance-object", "text": "Fetch remote instance Kind : global constant Returns : object - The instance response Param Type Description url URL The remote instance URL, including the credentials params object The params to query the remote instance", "title": "fetchRemoteInstance \u21d2 object"}, {"location": "cozy-client/api/cozy-pouch-link/#fetchremotelastsequence-string", "text": "Fetch last sequence from remote instance Kind : global constant Returns : string - The last sequence Param Type Description baseUrl string The base URL of the remote instance", "title": "fetchRemoteLastSequence \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#replicatealldocs-array", "text": "Replicate all docs locally from a remote URL. It uses the _all_docs view, and bulk insert the docs. Note it saves the last replicated _id for each run and starts from there in case the process stops before the end. Kind : global constant Returns : Array - The retrieved documents Param Type Description db object Pouch instance baseUrl string The remote instance doctype string The doctype to replicate", "title": "replicateAllDocs \u21d2 Array"}, {"location": "cozy-client/api/cozy-pouch-link/#getdatabasename-string", "text": "Get the database name based on prefix and doctype Kind : global constant Returns : string - The database name Param Type Description prefix string The URL prefix doctype string The database doctype", "title": "getDatabaseName \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#getprefix-string", "text": "Get the URI prefix Kind : global constant Returns : string - The URI prefix Param Type Description uri string The Cozy URI", "title": "getPrefix \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#getqueryaliasquery-string", "text": "Kind : global function Returns : string - alias Param Type Description query QueryDefinition The query definition whose name we\u2019re getting", "title": "getQueryAlias(query) \u21d2 string"}, {"location": "cozy-client/api/cozy-pouch-link/#syncstatus-idle-replicating", "text": "Kind : global typedef", "title": "SyncStatus : "idle" | "replicating""}, {"location": "cozy-client/api/cozy-pouch-link/#migrationparams-object", "text": "Migrate the current adapter Kind : global typedef Param Type Description params MigrationParams Migration params Properties Name Type Description [fromAdapter] string The current adapter type, e.g. \u2018idb\u2019 [toAdapter] string The new adapter type, e.g. \u2018indexeddb\u2019 [url] string The Cozy URL [plugins] Array. The PouchDB plugins", "title": "MigrationParams : object"}, {"location": "cozy-client/api/cozy-pouch-link/#syncinfo-object", "text": "Persist the synchronized doctypes Kind : global typedef Param Type Description syncedDoctypes Record. The sync doctypes Properties Name Type Date string", "title": "SyncInfo : object"}, {"location": "cozy-client/api/cozy-pouch-link/#migrationparams-object_1", "text": "Migrate a PouchDB database to a new adapter. Kind : global typedef Returns : object - - The migrated pouch Param Type Description params MigrationParams The migration params Properties Name Type Description [dbName] string The database name [fromAdapter] string The current adapter type, e.g. \u2018idb\u2019 [toAdapter] string The new adapter type, e.g. \u2018indexeddb\u2019", "title": "MigrationParams \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/", "text": "Classes \u00b6 AppCollection Extends DocumentCollection API along with specific methods for io.cozy.apps . AppsRegistryCollection Extends DocumentCollection API along with specific methods for io.cozy.apps_registry . Collection Utility class to abstract an regroup identical methods and logics for specific collections. CozyStackClient Main API against the cozy-stack server. DocumentCollection Abstracts a collection of documents of the same doctype, providing CRUD methods and other helpers. FileCollection Implements DocumentCollection API along with specific methods for io.cozy.files . Files are a special type of documents and are handled differently by the stack: special routes are to be used, and there is a notion of referenced files, aka files associated to a specific document NotesCollection Implements DocumentCollection API to interact with the /notes endpoint of the stack OAuthClient Specialized CozyStackClient for mobile, implementing stack registration through OAuth. OAuthClientsCollection Implements DocumentCollection API to interact with the /settings/clients endpoint of the stack PermissionCollection Implements DocumentCollection API along with specific methods for io.cozy.permissions . PromiseCache Caches promises while they are pending Serves to dedupe equal queries requested at the same time SettingsCollection Implements DocumentCollection API to interact with the /settings endpoint of the stack SharingCollection Implements the DocumentCollection API along with specific methods for io.cozy.sharings . TriggerCollection Implements DocumentCollection API along with specific methods for io.cozy.triggers . Constants \u00b6 dontThrowNotFoundError \u21d2 object Handler for error response which return a empty value for \"not found\" error isIndexNotFoundError \u21d2 Array | null Helper to identify an index not found error isIndexConflictError \u21d2 Array | null Helper to identify an index conflict isIndexNotUsedWarning \u21d2 Array | null Helper to identify a not used index isNoUsableIndexError \u21d2 Array | null Helper to identify a no usable index error isDocumentUpdateConflict \u21d2 Array | null Helper to identify a document conflict isFile \u21d2 boolean Returns true when parameter has type directory, file or has _type io.cozy.files isDirectory \u21d2 boolean Returns true when parameters has type directory getIllegalCharacters \u21d2 string Get the list of illegal characters in the file name makeKeyFromPartialFilter \u21d2 string Process a partial filter to generate a string key getIndexNameFromFields \u21d2 string Name an index, based on its indexed fields and partial filter. It follows this naming convention: by_{indexed_field1}_and_{indexed_field2}_filter_({partial_filter.key1}_{partial_filter.value1})_and_({partial_filter.key2}_{partial_filter.value2}) transformSort \u21d2 MangoSort Transform sort into Array getIndexFields \u21d2 Array Compute fields that should be indexed for a mango query to work isMatchingIndex \u21d2 boolean Check if an index is matching the given fields makeOperatorsExplicit \u21d2 object Transform a query to make all operators explicit getPermissionsFor \u21d2 object Build a permission set normalizeSettings \u21d2 object Normalizing a document for SettingsCollection context getSharingRules \u21d2 Array. Rules determine the behavior of the sharing when changes are made to the shared document See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing forceDownload Force a download from the given href encodePath \u21d2 string Encode a path for use in a URL by encoding special characters but keeping slashes Functions \u00b6 getAccessToken() \u21d2 string Get the access token string getAccessToken() \u21d2 string Get the app token string getIconURL() Get Icon URL using blob mechanism if OAuth connected or using preloaded url when blob not needed handleNorOperator(conditions) \u21d2 Array Handle the $nor operator in a query CouchDB transforms $nor into $and with $ne operators garbageCollect() Delete outdated results from cache memoize() Memoize with maxDuration and custom key getSharingRulesForPhotosAlbum(document, sharingType) \u21d2 Array. Compute the rules that define how to share a Photo Album. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing getSharingPolicyForReferencedFiles(sharingType) \u21d2 SharingPolicy Compute the sharing policy for a ReferencedFile based on its sharing type getSharingPolicyForAlbum(sharingType) \u21d2 Array. Compute the sharing policy for an Album based on its sharing type getSharingRulesForFile(document, sharingType) \u21d2 Array. Compute the rules that define how to share a File. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing getSharingPolicyForFile(document, sharingType) \u21d2 SharingPolicy Compute the sharing policy for a File based on its sharing type getSharingRulesForOrganizations(document) \u21d2 Array. Compute the rules that define how to share an Organization. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing toRelationshipItem(item) \u21d2 RelationshipItem Compute the RelationshipItem that can be referenced as a sharing recipient getCozyURL() Get a uniform formatted URL and SSL information according to a provided URL joinPath(start, end) \u21d2 string Join two paths together ensuring there is only one slash between them Typedefs \u00b6 FetchChangesReturnValue \u21d2 Promise. Use Couch _changes API Deleted and design docs are filtered by default, thus documents are retrieved in the response (include_docs is set to true in the parameters of _changes). You should use fetchChangesRaw to have low level control on _changes parameters. IOCozyFolder : object Folder SpecificFileAttributesForKonnector : object Specific file attributes for creation for konnector CouchDBViewCursor : Array. | string Cursor used for Mango queries pagination DirectoryAttributes : object Attributes used for directory creation FileAttributes : object Attributes used for file creation FileDocument : object Document representing a io.cozy.files Stream : object Stream is not defined in a browser, but is on NodeJS environment OAuthClient : object Document representing a io.cozy.oauth.clients ArchivePages : object Attributes used for create archive link by ids FetchChangesReturnValue \u21d2 FetchChangesReturnValue Use cozy-stack's _changes API for io.cozy.files Design docs are filtered by default, thus documents are retrieved in the response (includeDocs is set to true in the parameters of _changes). Deleted and trashed documents can be filtered on demand and files' paths can be requested as well. Since deleted and trashed documents are skipped by cozy-stack rather than CouchDB, when either option is set to true, the response can contain less documents than the defined limit. Thus one should rely solely on the pending result attribute to determine if more documents can be fetched or not. You should use fetchChangesRaw to call CouchDB's _changes API. JobDocument : object Document representing a io.cozy.jobs MangoPartialFilter : Object MangoSelector : object MangoSort : Array. MangoQueryOptions : object DesignDoc : object Attributes representing a design doc SessionCode : string SessionCodeRes AccessTokenRes TwoFactorNeededRes Permission \u21d2 Permission async getOwnPermissions - deprecated: please use fetchOwnPermissions instead Permission \u21d2 Permission async fetchOwnPermissions - Fetches permissions Rule : object A sharing rule Recipient : object An io.cozy.contact Sharing : object An io.cozy.sharings document SharingPolicy : object Define the add/update/remove policies for a sharing SharingType : undefined | 'one-way' | 'two-way' Define how a document is synced between sharing's owner and receivers. RelationshipItem : object Define a recipient that can be used as target of a sharing CozyStackClient : object AppCollection \u00b6 Extends DocumentCollection API along with specific methods for io.cozy.apps . Kind : global class appCollection.all() \u21d2 Object \u00b6 Lists all apps, without filters. The returned documents are not paginated by the stack. Kind : instance method of AppCollection Returns : Object - The JSON API conformant response. Throws : FetchError AppsRegistryCollection \u00b6 Extends DocumentCollection API along with specific methods for io.cozy.apps_registry . Kind : global class appsRegistryCollection.get(slug) \u21d2 Promise.<{data: object}> \u00b6 Fetches an app from the registry. Kind : instance method of AppsRegistryCollection Returns : Promise.<{data: object}> - JsonAPI response containing normalized document as data attribute Throws : FetchError Param Type Description slug string Slug of the app Collection \u00b6 Utility class to abstract an regroup identical methods and logics for specific collections. Kind : global class Collection.get(stackClient, endpoint, options) \u21d2 Promise. \u00b6 Utility method aimed to return only one document. Kind : static method of Collection Returns : Promise. - JsonAPI response containing normalized document as data attribute Param Type Default Description stackClient CozyStackClient CozyStackClient endpoint string Stack endpoint options object Options of the collection options.normalize function Callback to normalize response data (default data => data ) [options.method] string \"GET\" HTTP method CozyStackClient \u00b6 Main API against the cozy-stack server. Kind : global class CozyStackClient .collection(doctype) \u21d2 DocumentCollection .fetch(method, path, [body], [opts]) \u21d2 object .refreshToken() \u21d2 Promise .fetchJSON(method, path, body, options) \u21d2 object .setToken(token) .getAccessToken() \u21d2 string cozyStackClient.collection(doctype) \u21d2 DocumentCollection \u00b6 Creates a DocumentCollection instance. Kind : instance method of CozyStackClient Param Type Description doctype string The collection doctype. cozyStackClient.fetch(method, path, [body], [opts]) \u21d2 object \u00b6 Fetches an endpoint in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Default Description method string The HTTP method. path string The URI. [body] object The payload. [opts] object Options for fetch cozyStackClient.refreshToken() \u21d2 Promise \u00b6 Retrieves a new app token by refreshing the currently used token. Kind : instance method of CozyStackClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : Error The client should already have an access token to use this function Error The client couldn\u2019t fetch a new token cozyStackClient.fetchJSON(method, path, body, options) \u21d2 object \u00b6 Fetches JSON in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Description method string The HTTP method. path string The URI. body object The payload. options object Options cozyStackClient.setToken(token) \u00b6 Change or set the API token Kind : instance method of CozyStackClient Param Type Description token string | AppToken | AccessToken Stack API token cozyStackClient.getAccessToken() \u21d2 string \u00b6 Get the access token string, being an oauth token or an app token Kind : instance method of CozyStackClient Returns : string - token DocumentCollection \u00b6 Abstracts a collection of documents of the same doctype, providing CRUD methods and other helpers. Kind : global class DocumentCollection instance .all(options) \u21d2 Promise.<{data, meta, skip, bookmark, next}> .fetchDocumentsWithMango(path, selector, options) .findWithMango(path, selector, options) \u21d2 Promise. .find(selector, options) \u21d2 Promise.<{data, skip, bookmark, next, execution_stats}> .findAll(selector, options) \u21d2 Promise.> .get(id) \u21d2 Promise. .getAll() .create(doc) .update(document) .destroy(doc) .updateAll(rawDocs) .destroyAll(docs) .toMangoOptions(selector, options) \u21d2 MangoQueryOptions .createIndex(fields, indexOption) \u21d2 Promise.<{id, fields}> .fetchAllMangoIndexes() \u21d2 Promise.> .destroyIndex(index) \u21d2 Promise. .copyIndex(existingIndex, newIndexName) \u21d2 Promise. .fetchChangesRaw(couchOptions) static .normalizeDoctype(doctype) \u21d2 function documentCollection.all(options) \u21d2 Promise.<{data, meta, skip, bookmark, next}> \u00b6 Lists all documents of the collection, without filters. The returned documents are paginated by the stack. Kind : instance method of DocumentCollection Returns : Promise.<{data, meta, skip, bookmark, next}> - The JSON API conformant response. Throws : FetchError Param Type Default Description options object The fetch options: pagination & fetch of specific docs. [options.limit] number 100 Pagination limit [options.skip] number 0 Pagination Skip [options.bookmark] string Pagination bookmark [options.keys] Array. Keys to query documentCollection.fetchDocumentsWithMango(path, selector, options) \u00b6 Fetch Documents with Mango Kind : instance method of DocumentCollection Param Type Description path string path to fetch selector MangoSelector selector options MangoQueryOptions request options documentCollection.findWithMango(path, selector, options) \u21d2 Promise. \u00b6 Find documents with the mango selector and create index if missing. We adopt an optimistic approach for index creation: we run the query first, and only if an index missing error is returned, the index is created and the query run again. Kind : instance method of DocumentCollection Returns : Promise. - - The find response Access : protected Param Type Description path string The route path selector MangoSelector The mango selector options MangoQueryOptions The find options documentCollection.find(selector, options) \u21d2 Promise.<{data, skip, bookmark, next, execution_stats}> \u00b6 Returns a filtered list of documents using a Mango selector. The returned documents are paginated by the stack. Kind : instance method of DocumentCollection Returns : Promise.<{data, skip, bookmark, next, execution_stats}> - The JSON API conformant response. Throws : FetchError Param Type Description selector MangoSelector The Mango selector. options MangoQueryOptions MangoQueryOptions documentCollection.findAll(selector, options) \u21d2 Promise.> \u00b6 Returns a filtered list with all documents using a Mango selector, automatically fetching more documents if the total of documents is superior to the pagination limit. Can result in a lot of network requests. The returned documents are paginated by the stack. Kind : instance method of DocumentCollection Returns : Promise.> - Documents fetched Throws : FetchError Param Type Description selector MangoSelector The Mango selector. options MangoQueryOptions MangoQueryOptions documentCollection.get(id) \u21d2 Promise. \u00b6 Get a document by id Kind : instance method of DocumentCollection Returns : Promise. - JsonAPI response containing normalized document as data attribute Param Type Description id string The document id. documentCollection.getAll() \u00b6 Get many documents by id Kind : instance method of DocumentCollection documentCollection.create(doc) \u00b6 Creates a document Kind : instance method of DocumentCollection Param Type Description doc object Document to create. Optional: you can force the id with the _id attribute documentCollection.update(document) \u00b6 Updates a document Kind : instance method of DocumentCollection Param Type Description document object Document to update. Do not forget the _id attribute documentCollection.destroy(doc) \u00b6 Destroys a document Kind : instance method of DocumentCollection Param Type Description doc object Document to destroy. Do not forget _id and _rev attributes documentCollection.updateAll(rawDocs) \u00b6 Updates several documents in one batch Kind : instance method of DocumentCollection Param Type Description rawDocs Array. Documents to be updated documentCollection.destroyAll(docs) \u00b6 Deletes several documents in one batch Kind : instance method of DocumentCollection Param Type Description docs Array. Documents to delete documentCollection.toMangoOptions(selector, options) \u21d2 MangoQueryOptions \u00b6 Returns Mango Options from Selector and Options Kind : instance method of DocumentCollection Returns : MangoQueryOptions - Mango options Param Type Description selector MangoSelector Mango selector options MangoQueryOptions Mango Options documentCollection.createIndex(fields, indexOption) \u21d2 Promise.<{id, fields}> \u00b6 Kind : instance method of DocumentCollection Param Type Description fields Array Fields to index indexOption object Options for the index [indexOption.partialFilter] MangoPartialFilter partialFilter [indexOption.indexName] string indexName documentCollection.fetchAllMangoIndexes() \u21d2 Promise.> \u00b6 Retrieve all design docs of mango indexes Kind : instance method of DocumentCollection Returns : Promise.> - The design docs documentCollection.destroyIndex(index) \u21d2 Promise. \u00b6 Delete the specified design doc Kind : instance method of DocumentCollection Returns : Promise. - The delete response Param Type Description index DesignDoc The design doc to remove documentCollection.copyIndex(existingIndex, newIndexName) \u21d2 Promise. \u00b6 Copy an existing design doc. This is useful to create a new design doc without having to recompute the existing index. Kind : instance method of DocumentCollection Returns : Promise. - The copy response Param Type Description existingIndex DesignDoc The design doc to copy newIndexName string The name of the copy documentCollection.fetchChangesRaw(couchOptions) \u00b6 Calls _changes route from CouchDB No further treatment is done contrary to fetchchanges Kind : instance method of DocumentCollection See : https://docs.couchdb.org/en/stable/api/database/changes.html Param Type Description couchOptions object Couch options for changes https://kutt.it/5r7MNQ [couchOptions.since] string Bookmark telling CouchDB from which point in time should changes be returned [couchOptions.doc_ids] Array. Only return changes for a subset of documents [couchOptions.includeDocs] boolean Includes full documents as part of results [couchOptions.filter] string Filter DocumentCollection.normalizeDoctype(doctype) \u21d2 function \u00b6 Provides a callback for Collection.get Kind : static method of DocumentCollection Returns : function - (data, response) => normalizedDocument using normalizeDoc Param Type Description doctype string Document doctype FileCollection \u00b6 Implements DocumentCollection API along with specific methods for io.cozy.files . Files are a special type of documents and are handled differently by the stack: special routes are to be used, and there is a notion of referenced files, aka files associated to a specific document Kind : global class FileCollection .forceFileDownload .get(id) \u21d2 Object .find(selector, options) \u21d2 Promise.<{data, meta, skip, next, bookmark, execution_stats}> .findReferencedBy(document, options) \u21d2 Promise.<{data, included, meta, skip, next}> .addReferencedBy(document, documents) \u21d2 Promise.<{data, meta}> .removeReferencedBy(document, documents) \u21d2 Promise.<{data, meta}> .addReferencesTo(document, documents) .removeReferencesTo(document, documents) .destroy(file) \u21d2 Promise .emptyTrash() .restore(id) \u21d2 Promise .copy(id, [name], [dirId]) \u21d2 Promise. .deleteFilePermanently(id) \u21d2 Promise. .upload(data, dirPath) \u21d2 Promise. .create(attributes) .updateFile(data, params) \u21d2 object .download(file, versionId, filename) .fetchFileContentById(id) .getBeautifulSize(file, decimal) .downloadArchive(fileIds, [notSecureFilename], [options]) ~~ .getArchiveLinkByIds() ~~ .createArchiveLinkByIds(params) \u21d2 Promise. .isChildOf(child, parent) \u21d2 boolean .statById(id, options) \u21d2 object .createDirectoryByPath(path) \u21d2 object .createFileMetadata(attributes) \u21d2 Promise. .updateMetadataAttribute(id, metadata) \u21d2 Promise. .getFileTypeFromName(name) \u21d2 string .doUpload(dataArg, path, options, method) .findNotSynchronizedDirectories(oauthClient, options) \u21d2 Array.<(object|IOCozyFolder)> .addNotSynchronizedDirectories(oauthClient, directories) .removeNotSynchronizedDirectories(oauthClient, directories) fileCollection.forceFileDownload \u00b6 Force a file download from the given href Kind : instance property of FileCollection Param Type Description href string The link to download filename string The file name to download fileCollection.get(id) \u21d2 Object \u00b6 Fetches the file\u2019s data Kind : instance method of FileCollection Returns : Object - Information about the file or folder and it\u2019s descendents Param Type Description id string File id fileCollection.find(selector, options) \u21d2 Promise.<{data, meta, skip, next, bookmark, execution_stats}> \u00b6 Returns a filtered list of documents using a Mango selector. The returned documents are paginated by the stack. Kind : instance method of FileCollection Returns : Promise.<{data, meta, skip, next, bookmark, execution_stats}> - The JSON API conformant response. Throws : FetchError Param Type Description selector object The Mango selector. options MangoQueryOptions The query options fileCollection.findReferencedBy(document, options) \u21d2 Promise.<{data, included, meta, skip, next}> \u00b6 async findReferencedBy - Returns the list of files referenced by a document \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/ Kind : instance method of FileCollection Returns : Promise.<{data, included, meta, skip, next}> - The JSON API conformant response. Param Type Description document object A JSON representing a document, with at least a _type and _id field. options object Additional options [options.skip] number | null For skip-based pagination, the number of referenced files to skip. [options.limit] number | null For pagination, the number of results to return. [options.cursor] CouchDBViewCursor | null For cursor-based pagination, the index cursor. fileCollection.addReferencedBy(document, documents) \u21d2 Promise.<{data, meta}> \u00b6 Add referenced_by documents to a file \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#post-filesfile-idrelationshipsreferenced_by For example, to have an album referenced by a file: addReferencedBy({_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}, [{_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}]) Kind : instance method of FileCollection Returns : Promise.<{data, meta}> - The JSON API conformant response. Param Type Description document FileDocument A JSON representing the file documents Array An array of JSON documents having a _type and _id field. fileCollection.removeReferencedBy(document, documents) \u21d2 Promise.<{data, meta}> \u00b6 Remove referenced_by documents from a file \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#delete-filesfile-idrelationshipsreferenced_by For example, to remove an album reference from a file: removeReferencedBy({_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}, [{_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}]) Kind : instance method of FileCollection Returns : Promise.<{data, meta}> - The JSON API conformant response. Param Type Description document object A JSON representing the file documents Array An array of JSON documents having a _type and _id field. fileCollection.addReferencesTo(document, documents) \u00b6 Add files references to a document \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#post-datatypedoc-idrelationshipsreferences For example, to add a photo to an album: addReferencesTo({_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}, [{_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}]) Kind : instance method of FileCollection Param Type Description document object A JSON representing a document, with at least a _type and _id field. documents Array An array of JSON files having an _id field. Returns 204 No Content fileCollection.removeReferencesTo(document, documents) \u00b6 Remove files references to a document \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#delete-datatypedoc-idrelationshipsreferences For example, to remove a photo from an album: removeReferencesTo({_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}, [{_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}]) Kind : instance method of FileCollection Param Type Description document object A JSON representing a document, with at least a _type and _id field. documents Array An array of JSON files having an _id field. Returns 204 No Content fileCollection.destroy(file) \u21d2 Promise \u00b6 Sends file to trash and removes references to it Kind : instance method of FileCollection Returns : Promise - - Resolves when references have been removed and file has been sent to trash Param Type Description file FileDocument File that will be sent to trash fileCollection.emptyTrash() \u00b6 Empty the Trash Kind : instance method of FileCollection fileCollection.restore(id) \u21d2 Promise \u00b6 Restores a trashed file. Kind : instance method of FileCollection Returns : Promise - - A promise that returns the restored file if resolved. Throws : FetchError Param Type Description id string The file\u2019s id fileCollection.copy(id, [name], [dirId]) \u21d2 Promise. \u00b6 Copy a file. Kind : instance method of FileCollection Returns : Promise. - - A promise that returns the copied file if resolved. Throws : FetchError Param Type Description id string The file\u2019s id [name] string The file copy name [dirId] string The destination directory id fileCollection.deleteFilePermanently(id) \u21d2 Promise. \u00b6 async deleteFilePermanently - Definitely delete a file Kind : instance method of FileCollection Returns : Promise. - The deleted file object Param Type Description id string The id of the file to delete fileCollection.upload(data, dirPath) \u21d2 Promise. \u00b6 Kind : instance method of FileCollection Returns : Promise. - Created io.cozy.files Param Type Description data File | Blob | Stream | string | ArrayBuffer file to be uploaded dirPath string Path to upload the file to. ie : /Administative/XXX/ fileCollection.create(attributes) \u00b6 Creates directory or file. - Used by StackLink to support CozyClient.create(\u2018io.cozy.files\u2019, options) Kind : instance method of FileCollection Throws : Error - explaining reason why creation failed Param Type Description attributes FileAttributes | DirectoryAttributes Attributes of the created file/directory attributes.data File | Blob | string | ArrayBuffer Will be used as content of the created file fileCollection.updateFile(data, params) \u21d2 object \u00b6 updateFile - Updates a file\u2019s data Kind : instance method of FileCollection Returns : object - Updated document Throws : Error - explaining reason why update failed Param Type Description data File | Blob | Stream | string | ArrayBuffer file to be uploaded params FileAttributes Additional parameters params.options object Options to pass to doUpload method (additional headers) fileCollection.download(file, versionId, filename) \u00b6 Download a file or a specific version of the file Kind : instance method of FileCollection Param Type Default Description file object io.cozy.files object versionId string null Id of the io.cozy.files.version filename string The name you want for the downloaded file (by default the same as the file) fileCollection.fetchFileContentById(id) \u00b6 Fetch the binary of a file or a specific version of a file Useful for instance when you can\u2019t download the file directly (via a content-disposition attachement header) and need to store it before doing an operation. Kind : instance method of FileCollection Param Type Description id string Id of the io.cozy.files or io.cozy.files.version fileCollection.getBeautifulSize(file, decimal) \u00b6 Get a beautified size for a given file 1024B => 1KB 102404500404B => 95.37 GB Kind : instance method of FileCollection Param Type Description file object io.cozy.files object decimal number number of decimal fileCollection.downloadArchive(fileIds, [notSecureFilename], [options]) \u00b6 Download an archive of the files Kind : instance method of FileCollection Param Type Description fileIds Array. List of file ids [notSecureFilename] string Name of the archive (default: \u2018files\u2019) [options] object Additional options [options.pages] Array. Array of objects, with id the file identifier, and page the page number (1 is the first page) ~~fileCollection.getArchiveLinkByIds()~~ \u00b6 Deprecated Kind : instance method of FileCollection fileCollection.createArchiveLinkByIds(params) \u21d2 Promise. \u00b6 Create the archive link for a list of files The generated archive is temporary and is not persisted Kind : instance method of FileCollection Returns : Promise. - - The archive link Param Type Description params object Parameters params.ids Array. List of file ids [params.name] string Name of the archive (default: \u2018files\u2019) [params.pages] Array. Array of objects, with id the file identifier, and page the page number (1 is the first page) fileCollection.isChildOf(child, parent) \u21d2 boolean \u00b6 Checks if the file belongs to the parent\u2019s hierarchy. Kind : instance method of FileCollection Returns : boolean - Whether the file is a parent\u2019s child Param Type Description child string | object The file which can either be an id or an object parent string | object The parent target which can either be an id or an object fileCollection.statById(id, options) \u21d2 object \u00b6 statById - Fetches the metadata about a document. For folders, the results include the list of child files and folders. Kind : instance method of FileCollection Returns : object - A promise resolving to an object containing \u201cdata\u201d (the document metadata), \u201cincluded\u201d (the child documents) and \u201clinks\u201d (pagination informations) Param Type Description id string ID of the document options object | null Pagination options [options.page[limit]] number | null For pagination, the number of results to return. [options.page[skip]] number | null For skip-based pagination, the number of referenced files to skip. [options.page[cursor]] CouchDBViewCursor | null For cursor-based pagination, the index cursor. fileCollection.createDirectoryByPath(path) \u21d2 object \u00b6 async createDirectoryByPath - Creates one or more folders until the given path exists Kind : instance method of FileCollection Returns : object - The document corresponding to the last segment of the path Param Type Description path string Path of the created directory fileCollection.createFileMetadata(attributes) \u21d2 Promise. \u00b6 Send a metadata object that can be associated to a file uploaded after that, via the MetadataID query parameter. See https://github.com/cozy/cozy-stack/blob/master/docs/files.md#post-filesuploadmetadata Kind : instance method of FileCollection Returns : Promise. - The Metadata object Param Type Description attributes object The file\u2019s metadata fileCollection.updateMetadataAttribute(id, metadata) \u21d2 Promise. \u00b6 Updates the metadata attribute of a io.cozy.files Creates a new version of the file without having to upload again the file\u2019s content To see available content of the metadata attribute see : https://docs.cozy.io/en/cozy-doctypes/docs/io.cozy.files_metadata/ Kind : instance method of FileCollection Returns : Promise. - io.cozy.files updated Param Type Description id string File id metadata object io.cozy.files.metadata attributes fileCollection.getFileTypeFromName(name) \u21d2 string \u00b6 Get the file mime-type based on its name Kind : instance method of FileCollection Returns : string - the inferred file mime-type Param Type Description name string The file name fileCollection.doUpload(dataArg, path, options, method) \u00b6 This method should not be called directly to upload a file. You should use createFile Kind : instance method of FileCollection Param Type Default Description dataArg File | Blob | Stream | string | ArrayBuffer file to be uploaded path string Uri to call the stack from. Something like /files/${dirId}?Name=${name}&Type=file&Executable=${executable}&MetadataID=${metadataId} options object Additional headers method string \"POST\" POST / PUT / PATCH fileCollection.findNotSynchronizedDirectories(oauthClient, options) \u21d2 Array.<(object|IOCozyFolder)> \u00b6 async findNotSynchronizedDirectories - Returns the list of directories not synchronized on the given OAuth client (mainly Cozy Desktop clients) \u2014 see https://docs.cozy.io/en/cozy-stack/not-synchronized-vfs/#get-datatypedoc-idrelationshipsnot_synchronizing Kind : instance method of FileCollection Returns : Array.<(object|IOCozyFolder)> - The JSON API conformant response. Param Type Description oauthClient OAuthClient A JSON representing an OAuth client, with at least a _type and _id field. options object | null Pagination options options.skip number | null For skip-based pagination, the number of referenced files to skip. options.limit number | null For pagination, the number of results to return. options.cursor CouchDBViewCursor | null For cursor-based pagination, the index cursor. options.includeFiles boolean Include the whole file documents in the results list fileCollection.addNotSynchronizedDirectories(oauthClient, directories) \u00b6 Add directory synchronization exclusions to an OAuth client \u2014 see https://docs.cozy.io/en/cozy-stack/not-synchronized-vfs/#post-datatypedoc-idrelationshipsnot_synchronizing For example, to exclude directory /Photos from My Computer \u2018s desktop synchronization: addNotSynchronizedDirectories({_id: 123, _type: \"io.cozy.oauth.clients\", clientName: \"Cozy Drive (My Computer)\", clientKind: \"desktop\"}, [{_id: 456, _type: \"io.cozy.files\", name: \"Photos\", path: \"/Photos\"}]) Kind : instance method of FileCollection Param Type Description oauthClient OAuthClient A JSON representing the OAuth client directories Array An array of JSON documents having a _type and _id fields and representing directories. Returns 204 No Content fileCollection.removeNotSynchronizedDirectories(oauthClient, directories) \u00b6 Remove directory synchronization exclusions from an OAuth client \u2014 see https://docs.cozy.io/en/cozy-stack/not-synchronized-vfs/#delete-datatypedoc-idrelationshipsnot_synchronizing For example, to re-include directory /Photos into My Computer \u2018s desktop synchronization: removeNotSynchronizedDirectories({_id: 123, _type: \"io.cozy.oauth.clients\", clientName: \"Cozy Drive (My Computer)\", clientKind: \"desktop\"}, [{_id: 456, _type: \"io.cozy.files\", name: \"Photos\", path: \"/Photos\"}]) Kind : instance method of FileCollection Param Type Description oauthClient OAuthClient A JSON representing the OAuth client directories Array An array of JSON documents having a _type and _id field and representing directories. Returns 204 No Content NotesCollection \u00b6 Implements DocumentCollection API to interact with the /notes endpoint of the stack Kind : global class NotesCollection .get(id) \u21d2 Object .all() \u21d2 Object .destroy(note) \u21d2 Object .create(options) \u21d2 Object .fetchURL(note) \u21d2 Object .getDefaultSchema() \u21d2 object notesCollection.get(id) \u21d2 Object \u00b6 Fetches the note data Kind : instance method of NotesCollection Returns : Object - Information about the note Param Type Description id string Note id notesCollection.all() \u21d2 Object \u00b6 Fetches all notes Kind : instance method of NotesCollection Returns : Object - The JSON API conformant response. notesCollection.destroy(note) \u21d2 Object \u00b6 Destroys the note on the server Kind : instance method of NotesCollection Returns : Object - The deleted note Param Type Description note object The io.cozy.notes document to destroy [note._id] string The note\u2019s id notesCollection.create(options) \u21d2 Object \u00b6 Create a note Kind : instance method of NotesCollection Returns : Object - The JSON API conformant response. Param Type Description options object Options [options.dir_id] string dir_id where to create the note notesCollection.fetchURL(note) \u21d2 Object \u00b6 Returns the details to build the note\u2019s url Kind : instance method of NotesCollection Returns : Object - The note\u2019s url details See : https://github.com/cozy/cozy-stack/blob/master/docs/notes.md#get-notesidopen Param Type Description note object The io.cozy.notes document to open [note._id] string The note\u2019s id notesCollection.getDefaultSchema() \u21d2 object \u00b6 Returns promise mirror schema for a note Kind : instance method of NotesCollection Returns : object - schema OAuthClient \u00b6 Specialized CozyStackClient for mobile, implementing stack registration through OAuth. Kind : global class OAuthClient .doRegistration() .register() \u21d2 Promise .unregister() \u21d2 Promise .fetchInformation() \u21d2 Promise .updateInformation(information, resetSecret) \u21d2 Promise .generateStateCode() \u21d2 string .getAuthCodeURL(options) \u21d2 string .getAccessCodeFromURL(pageURL, stateCode) \u21d2 string .fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise .fetchKonnectorToken(slug) \u21d2 Promise. .fetchSessionCode() \u21d2 Promise. .fetchSessionCodeWithPassword() \u21d2 Promise. .loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> .refreshToken() \u21d2 Promise .setToken(token) .setOAuthOptions(options) .resetClient() .setPassphraseFlagship(params) \u21d2 object .checkForRevocation() \u21d2 Promise. oAuthClient.doRegistration() \u00b6 Performs the HTTP call to register the client to the server Kind : instance method of OAuthClient oAuthClient.register() \u21d2 Promise \u00b6 Registers the currenly configured client with the OAuth server and sets internal information from the server response Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a complete list of client information, including client ID and client secret. Throws : Error When the client is already registered oAuthClient.unregister() \u21d2 Promise \u00b6 Unregisters the currenly configured client with the OAuth server. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information oAuthClient.fetchInformation() \u21d2 Promise \u00b6 Fetches the complete set of client information from the server after it has been registered. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information oAuthClient.updateInformation(information, resetSecret) \u21d2 Promise \u00b6 Overwrites the client own information. This method will update both the local information and the remote information on the OAuth server. Kind : instance method of OAuthClient Returns : Promise - Resolves to a complete, updated list of client information Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Default Description information object Set of information to update. Note that some fields such as clientID can\u2019t be updated. resetSecret boolean false = false Optionnal, whether to reset the client secret or not oAuthClient.generateStateCode() \u21d2 string \u00b6 Generates a random state code to be used during the OAuth process Kind : instance method of OAuthClient oAuthClient.getAuthCodeURL(options) \u21d2 string \u00b6 Generates the URL that the user should be sent to in order to accept the app\u2019s permissions. Kind : instance method of OAuthClient Returns : string - The URL Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description options object URL generation options options.stateCode string A random code to be included in the URl for security. Can be generated with client.generateStateCode() [options.scopes] Array An array of permission scopes for the token. [options.sessionCode] SessionCode A session code that can be used to create a session. [options.codeChallenge] string A code challenge that can be used in a PKCE verification process. oAuthClient.getAccessCodeFromURL(pageURL, stateCode) \u21d2 string \u00b6 Retrieves the access code contained in the URL to which the user is redirected after accepting the app\u2019s permissions (the redirectURI ). Kind : instance method of OAuthClient Returns : string - The access code Throws : Error The URL should contain the same state code as the one generated with client.getAuthCodeURL() . If not, it will throw an error Param Type Description pageURL string The redirected page URL, containing the state code and the access code stateCode string The state code that was contained in the original URL the user was sent to (see client.getAuthCodeURL() ) oAuthClient.fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise \u00b6 Exchanges an access code for an access token. This function does not update the client\u2019s token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with an AccessToken object. Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description accessCode string The access code contained in the redirection URL \u2014 see client.getAccessCodeFromURL() oauthOptionsArg object \u2014 To use when OAuthClient is not yet registered (during login process) uri string \u2014 To use when OAuthClient is not yet registered (during login process) codeVerifier string \u2014 The PKCE code verifier (see https://docs.cozy.io/en/cozy-stack/auth/#pkce-extension) oAuthClient.fetchKonnectorToken(slug) \u21d2 Promise. \u00b6 Used by the flagship application in order to create a token for the konnector with the given slug. This token can then be used by the client-side konnector to make requests to cozy-stack. The flagship app will need to use its own access token to request the konnector token. Kind : instance method of OAuthClient Returns : Promise. - - A promise that resolves with a new token Param Type Description slug string The slug of the konnector oAuthClient.fetchSessionCode() \u21d2 Promise. \u00b6 Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application oAuthClient.fetchSessionCodeWithPassword() \u21d2 Promise. \u00b6 Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application oAuthClient.loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> \u00b6 Get OAuth access and register tokens without having to make OAuth dance This endpoint returns registration tokens only from a Flagship app, otherwise it returns a session_code that should be used in an OAuth dance More info: https://docs.cozy.io/en/cozy-stack/flagship/ More info: https://docs.cozy.io/en/cozy-stack/auth/#post-authloginflagship Kind : instance method of OAuthClient Returns : Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> - A promise that resolves with an access token, a session_code or a 2FA code oAuthClient.refreshToken() \u21d2 Promise \u00b6 Retrieves a new access token by refreshing the currently used token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Error The client should already have an access token to use this function oAuthClient.setToken(token) \u00b6 Updates the client\u2019s stored token Kind : instance method of OAuthClient Param Type Description token string = null The new token to use \u2014 can be a string, a json object or an AccessToken instance. oAuthClient.setOAuthOptions(options) \u00b6 Updates the OAuth informations Kind : instance method of OAuthClient Param Type Description options object Map of OAuth options oAuthClient.resetClient() \u00b6 Reset the current OAuth client Kind : instance method of OAuthClient oAuthClient.setPassphraseFlagship(params) \u21d2 object \u00b6 This method should be used in flagship app onboarding process to finalize the cozy creation by setting the user password into the cozy-stack More info: https://docs.cozy.io/en/cozy-stack/settings/#post-settingspassphraseflagship Kind : instance method of OAuthClient Returns : object - token - The OAauth token Param Type Description params object parameters needed to set passphrase params.registerToken string registration token provided by the onboarding link params.passwordHash string hash of the master password params.hint string hint for the master password params.key string key (crypted) used for the vault encryption params.publicKey string public key used for sharing ciphers from the vault params.privateKey string private key (crypted) used for sharing ciphers from the vault params.iterations string number of KDF iterations applied when hashing the master password oAuthClient.checkForRevocation() \u21d2 Promise. \u00b6 Check if the OAuth client\u2019s has been revoked. If this is the case, call the onRevocationChange callback Kind : instance method of OAuthClient Returns : Promise. - A Promise that resolves to false if client is still valid, or true if it has been revoked. OAuthClientsCollection \u00b6 Implements DocumentCollection API to interact with the /settings/clients endpoint of the stack Kind : global class OAuthClientsCollection .all(options) \u21d2 object .get(id) \u21d2 object .destroy(oauthClient) \u21d2 Object oAuthClientsCollection.all(options) \u21d2 object \u00b6 Fetches all OAuth clients Kind : instance method of OAuthClientsCollection Returns : object - The JSON API conformant response. Param Type Description options object Query options [options.limit] number For pagination, the number of results to return. [options.bookmark] string For bookmark-based pagination, the document _id to start from [options.keys] Array. Ids of specific clients to return (within the current page), oAuthClientsCollection.get(id) \u21d2 object \u00b6 Get an OAuth client by id Kind : instance method of OAuthClientsCollection Returns : object - JsonAPI response containing normalized client as data attribute Param Type Description id string The client id. oAuthClientsCollection.destroy(oauthClient) \u21d2 Object \u00b6 Destroys the OAuth client on the server Kind : instance method of OAuthClientsCollection Returns : Object - The deleted client Param Type Description oauthClient object The io.cozy.oauth.clients document to destroy PermissionCollection \u00b6 Implements DocumentCollection API along with specific methods for io.cozy.permissions . Kind : global class PermissionCollection .create(permission) .add(document, permission) \u21d2 Promise ~~ .findApps() ~~ .createSharingLink(document, options) .fetchPermissionsByLink(permissions) .fetchAllLinks(document) \u21d2 object .revokeSharingLink(document) permissionCollection.create(permission) \u00b6 Create a new set of permissions It can also associates one or more codes to it, via the codes parameter Kind : instance method of PermissionCollection See : https://docs.cozy.io/en/cozy-stack/permissions/#post-permissions Param Type Description permission object permission to create permission.codes string A comma separed list of values (defaulted to code) permission.ttl string Make the codes expire after a delay (bigduration format) permission.tiny boolean If set to true then the generated shortcode will be 6 digits Cozy-Stack has a few conditions to be able to use this tiny shortcode ATM you have to specifiy a ttl < 1h, but it can change. see https://docs.cozy.io/en/cozy-stack/permissions/#post-permissions for exact informations bigduration format: https://github.com/justincampbell/bigduration/blob/master/README.md permissionCollection.add(document, permission) \u21d2 Promise \u00b6 Adds a permission to the given document. Document type must be io.cozy.apps , io.cozy.konnectors or io.cozy.permissions Kind : instance method of PermissionCollection Param Type Description document object Document which receives the permission permission object Describes the permission Example const permissions = await client .collection('io.cozy.permissions') .add(konnector, { folder: { type: 'io.cozy.files', verbs: ['GET', 'PUT'], values: [`io.cozy.files.bc57b60eb2954537b0dcdc6ebd8e9d23`] } }) ~~permissionCollection.findApps()~~ \u00b6 Deprecated Kind : instance method of PermissionCollection permissionCollection.createSharingLink(document, options) \u00b6 Create a share link Kind : instance method of PermissionCollection Param Type Description document Object cozy document options object options options.verbs Array. explicit permissions to use permissionCollection.fetchPermissionsByLink(permissions) \u00b6 Follow the next link to fetch the next permissions Kind : instance method of PermissionCollection Param Type Description permissions object JSON-API based permissions document permissionCollection.fetchAllLinks(document) \u21d2 object \u00b6 Kind : instance method of PermissionCollection Returns : object - with all the permissions Param Type Description document object Cozy doc permissionCollection.revokeSharingLink(document) \u00b6 Destroy a sharing link and the related permissions Kind : instance method of PermissionCollection Param Type Description document object document to revoke sharing link PromiseCache \u00b6 Caches promises while they are pending Serves to dedupe equal queries requested at the same time Kind : global class PromiseCache .pending : Object. .exec(promiseFunc, keyFunc) \u21d2 Promise. .get(keyFunc) \u21d2 Promise | null promiseCache.pending : Object. \u00b6 Holds pending promises Kind : instance property of PromiseCache promiseCache.exec(promiseFunc, keyFunc) \u21d2 Promise. \u00b6 Tries to find a pending promise corresponding to the result of keyFunc - If not found, promiseFunc is executed and the resulting promise is stored while it\u2019s pending - If found, it is immediately returned Kind : instance method of PromiseCache Param Type Description promiseFunc function Not executed only if an \u201cequal\u201d promise is already pending. keyFunc function Returns a key to find in cache to find a pending promise. promiseCache.get(keyFunc) \u21d2 Promise | null \u00b6 Kind : instance method of PromiseCache Param Type Description keyFunc function Returns a key to find in cache to find a pending promise. SettingsCollection \u00b6 Implements DocumentCollection API to interact with the /settings endpoint of the stack Kind : global class SettingsCollection .get(id) \u21d2 object .update(document) settingsCollection.get(id) \u21d2 object \u00b6 async get - Calls a route on the /settings API Kind : instance method of SettingsCollection Returns : object - The response from the route Param Type Description id string The setting id to call, eg io.cozy.settings.instance for instance route or io.cozy.settings.context for context route settingsCollection.update(document) \u00b6 Updates a settings document Kind : instance method of SettingsCollection Param Type Description document object Document to update. Do not forget the _id attribute SharingCollection \u00b6 Implements the DocumentCollection API along with specific methods for io.cozy.sharings . Kind : global class SharingCollection .get(id) \u21d2 Sharing .create(params) ~~ .share(document, recipients, sharingType, description, [previewPath]) ~~ .getDiscoveryLink(sharingId, sharecode) \u21d2 string .addRecipients(options) .revokeRecipient(sharing, recipientIndex) .revokeGroup(sharing, groupIndex) .revokeSelf(sharing) .revokeAllRecipients(sharing) sharingCollection.get(id) \u21d2 Sharing \u00b6 Fetches a sharing by id Kind : instance method of SharingCollection Returns : Sharing - sharing Param Type Description id string Sharing\u2019s id sharingCollection.create(params) \u00b6 Creates a new Sharing. See https://docs.cozy.io/en/cozy-stack/sharing/#post-sharings Kind : instance method of SharingCollection Param Type Description params object Sharing params params.document Sharing The document to share params.description string Description of the sharing [params.previewPath] string The preview path [params.rules] Array. The rules defined to the sharing. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing [params.recipients] Array. Recipients to add to the sharings (will have the same permissions given by the rules defined by the sharing ) [params.readOnlyRecipients] Array. Recipients to add to the sharings with only read only access [params.openSharing] boolean If someone else than the owner can add a recipient to the sharing [params.appSlug] string Slug of the targeted app ~~sharingCollection.share(document, recipients, sharingType, description, [previewPath])~~ \u00b6 Deprecated Kind : instance method of SharingCollection Param Type Default Description document Sharing The document to share. Should have and _id and a name. recipients Array A list of io.cozy.contacts sharingType string If \u201ctwo-way\u201d, will set the open_sharing attribute to true description string Describes the sharing [previewPath] string null Relative URL of the sharings preview page sharingCollection.getDiscoveryLink(sharingId, sharecode) \u21d2 string \u00b6 getDiscoveryLink - Returns the URL of the page that can be used to accept a sharing. See https://docs.cozy.io/en/cozy-stack/sharing/#get-sharingssharing-iddiscovery Kind : instance method of SharingCollection Param Type Description sharingId string Id of the sharing sharecode string Code of the sharing sharingCollection.addRecipients(options) \u00b6 Add an array of contacts to the Sharing Kind : instance method of SharingCollection Param Type Description options object Object options.document Sharing Sharing Object [options.recipients] Array. Recipients to add to the sharing [options.readOnlyRecipients] Array. Recipients to add to the sharings with only read only access sharingCollection.revokeRecipient(sharing, recipientIndex) \u00b6 Revoke only one recipient of the sharing. Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Object recipientIndex number Index of this recipient in the members array of the sharing sharingCollection.revokeGroup(sharing, groupIndex) \u00b6 Revoke only one group of the sharing. Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Object groupIndex number Index of this group in the groups array of the sharing sharingCollection.revokeSelf(sharing) \u00b6 Remove self from the sharing. Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Object sharingCollection.revokeAllRecipients(sharing) \u00b6 Revoke the sharing for all the members. Must be called from the owner\u2019s cozy Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Objects TriggerCollection \u00b6 Implements DocumentCollection API along with specific methods for io.cozy.triggers . Kind : global class TriggerCollection .all(options) \u21d2 Object .create(attributes) \u21d2 object .destroy(document) \u21d2 object .find(selector, options) \u21d2 Object .launch(trigger) \u21d2 object .update(trigger) \u21d2 object triggerCollection.all(options) \u21d2 Object \u00b6 Get the list of triggers. Kind : instance method of TriggerCollection Returns : Object - The JSON API conformant response. Throws : FetchError See : https://docs.cozy.io/en/cozy-stack/jobs/#get-jobstriggers Param Type Description options Object The fetch options: Worker allow to filter only triggers associated with a specific worker. triggerCollection.create(attributes) \u21d2 object \u00b6 Creates a Trigger document Kind : instance method of TriggerCollection Returns : object - Stack response, containing trigger document under data attribute. See : https://docs.cozy.io/en/cozy-stack/jobs/#post-jobstriggers Param Type Description attributes object Trigger\u2019s attributes triggerCollection.destroy(document) \u21d2 object \u00b6 Deletes a trigger Kind : instance method of TriggerCollection Returns : object - The deleted document See : https://docs.cozy.io/en/cozy-stack/jobs/#delete-jobstriggerstrigger-id Param Type Description document object The trigger to delete \u2014 must have an _id field triggerCollection.find(selector, options) \u21d2 Object \u00b6 Be warned, ATM /jobs/triggers does not return the same informations than /data/io.cozy.triggers (used by the super.find method). See https://github.com/cozy/cozy-stack/pull/2010 Kind : instance method of TriggerCollection Returns : Object - The JSON API conformant response. Throws : FetchError Param Type Description selector object Which kind of worker options object Options triggerCollection.launch(trigger) \u21d2 object \u00b6 Force given trigger execution. Kind : instance method of TriggerCollection Returns : object - Stack response, containing job launched by trigger, under data attribute. See : https://docs.cozy.io/en/cozy-stack/jobs/#post-jobstriggerstrigger-idlaunch Param Type Description trigger object Trigger to launch triggerCollection.update(trigger) \u21d2 object \u00b6 Updates a Trigger document. Only updatable attributes plus _id are allowed. Kind : instance method of TriggerCollection Returns : object - Stack response, containing resulting trigger document under data attribute. Param Type Description trigger object Trigger\u2019s attributes to update + id dontThrowNotFoundError \u21d2 object \u00b6 Handler for error response which return a empty value for \u201cnot found\u201d error Kind : global constant Returns : object - JsonAPI response with empty data in case of \u201cnot found\u201d error. Param Type Description error Error An error data Array | object | null Data to return in case of \u201cnot found\u201d error isIndexNotFoundError \u21d2 Array | null \u00b6 Helper to identify an index not found error Kind : global constant Returns : Array | null - - Whether or not the error is an index not found error Param Type Description error Error An error isIndexConflictError \u21d2 Array | null \u00b6 Helper to identify an index conflict Kind : global constant Returns : Array | null - - Whether or not the error is an index conflict error Param Type Description error Error An error isIndexNotUsedWarning \u21d2 Array | null \u00b6 Helper to identify a not used index Kind : global constant Returns : Array | null - Whether or not this is a not used index warning Param Type Description warning string The warning returned by CouchDB isNoUsableIndexError \u21d2 Array | null \u00b6 Helper to identify a no usable index error Kind : global constant Returns : Array | null - - Whether or not the error is a no usable index error Param Type Description error Error An error isDocumentUpdateConflict \u21d2 Array | null \u00b6 Helper to identify a document conflict Kind : global constant Returns : Array | null - - Whether or not the error is a document conflict error Param Type Description error Error An error isFile \u21d2 boolean \u00b6 Returns true when parameter has type directory, file or has _type io.cozy.files Kind : global constant Returns : boolean - true when objects has type directory, file or has _type io.cozy.files or false Param Type Description doc object The document whose type is checked [doc._type] string The document\u2019s doctype [doc.type] 'directory' | 'file' The io.cozy-files document type isDirectory \u21d2 boolean \u00b6 Returns true when parameters has type directory Kind : global constant Returns : boolean - true when parameters has type directory or false Param Type Description args object File args.type string The type of the file getIllegalCharacters \u21d2 string \u00b6 Get the list of illegal characters in the file name Kind : global constant Returns : string - illegal characters separated by spaces Access : public Param Type Description name string the file name makeKeyFromPartialFilter \u21d2 string \u00b6 Process a partial filter to generate a string key Kind : global constant Returns : string - - The string key of the processed partial filter Param Type Description condition object An object representing the partial filter or a sub-condition of the partial filter getIndexNameFromFields \u21d2 string \u00b6 Name an index, based on its indexed fields and partial filter. It follows this naming convention: by_{indexed_field1}_and_{indexed_field2}_filter_({partial_filter.key1}_{partial_filter.value1})_and_({partial_filter.key2}_{partial_filter.value2}) Kind : global constant Returns : string - The index name, built from the fields Param Type Description fields Array. The indexed fields [partialFilter] object The partial filter transformSort \u21d2 MangoSort \u00b6 Transform sort into Array Kind : global constant Param Type Description sort MangoSort The sorting parameters getIndexFields \u21d2 Array \u00b6 Compute fields that should be indexed for a mango query to work Kind : global constant Returns : Array - - Fields to index isMatchingIndex \u21d2 boolean \u00b6 Check if an index is matching the given fields Kind : global constant Returns : boolean - True if the index is matches the given fields Param Type Description index DesignDoc The index to check fields Array The fields that the index must have partialFilter object An optional partial filter makeOperatorsExplicit \u21d2 object \u00b6 Transform a query to make all operators explicit Kind : global constant Returns : object - - The transformed query with all operators explicit Param Type Description query object The query to transform reverseEq boolean If true, $eq will be transformed to $ne (useful for manage $nor) getPermissionsFor \u21d2 object \u00b6 Build a permission set Kind : global constant Returns : object - permissions object that can be sent through /permissions/* Param Type Description document Object cozy document publicLink boolean are the permissions for a public link ? options object options options.verbs Array. explicit permissions to use normalizeSettings \u21d2 object \u00b6 Normalizing a document for SettingsCollection context Kind : global constant Returns : object - normalized document Param Type Description doc object Document to normalize getSharingRules \u21d2 Array. \u00b6 Rules determine the behavior of the sharing when changes are made to the shared document See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global constant Returns : Array. - The rules that define how to share the document Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing forceDownload \u00b6 Force a download from the given href Kind : global constant Param Type Description href string The link to download filename string The file name to download encodePath \u21d2 string \u00b6 Encode a path for use in a URL by encoding special characters but keeping slashes Kind : global constant Returns : string - - The encoded path with special characters for parentheses and spaces Param Type Description path string The path to encode getAccessToken() \u21d2 string \u00b6 Get the access token string Kind : global function Returns : string - token See : CozyStackClient.getAccessToken getAccessToken() \u21d2 string \u00b6 Get the app token string Kind : global function Returns : string - token See : CozyStackClient.getAccessToken getIconURL() \u00b6 Get Icon URL using blob mechanism if OAuth connected or using preloaded url when blob not needed Kind : global function handleNorOperator(conditions) \u21d2 Array \u00b6 Handle the $nor operator in a query CouchDB transforms $nor into $and with $ne operators Kind : global function Returns : Array - - The reversed conditions Param Type Description conditions Array The conditions inside the $nor operator garbageCollect() \u00b6 Delete outdated results from cache Kind : global function memoize() \u00b6 Memoize with maxDuration and custom key Kind : global function getSharingRulesForPhotosAlbum(document, sharingType) \u21d2 Array. \u00b6 Compute the rules that define how to share a Photo Album. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global function Returns : Array. - The rules that define how to share a Photo Album Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing getSharingPolicyForReferencedFiles(sharingType) \u21d2 SharingPolicy \u00b6 Compute the sharing policy for a ReferencedFile based on its sharing type Kind : global function Returns : SharingPolicy - The sharing policy for the ReferencedFile Param Type Description sharingType SharingType The type of the sharing getSharingPolicyForAlbum(sharingType) \u21d2 Array. \u00b6 Compute the sharing policy for an Album based on its sharing type Kind : global function Returns : Array. - The sharing policy for the Album Param Type Description sharingType SharingType The type of the sharing getSharingRulesForFile(document, sharingType) \u21d2 Array. \u00b6 Compute the rules that define how to share a File. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global function Returns : Array. - The rules that define how to share a File Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing getSharingPolicyForFile(document, sharingType) \u21d2 SharingPolicy \u00b6 Compute the sharing policy for a File based on its sharing type Kind : global function Returns : SharingPolicy - The sharing policy for the File Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing getSharingRulesForOrganizations(document) \u21d2 Array. \u00b6 Compute the rules that define how to share an Organization. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global function Returns : Array. - The rules that define how to share an Organization Param Type Description document Sharing The document to share. Should have and _id and a name toRelationshipItem(item) \u21d2 RelationshipItem \u00b6 Compute the RelationshipItem that can be referenced as a sharing recipient Kind : global function Returns : RelationshipItem - The RelationshipItem that can be referenced as a sharing recipient Param Type Description item Recipient The recipient of a sharing getCozyURL() \u00b6 Get a uniform formatted URL and SSL information according to a provided URL Kind : global function joinPath(start, end) \u21d2 string \u00b6 Join two paths together ensuring there is only one slash between them Kind : global function Returns : string - The joined path Param Type Description start string The starting part of the path end string The ending part of the path FetchChangesReturnValue \u21d2 Promise. \u00b6 Use Couch _changes API Deleted and design docs are filtered by default, thus documents are retrieved in the response (include_docs is set to true in the parameters of _changes). You should use fetchChangesRaw to have low level control on _changes parameters. Kind : global typedef Param Type Description couchOptions object Couch options for changes [couchOptions.since] string Bookmark telling CouchDB from which point in time should changes be returned [couchOptions.doc_ids] Array. Only return changes for a subset of documents options object Further options on the returned documents. By default, it is set to [options.includeDesign] boolean Whether to include changes from design docs (needs include_docs to be true) [options.includeDeleted] boolean Whether to include changes for deleted documents (needs include_docs to be true) Properties Name Type newLastSeq string documents Array. IOCozyFolder : object \u00b6 Folder Kind : global typedef SpecificFileAttributesForKonnector : object \u00b6 Specific file attributes for creation for konnector Kind : global typedef Properties Name Type Description sourceAccount string the id of the source account used by a konnector sourceAccountIdentifier string the unique identifier of the account targeted by the connector CouchDBViewCursor : Array. | string \u00b6 Cursor used for Mango queries pagination Kind : global typedef DirectoryAttributes : object \u00b6 Attributes used for directory creation Kind : global typedef Properties Name Type Description dirId string Id of the parent directory. name boolean Name of the created directory. executable boolean Indicates whether the file will be executable. [metadata] object io.cozy.files.metadata to attach to the directory FileAttributes : object \u00b6 Attributes used for file creation Kind : global typedef Properties Name Type Description id string Id of the document _id string Id of the document dirId string Id of the parent directory. name string Name of the created file. lastModifiedDate Date Can be used to set the last modified date of a file. executable boolean Whether or not the file is executable encrypted boolean Whether or not the file is client-side encrypted metadata object io.cozy.files.metadata to attach to the file FileDocument : object \u00b6 Document representing a io.cozy.files Kind : global typedef Properties Name Type Description _id string Id of the file attributes FileAttributes Attributes of the file meta object Meta relationships object Relationships referenced_by object Referenced by Stream : object \u00b6 Stream is not defined in a browser, but is on NodeJS environment Kind : global typedef OAuthClient : object \u00b6 Document representing a io.cozy.oauth.clients Kind : global typedef Properties Name Type Description _id string Id of the client _type string Doctype of the client (i.e. io.cozy.oauth.clients) OAuthClient : object .doRegistration() .register() \u21d2 Promise .unregister() \u21d2 Promise .fetchInformation() \u21d2 Promise .updateInformation(information, resetSecret) \u21d2 Promise .generateStateCode() \u21d2 string .getAuthCodeURL(options) \u21d2 string .getAccessCodeFromURL(pageURL, stateCode) \u21d2 string .fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise .fetchKonnectorToken(slug) \u21d2 Promise. .fetchSessionCode() \u21d2 Promise. .fetchSessionCodeWithPassword() \u21d2 Promise. .loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> .refreshToken() \u21d2 Promise .setToken(token) .setOAuthOptions(options) .resetClient() .setPassphraseFlagship(params) \u21d2 object .checkForRevocation() \u21d2 Promise. oAuthClient.doRegistration() \u00b6 Performs the HTTP call to register the client to the server Kind : instance method of OAuthClient oAuthClient.register() \u21d2 Promise \u00b6 Registers the currenly configured client with the OAuth server and sets internal information from the server response Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a complete list of client information, including client ID and client secret. Throws : Error When the client is already registered oAuthClient.unregister() \u21d2 Promise \u00b6 Unregisters the currenly configured client with the OAuth server. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information oAuthClient.fetchInformation() \u21d2 Promise \u00b6 Fetches the complete set of client information from the server after it has been registered. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information oAuthClient.updateInformation(information, resetSecret) \u21d2 Promise \u00b6 Overwrites the client own information. This method will update both the local information and the remote information on the OAuth server. Kind : instance method of OAuthClient Returns : Promise - Resolves to a complete, updated list of client information Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Default Description information object Set of information to update. Note that some fields such as clientID can\u2019t be updated. resetSecret boolean false = false Optionnal, whether to reset the client secret or not oAuthClient.generateStateCode() \u21d2 string \u00b6 Generates a random state code to be used during the OAuth process Kind : instance method of OAuthClient oAuthClient.getAuthCodeURL(options) \u21d2 string \u00b6 Generates the URL that the user should be sent to in order to accept the app\u2019s permissions. Kind : instance method of OAuthClient Returns : string - The URL Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description options object URL generation options options.stateCode string A random code to be included in the URl for security. Can be generated with client.generateStateCode() [options.scopes] Array An array of permission scopes for the token. [options.sessionCode] SessionCode A session code that can be used to create a session. [options.codeChallenge] string A code challenge that can be used in a PKCE verification process. oAuthClient.getAccessCodeFromURL(pageURL, stateCode) \u21d2 string \u00b6 Retrieves the access code contained in the URL to which the user is redirected after accepting the app\u2019s permissions (the redirectURI ). Kind : instance method of OAuthClient Returns : string - The access code Throws : Error The URL should contain the same state code as the one generated with client.getAuthCodeURL() . If not, it will throw an error Param Type Description pageURL string The redirected page URL, containing the state code and the access code stateCode string The state code that was contained in the original URL the user was sent to (see client.getAuthCodeURL() ) oAuthClient.fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise \u00b6 Exchanges an access code for an access token. This function does not update the client\u2019s token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with an AccessToken object. Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description accessCode string The access code contained in the redirection URL \u2014 see client.getAccessCodeFromURL() oauthOptionsArg object \u2014 To use when OAuthClient is not yet registered (during login process) uri string \u2014 To use when OAuthClient is not yet registered (during login process) codeVerifier string \u2014 The PKCE code verifier (see https://docs.cozy.io/en/cozy-stack/auth/#pkce-extension) oAuthClient.fetchKonnectorToken(slug) \u21d2 Promise. \u00b6 Used by the flagship application in order to create a token for the konnector with the given slug. This token can then be used by the client-side konnector to make requests to cozy-stack. The flagship app will need to use its own access token to request the konnector token. Kind : instance method of OAuthClient Returns : Promise. - - A promise that resolves with a new token Param Type Description slug string The slug of the konnector oAuthClient.fetchSessionCode() \u21d2 Promise. \u00b6 Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application oAuthClient.fetchSessionCodeWithPassword() \u21d2 Promise. \u00b6 Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application oAuthClient.loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> \u00b6 Get OAuth access and register tokens without having to make OAuth dance This endpoint returns registration tokens only from a Flagship app, otherwise it returns a session_code that should be used in an OAuth dance More info: https://docs.cozy.io/en/cozy-stack/flagship/ More info: https://docs.cozy.io/en/cozy-stack/auth/#post-authloginflagship Kind : instance method of OAuthClient Returns : Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> - A promise that resolves with an access token, a session_code or a 2FA code oAuthClient.refreshToken() \u21d2 Promise \u00b6 Retrieves a new access token by refreshing the currently used token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Error The client should already have an access token to use this function oAuthClient.setToken(token) \u00b6 Updates the client\u2019s stored token Kind : instance method of OAuthClient Param Type Description token string = null The new token to use \u2014 can be a string, a json object or an AccessToken instance. oAuthClient.setOAuthOptions(options) \u00b6 Updates the OAuth informations Kind : instance method of OAuthClient Param Type Description options object Map of OAuth options oAuthClient.resetClient() \u00b6 Reset the current OAuth client Kind : instance method of OAuthClient oAuthClient.setPassphraseFlagship(params) \u21d2 object \u00b6 This method should be used in flagship app onboarding process to finalize the cozy creation by setting the user password into the cozy-stack More info: https://docs.cozy.io/en/cozy-stack/settings/#post-settingspassphraseflagship Kind : instance method of OAuthClient Returns : object - token - The OAauth token Param Type Description params object parameters needed to set passphrase params.registerToken string registration token provided by the onboarding link params.passwordHash string hash of the master password params.hint string hint for the master password params.key string key (crypted) used for the vault encryption params.publicKey string public key used for sharing ciphers from the vault params.privateKey string private key (crypted) used for sharing ciphers from the vault params.iterations string number of KDF iterations applied when hashing the master password oAuthClient.checkForRevocation() \u21d2 Promise. \u00b6 Check if the OAuth client\u2019s has been revoked. If this is the case, call the onRevocationChange callback Kind : instance method of OAuthClient Returns : Promise. - A Promise that resolves to false if client is still valid, or true if it has been revoked. ArchivePages : object \u00b6 Attributes used for create archive link by ids Kind : global typedef Properties Name Type Description id string Id of the file page number The page number. PDF files only (1 is the first page) FetchChangesReturnValue \u21d2 FetchChangesReturnValue \u00b6 Use cozy-stack\u2019s _changes API for io.cozy.files Design docs are filtered by default, thus documents are retrieved in the response (includeDocs is set to true in the parameters of _changes). Deleted and trashed documents can be filtered on demand and files\u2019 paths can be requested as well. Since deleted and trashed documents are skipped by cozy-stack rather than CouchDB, when either option is set to true, the response can contain less documents than the defined limit. Thus one should rely solely on the pending result attribute to determine if more documents can be fetched or not. You should use fetchChangesRaw to call CouchDB\u2019s _changes API. Kind : global typedef Param Type Description couchOptions CouchOptions Couch options for changes options FetchChangesOptions Further options on the returned documents. By default, it is set to Properties Name Type Description since string Bookmark telling CouchDB from which point in time should changes be returned limit number The maximum number of returned documents for one call includeDocs boolean Whether or not complete documents should be returned fields Array. The list of fields that should be returned for each document includeFilePath boolean Whether to include the path of file changes (needs includeDocs to be true) skipDeleted boolean Whether to skip changes for deleted documents skipTrashed boolean Whether to skip changes for trashed documents (needs includeDocs to be true) newLastSeq string pending boolean documents Array. JobDocument : object \u00b6 Document representing a io.cozy.jobs Kind : global typedef Properties Name Type Description _id string Id of the job attributes.state string state of the job. Can be \u2018errored\u2019, \u2018running\u2019, \u2018queued\u2019, \u2018done\u2019 attributes.error string Error message of the job if any MangoPartialFilter : Object \u00b6 Kind : global typedef MangoSelector : object \u00b6 Kind : global typedef MangoSort : Array. \u00b6 Kind : global typedef MangoQueryOptions : object \u00b6 Kind : global typedef Properties Name Type Description [selector] MangoSelector Selector [sort] MangoSort The sorting parameters [fields] Array. The fields to return [partialFilterFields] Array. The partial filter fields [limit] number | null For pagination, the number of results to return [skip] number | null For skip-based pagination, the number of referenced files to skip [indexId] string | null The _id of the CouchDB index to use for this request [bookmark] string | null For bookmark-based pagination, the document _id to start from [indexedFields] Array. [use_index] string Name of the index to use [execution_stats] boolean If true, we request the stats from Couch [partialFilter] MangoPartialFilter | null An optional partial filter DesignDoc : object \u00b6 Attributes representing a design doc Kind : global typedef Properties Name Type Description _id string Id of the design doc. Can be named, e.g. \u2018_design/by_indexed_attribute\u2019 or not, e.g. \u2018_design/12345\u2019 language string The index language. Can be \u2018query\u2019 for mango index or \u2018javascript\u2019 for views. views object Views definition, i.e. the index. _rev string Rev version SessionCode : string \u00b6 Kind : global typedef SessionCodeRes \u00b6 Kind : global typedef Properties Name Type Description session_code string The value of the session code AccessTokenRes \u00b6 Kind : global typedef Properties Name Type Description email_verified_code string The email verified code to skip 2FA access_token string The OAuth access token refresh_token string The OAuth refresh token token_type string The OAuth token type scope string The OAuth scope TwoFactorNeededRes \u00b6 Kind : global typedef Properties Name Type Description two_factor_token string The 2FA token Permission \u21d2 Permission \u00b6 async getOwnPermissions - deprecated: please use fetchOwnPermissions instead Kind : global typedef Returns : Permission - permission Permission \u21d2 Permission \u00b6 async fetchOwnPermissions - Fetches permissions Kind : global typedef Returns : Permission - permission Rule : object \u00b6 A sharing rule Kind : global typedef Properties Name Type title string doctype string values Array [add] string [update] string [remove] string Recipient : object \u00b6 An io.cozy.contact Kind : global typedef Sharing : object \u00b6 An io.cozy.sharings document Kind : global typedef SharingPolicy : object \u00b6 Define the add/update/remove policies for a sharing Kind : global typedef Properties Name Type add string update string remove string SharingType : undefined | 'one-way' | 'two-way' \u00b6 Define how a document is synced between sharing\u2019s owner and receivers. Kind : global typedef RelationshipItem : object \u00b6 Define a recipient that can be used as target of a sharing Kind : global typedef Properties Name Type Description id string Recipient\u2019s ID type string Reciptient\u2019s type (should be \u2018io.cozy.contacts\u2019) CozyStackClient : object \u00b6 Kind : global typedef Properties Name Type Description oauthOptions object oauthOptions uri string CozyUri fetch function fetchMethod fetchJSON function fetchJSON CozyStackClient : object .collection(doctype) \u21d2 DocumentCollection .fetch(method, path, [body], [opts]) \u21d2 object .refreshToken() \u21d2 Promise .fetchJSON(method, path, body, options) \u21d2 object .setToken(token) .getAccessToken() \u21d2 string cozyStackClient.collection(doctype) \u21d2 DocumentCollection \u00b6 Creates a DocumentCollection instance. Kind : instance method of CozyStackClient Param Type Description doctype string The collection doctype. cozyStackClient.fetch(method, path, [body], [opts]) \u21d2 object \u00b6 Fetches an endpoint in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Default Description method string The HTTP method. path string The URI. [body] object The payload. [opts] object Options for fetch cozyStackClient.refreshToken() \u21d2 Promise \u00b6 Retrieves a new app token by refreshing the currently used token. Kind : instance method of CozyStackClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : Error The client should already have an access token to use this function Error The client couldn\u2019t fetch a new token cozyStackClient.fetchJSON(method, path, body, options) \u21d2 object \u00b6 Fetches JSON in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Description method string The HTTP method. path string The URI. body object The payload. options object Options cozyStackClient.setToken(token) \u00b6 Change or set the API token Kind : instance method of CozyStackClient Param Type Description token string | AppToken | AccessToken Stack API token cozyStackClient.getAccessToken() \u21d2 string \u00b6 Get the access token string, being an oauth token or an app token Kind : instance method of CozyStackClient Returns : string - token", "title": "Cozy Stack Client API"}, {"location": "cozy-client/api/cozy-stack-client/#classes", "text": "AppCollection Extends DocumentCollection API along with specific methods for io.cozy.apps . AppsRegistryCollection Extends DocumentCollection API along with specific methods for io.cozy.apps_registry . Collection Utility class to abstract an regroup identical methods and logics for specific collections. CozyStackClient Main API against the cozy-stack server. DocumentCollection Abstracts a collection of documents of the same doctype, providing CRUD methods and other helpers. FileCollection Implements DocumentCollection API along with specific methods for io.cozy.files . Files are a special type of documents and are handled differently by the stack: special routes are to be used, and there is a notion of referenced files, aka files associated to a specific document NotesCollection Implements DocumentCollection API to interact with the /notes endpoint of the stack OAuthClient Specialized CozyStackClient for mobile, implementing stack registration through OAuth. OAuthClientsCollection Implements DocumentCollection API to interact with the /settings/clients endpoint of the stack PermissionCollection Implements DocumentCollection API along with specific methods for io.cozy.permissions . PromiseCache Caches promises while they are pending Serves to dedupe equal queries requested at the same time SettingsCollection Implements DocumentCollection API to interact with the /settings endpoint of the stack SharingCollection Implements the DocumentCollection API along with specific methods for io.cozy.sharings . TriggerCollection Implements DocumentCollection API along with specific methods for io.cozy.triggers .", "title": "Classes"}, {"location": "cozy-client/api/cozy-stack-client/#constants", "text": "dontThrowNotFoundError \u21d2 object Handler for error response which return a empty value for \"not found\" error isIndexNotFoundError \u21d2 Array | null Helper to identify an index not found error isIndexConflictError \u21d2 Array | null Helper to identify an index conflict isIndexNotUsedWarning \u21d2 Array | null Helper to identify a not used index isNoUsableIndexError \u21d2 Array | null Helper to identify a no usable index error isDocumentUpdateConflict \u21d2 Array | null Helper to identify a document conflict isFile \u21d2 boolean Returns true when parameter has type directory, file or has _type io.cozy.files isDirectory \u21d2 boolean Returns true when parameters has type directory getIllegalCharacters \u21d2 string Get the list of illegal characters in the file name makeKeyFromPartialFilter \u21d2 string Process a partial filter to generate a string key getIndexNameFromFields \u21d2 string Name an index, based on its indexed fields and partial filter. It follows this naming convention: by_{indexed_field1}_and_{indexed_field2}_filter_({partial_filter.key1}_{partial_filter.value1})_and_({partial_filter.key2}_{partial_filter.value2}) transformSort \u21d2 MangoSort Transform sort into Array getIndexFields \u21d2 Array Compute fields that should be indexed for a mango query to work isMatchingIndex \u21d2 boolean Check if an index is matching the given fields makeOperatorsExplicit \u21d2 object Transform a query to make all operators explicit getPermissionsFor \u21d2 object Build a permission set normalizeSettings \u21d2 object Normalizing a document for SettingsCollection context getSharingRules \u21d2 Array. Rules determine the behavior of the sharing when changes are made to the shared document See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing forceDownload Force a download from the given href encodePath \u21d2 string Encode a path for use in a URL by encoding special characters but keeping slashes", "title": "Constants"}, {"location": "cozy-client/api/cozy-stack-client/#functions", "text": "getAccessToken() \u21d2 string Get the access token string getAccessToken() \u21d2 string Get the app token string getIconURL() Get Icon URL using blob mechanism if OAuth connected or using preloaded url when blob not needed handleNorOperator(conditions) \u21d2 Array Handle the $nor operator in a query CouchDB transforms $nor into $and with $ne operators garbageCollect() Delete outdated results from cache memoize() Memoize with maxDuration and custom key getSharingRulesForPhotosAlbum(document, sharingType) \u21d2 Array. Compute the rules that define how to share a Photo Album. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing getSharingPolicyForReferencedFiles(sharingType) \u21d2 SharingPolicy Compute the sharing policy for a ReferencedFile based on its sharing type getSharingPolicyForAlbum(sharingType) \u21d2 Array. Compute the sharing policy for an Album based on its sharing type getSharingRulesForFile(document, sharingType) \u21d2 Array. Compute the rules that define how to share a File. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing getSharingPolicyForFile(document, sharingType) \u21d2 SharingPolicy Compute the sharing policy for a File based on its sharing type getSharingRulesForOrganizations(document) \u21d2 Array. Compute the rules that define how to share an Organization. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing toRelationshipItem(item) \u21d2 RelationshipItem Compute the RelationshipItem that can be referenced as a sharing recipient getCozyURL() Get a uniform formatted URL and SSL information according to a provided URL joinPath(start, end) \u21d2 string Join two paths together ensuring there is only one slash between them", "title": "Functions"}, {"location": "cozy-client/api/cozy-stack-client/#typedefs", "text": "FetchChangesReturnValue \u21d2 Promise. Use Couch _changes API Deleted and design docs are filtered by default, thus documents are retrieved in the response (include_docs is set to true in the parameters of _changes). You should use fetchChangesRaw to have low level control on _changes parameters. IOCozyFolder : object Folder SpecificFileAttributesForKonnector : object Specific file attributes for creation for konnector CouchDBViewCursor : Array. | string Cursor used for Mango queries pagination DirectoryAttributes : object Attributes used for directory creation FileAttributes : object Attributes used for file creation FileDocument : object Document representing a io.cozy.files Stream : object Stream is not defined in a browser, but is on NodeJS environment OAuthClient : object Document representing a io.cozy.oauth.clients ArchivePages : object Attributes used for create archive link by ids FetchChangesReturnValue \u21d2 FetchChangesReturnValue Use cozy-stack's _changes API for io.cozy.files Design docs are filtered by default, thus documents are retrieved in the response (includeDocs is set to true in the parameters of _changes). Deleted and trashed documents can be filtered on demand and files' paths can be requested as well. Since deleted and trashed documents are skipped by cozy-stack rather than CouchDB, when either option is set to true, the response can contain less documents than the defined limit. Thus one should rely solely on the pending result attribute to determine if more documents can be fetched or not. You should use fetchChangesRaw to call CouchDB's _changes API. JobDocument : object Document representing a io.cozy.jobs MangoPartialFilter : Object MangoSelector : object MangoSort : Array. MangoQueryOptions : object DesignDoc : object Attributes representing a design doc SessionCode : string SessionCodeRes AccessTokenRes TwoFactorNeededRes Permission \u21d2 Permission async getOwnPermissions - deprecated: please use fetchOwnPermissions instead Permission \u21d2 Permission async fetchOwnPermissions - Fetches permissions Rule : object A sharing rule Recipient : object An io.cozy.contact Sharing : object An io.cozy.sharings document SharingPolicy : object Define the add/update/remove policies for a sharing SharingType : undefined | 'one-way' | 'two-way' Define how a document is synced between sharing's owner and receivers. RelationshipItem : object Define a recipient that can be used as target of a sharing CozyStackClient : object", "title": "Typedefs"}, {"location": "cozy-client/api/cozy-stack-client/#appcollection", "text": "Extends DocumentCollection API along with specific methods for io.cozy.apps . Kind : global class", "title": "AppCollection"}, {"location": "cozy-client/api/cozy-stack-client/#appcollectionall-object", "text": "Lists all apps, without filters. The returned documents are not paginated by the stack. Kind : instance method of AppCollection Returns : Object - The JSON API conformant response. Throws : FetchError", "title": "appCollection.all() \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#appsregistrycollection", "text": "Extends DocumentCollection API along with specific methods for io.cozy.apps_registry . Kind : global class", "title": "AppsRegistryCollection"}, {"location": "cozy-client/api/cozy-stack-client/#appsregistrycollectiongetslug-promisedata-object", "text": "Fetches an app from the registry. Kind : instance method of AppsRegistryCollection Returns : Promise.<{data: object}> - JsonAPI response containing normalized document as data attribute Throws : FetchError Param Type Description slug string Slug of the app", "title": "appsRegistryCollection.get(slug) \u21d2 Promise.<{data: object}>"}, {"location": "cozy-client/api/cozy-stack-client/#collection", "text": "Utility class to abstract an regroup identical methods and logics for specific collections. Kind : global class", "title": "Collection"}, {"location": "cozy-client/api/cozy-stack-client/#collectiongetstackclient-endpoint-options-promiseobject", "text": "Utility method aimed to return only one document. Kind : static method of Collection Returns : Promise. - JsonAPI response containing normalized document as data attribute Param Type Default Description stackClient CozyStackClient CozyStackClient endpoint string Stack endpoint options object Options of the collection options.normalize function Callback to normalize response data (default data => data ) [options.method] string \"GET\" HTTP method", "title": "Collection.get(stackClient, endpoint, options) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclient", "text": "Main API against the cozy-stack server. Kind : global class CozyStackClient .collection(doctype) \u21d2 DocumentCollection .fetch(method, path, [body], [opts]) \u21d2 object .refreshToken() \u21d2 Promise .fetchJSON(method, path, body, options) \u21d2 object .setToken(token) .getAccessToken() \u21d2 string", "title": "CozyStackClient"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientcollectiondoctype-documentcollection", "text": "Creates a DocumentCollection instance. Kind : instance method of CozyStackClient Param Type Description doctype string The collection doctype.", "title": "cozyStackClient.collection(doctype) \u21d2 DocumentCollection"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientfetchmethod-path-body-opts-object", "text": "Fetches an endpoint in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Default Description method string The HTTP method. path string The URI. [body] object The payload. [opts] object Options for fetch", "title": "cozyStackClient.fetch(method, path, [body], [opts]) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientrefreshtoken-promise", "text": "Retrieves a new app token by refreshing the currently used token. Kind : instance method of CozyStackClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : Error The client should already have an access token to use this function Error The client couldn\u2019t fetch a new token", "title": "cozyStackClient.refreshToken() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientfetchjsonmethod-path-body-options-object", "text": "Fetches JSON in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Description method string The HTTP method. path string The URI. body object The payload. options object Options", "title": "cozyStackClient.fetchJSON(method, path, body, options) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientsettokentoken", "text": "Change or set the API token Kind : instance method of CozyStackClient Param Type Description token string | AppToken | AccessToken Stack API token", "title": "cozyStackClient.setToken(token)"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientgetaccesstoken-string", "text": "Get the access token string, being an oauth token or an app token Kind : instance method of CozyStackClient Returns : string - token", "title": "cozyStackClient.getAccessToken() \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollection", "text": "Abstracts a collection of documents of the same doctype, providing CRUD methods and other helpers. Kind : global class DocumentCollection instance .all(options) \u21d2 Promise.<{data, meta, skip, bookmark, next}> .fetchDocumentsWithMango(path, selector, options) .findWithMango(path, selector, options) \u21d2 Promise. .find(selector, options) \u21d2 Promise.<{data, skip, bookmark, next, execution_stats}> .findAll(selector, options) \u21d2 Promise.> .get(id) \u21d2 Promise. .getAll() .create(doc) .update(document) .destroy(doc) .updateAll(rawDocs) .destroyAll(docs) .toMangoOptions(selector, options) \u21d2 MangoQueryOptions .createIndex(fields, indexOption) \u21d2 Promise.<{id, fields}> .fetchAllMangoIndexes() \u21d2 Promise.> .destroyIndex(index) \u21d2 Promise. .copyIndex(existingIndex, newIndexName) \u21d2 Promise. .fetchChangesRaw(couchOptions) static .normalizeDoctype(doctype) \u21d2 function", "title": "DocumentCollection"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionalloptions-promisedata-meta-skip-bookmark-next", "text": "Lists all documents of the collection, without filters. The returned documents are paginated by the stack. Kind : instance method of DocumentCollection Returns : Promise.<{data, meta, skip, bookmark, next}> - The JSON API conformant response. Throws : FetchError Param Type Default Description options object The fetch options: pagination & fetch of specific docs. [options.limit] number 100 Pagination limit [options.skip] number 0 Pagination Skip [options.bookmark] string Pagination bookmark [options.keys] Array. Keys to query", "title": "documentCollection.all(options) \u21d2 Promise.<{data, meta, skip, bookmark, next}>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionfetchdocumentswithmangopath-selector-options", "text": "Fetch Documents with Mango Kind : instance method of DocumentCollection Param Type Description path string path to fetch selector MangoSelector selector options MangoQueryOptions request options", "title": "documentCollection.fetchDocumentsWithMango(path, selector, options)"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionfindwithmangopath-selector-options-promiseobject", "text": "Find documents with the mango selector and create index if missing. We adopt an optimistic approach for index creation: we run the query first, and only if an index missing error is returned, the index is created and the query run again. Kind : instance method of DocumentCollection Returns : Promise. - - The find response Access : protected Param Type Description path string The route path selector MangoSelector The mango selector options MangoQueryOptions The find options", "title": "documentCollection.findWithMango(path, selector, options) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionfindselector-options-promisedata-skip-bookmark-next-execution_stats", "text": "Returns a filtered list of documents using a Mango selector. The returned documents are paginated by the stack. Kind : instance method of DocumentCollection Returns : Promise.<{data, skip, bookmark, next, execution_stats}> - The JSON API conformant response. Throws : FetchError Param Type Description selector MangoSelector The Mango selector. options MangoQueryOptions MangoQueryOptions", "title": "documentCollection.find(selector, options) \u21d2 Promise.<{data, skip, bookmark, next, execution_stats}>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionfindallselector-options-promisearraydata", "text": "Returns a filtered list with all documents using a Mango selector, automatically fetching more documents if the total of documents is superior to the pagination limit. Can result in a lot of network requests. The returned documents are paginated by the stack. Kind : instance method of DocumentCollection Returns : Promise.> - Documents fetched Throws : FetchError Param Type Description selector MangoSelector The Mango selector. options MangoQueryOptions MangoQueryOptions", "title": "documentCollection.findAll(selector, options) \u21d2 Promise.<Array.<{data}>>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectiongetid-promiseobject", "text": "Get a document by id Kind : instance method of DocumentCollection Returns : Promise. - JsonAPI response containing normalized document as data attribute Param Type Description id string The document id.", "title": "documentCollection.get(id) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectiongetall", "text": "Get many documents by id Kind : instance method of DocumentCollection", "title": "documentCollection.getAll()"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectioncreatedoc", "text": "Creates a document Kind : instance method of DocumentCollection Param Type Description doc object Document to create. Optional: you can force the id with the _id attribute", "title": "documentCollection.create(doc)"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionupdatedocument", "text": "Updates a document Kind : instance method of DocumentCollection Param Type Description document object Document to update. Do not forget the _id attribute", "title": "documentCollection.update(document)"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectiondestroydoc", "text": "Destroys a document Kind : instance method of DocumentCollection Param Type Description doc object Document to destroy. Do not forget _id and _rev attributes", "title": "documentCollection.destroy(doc)"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionupdateallrawdocs", "text": "Updates several documents in one batch Kind : instance method of DocumentCollection Param Type Description rawDocs Array. Documents to be updated", "title": "documentCollection.updateAll(rawDocs)"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectiondestroyalldocs", "text": "Deletes several documents in one batch Kind : instance method of DocumentCollection Param Type Description docs Array. Documents to delete", "title": "documentCollection.destroyAll(docs)"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectiontomangooptionsselector-options-mangoqueryoptions", "text": "Returns Mango Options from Selector and Options Kind : instance method of DocumentCollection Returns : MangoQueryOptions - Mango options Param Type Description selector MangoSelector Mango selector options MangoQueryOptions Mango Options", "title": "documentCollection.toMangoOptions(selector, options) \u21d2 MangoQueryOptions"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectioncreateindexfields-indexoption-promiseid-fields", "text": "Kind : instance method of DocumentCollection Param Type Description fields Array Fields to index indexOption object Options for the index [indexOption.partialFilter] MangoPartialFilter partialFilter [indexOption.indexName] string indexName", "title": "documentCollection.createIndex(fields, indexOption) \u21d2 Promise.<{id, fields}>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionfetchallmangoindexes-promisearraydesigndoc", "text": "Retrieve all design docs of mango indexes Kind : instance method of DocumentCollection Returns : Promise.> - The design docs", "title": "documentCollection.fetchAllMangoIndexes() \u21d2 Promise.<Array.<DesignDoc>>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectiondestroyindexindex-promiseobject", "text": "Delete the specified design doc Kind : instance method of DocumentCollection Returns : Promise. - The delete response Param Type Description index DesignDoc The design doc to remove", "title": "documentCollection.destroyIndex(index) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectioncopyindexexistingindex-newindexname-promisedesigndoc", "text": "Copy an existing design doc. This is useful to create a new design doc without having to recompute the existing index. Kind : instance method of DocumentCollection Returns : Promise. - The copy response Param Type Description existingIndex DesignDoc The design doc to copy newIndexName string The name of the copy", "title": "documentCollection.copyIndex(existingIndex, newIndexName) \u21d2 Promise.<DesignDoc>"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionfetchchangesrawcouchoptions", "text": "Calls _changes route from CouchDB No further treatment is done contrary to fetchchanges Kind : instance method of DocumentCollection See : https://docs.couchdb.org/en/stable/api/database/changes.html Param Type Description couchOptions object Couch options for changes https://kutt.it/5r7MNQ [couchOptions.since] string Bookmark telling CouchDB from which point in time should changes be returned [couchOptions.doc_ids] Array. Only return changes for a subset of documents [couchOptions.includeDocs] boolean Includes full documents as part of results [couchOptions.filter] string Filter", "title": "documentCollection.fetchChangesRaw(couchOptions)"}, {"location": "cozy-client/api/cozy-stack-client/#documentcollectionnormalizedoctypedoctype-function", "text": "Provides a callback for Collection.get Kind : static method of DocumentCollection Returns : function - (data, response) => normalizedDocument using normalizeDoc Param Type Description doctype string Document doctype", "title": "DocumentCollection.normalizeDoctype(doctype) \u21d2 function"}, {"location": "cozy-client/api/cozy-stack-client/#filecollection", "text": "Implements DocumentCollection API along with specific methods for io.cozy.files . Files are a special type of documents and are handled differently by the stack: special routes are to be used, and there is a notion of referenced files, aka files associated to a specific document Kind : global class FileCollection .forceFileDownload .get(id) \u21d2 Object .find(selector, options) \u21d2 Promise.<{data, meta, skip, next, bookmark, execution_stats}> .findReferencedBy(document, options) \u21d2 Promise.<{data, included, meta, skip, next}> .addReferencedBy(document, documents) \u21d2 Promise.<{data, meta}> .removeReferencedBy(document, documents) \u21d2 Promise.<{data, meta}> .addReferencesTo(document, documents) .removeReferencesTo(document, documents) .destroy(file) \u21d2 Promise .emptyTrash() .restore(id) \u21d2 Promise .copy(id, [name], [dirId]) \u21d2 Promise. .deleteFilePermanently(id) \u21d2 Promise. .upload(data, dirPath) \u21d2 Promise. .create(attributes) .updateFile(data, params) \u21d2 object .download(file, versionId, filename) .fetchFileContentById(id) .getBeautifulSize(file, decimal) .downloadArchive(fileIds, [notSecureFilename], [options]) ~~ .getArchiveLinkByIds() ~~ .createArchiveLinkByIds(params) \u21d2 Promise. .isChildOf(child, parent) \u21d2 boolean .statById(id, options) \u21d2 object .createDirectoryByPath(path) \u21d2 object .createFileMetadata(attributes) \u21d2 Promise. .updateMetadataAttribute(id, metadata) \u21d2 Promise. .getFileTypeFromName(name) \u21d2 string .doUpload(dataArg, path, options, method) .findNotSynchronizedDirectories(oauthClient, options) \u21d2 Array.<(object|IOCozyFolder)> .addNotSynchronizedDirectories(oauthClient, directories) .removeNotSynchronizedDirectories(oauthClient, directories)", "title": "FileCollection"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionforcefiledownload", "text": "Force a file download from the given href Kind : instance property of FileCollection Param Type Description href string The link to download filename string The file name to download", "title": "fileCollection.forceFileDownload"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiongetid-object", "text": "Fetches the file\u2019s data Kind : instance method of FileCollection Returns : Object - Information about the file or folder and it\u2019s descendents Param Type Description id string File id", "title": "fileCollection.get(id) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionfindselector-options-promisedata-meta-skip-next-bookmark-execution_stats", "text": "Returns a filtered list of documents using a Mango selector. The returned documents are paginated by the stack. Kind : instance method of FileCollection Returns : Promise.<{data, meta, skip, next, bookmark, execution_stats}> - The JSON API conformant response. Throws : FetchError Param Type Description selector object The Mango selector. options MangoQueryOptions The query options", "title": "fileCollection.find(selector, options) \u21d2 Promise.<{data, meta, skip, next, bookmark, execution_stats}>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionfindreferencedbydocument-options-promisedata-included-meta-skip-next", "text": "async findReferencedBy - Returns the list of files referenced by a document \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/ Kind : instance method of FileCollection Returns : Promise.<{data, included, meta, skip, next}> - The JSON API conformant response. Param Type Description document object A JSON representing a document, with at least a _type and _id field. options object Additional options [options.skip] number | null For skip-based pagination, the number of referenced files to skip. [options.limit] number | null For pagination, the number of results to return. [options.cursor] CouchDBViewCursor | null For cursor-based pagination, the index cursor.", "title": "fileCollection.findReferencedBy(document, options) \u21d2 Promise.<{data, included, meta, skip, next}>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionaddreferencedbydocument-documents-promisedata-meta", "text": "Add referenced_by documents to a file \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#post-filesfile-idrelationshipsreferenced_by For example, to have an album referenced by a file: addReferencedBy({_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}, [{_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}]) Kind : instance method of FileCollection Returns : Promise.<{data, meta}> - The JSON API conformant response. Param Type Description document FileDocument A JSON representing the file documents Array An array of JSON documents having a _type and _id field.", "title": "fileCollection.addReferencedBy(document, documents) \u21d2 Promise.<{data, meta}>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionremovereferencedbydocument-documents-promisedata-meta", "text": "Remove referenced_by documents from a file \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#delete-filesfile-idrelationshipsreferenced_by For example, to remove an album reference from a file: removeReferencedBy({_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}, [{_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}]) Kind : instance method of FileCollection Returns : Promise.<{data, meta}> - The JSON API conformant response. Param Type Description document object A JSON representing the file documents Array An array of JSON documents having a _type and _id field.", "title": "fileCollection.removeReferencedBy(document, documents) \u21d2 Promise.<{data, meta}>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionaddreferencestodocument-documents", "text": "Add files references to a document \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#post-datatypedoc-idrelationshipsreferences For example, to add a photo to an album: addReferencesTo({_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}, [{_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}]) Kind : instance method of FileCollection Param Type Description document object A JSON representing a document, with at least a _type and _id field. documents Array An array of JSON files having an _id field. Returns 204 No Content", "title": "fileCollection.addReferencesTo(document, documents)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionremovereferencestodocument-documents", "text": "Remove files references to a document \u2014 see https://docs.cozy.io/en/cozy-stack/references-docs-in-vfs/#delete-datatypedoc-idrelationshipsreferences For example, to remove a photo from an album: removeReferencesTo({_id: 456, _type: \"io.cozy.photos.albums\", name: \"Happy Cloud\"}, [{_id: 123, _type: \"io.cozy.files\", name: \"cozy.jpg\"}]) Kind : instance method of FileCollection Param Type Description document object A JSON representing a document, with at least a _type and _id field. documents Array An array of JSON files having an _id field. Returns 204 No Content", "title": "fileCollection.removeReferencesTo(document, documents)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiondestroyfile-promise", "text": "Sends file to trash and removes references to it Kind : instance method of FileCollection Returns : Promise - - Resolves when references have been removed and file has been sent to trash Param Type Description file FileDocument File that will be sent to trash", "title": "fileCollection.destroy(file) \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionemptytrash", "text": "Empty the Trash Kind : instance method of FileCollection", "title": "fileCollection.emptyTrash()"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionrestoreid-promise", "text": "Restores a trashed file. Kind : instance method of FileCollection Returns : Promise - - A promise that returns the restored file if resolved. Throws : FetchError Param Type Description id string The file\u2019s id", "title": "fileCollection.restore(id) \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectioncopyid-name-dirid-promiseobject", "text": "Copy a file. Kind : instance method of FileCollection Returns : Promise. - - A promise that returns the copied file if resolved. Throws : FetchError Param Type Description id string The file\u2019s id [name] string The file copy name [dirId] string The destination directory id", "title": "fileCollection.copy(id, [name], [dirId]) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiondeletefilepermanentlyid-promiseobject", "text": "async deleteFilePermanently - Definitely delete a file Kind : instance method of FileCollection Returns : Promise. - The deleted file object Param Type Description id string The id of the file to delete", "title": "fileCollection.deleteFilePermanently(id) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionuploaddata-dirpath-promiseobject", "text": "Kind : instance method of FileCollection Returns : Promise. - Created io.cozy.files Param Type Description data File | Blob | Stream | string | ArrayBuffer file to be uploaded dirPath string Path to upload the file to. ie : /Administative/XXX/", "title": "fileCollection.upload(data, dirPath) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectioncreateattributes", "text": "Creates directory or file. - Used by StackLink to support CozyClient.create(\u2018io.cozy.files\u2019, options) Kind : instance method of FileCollection Throws : Error - explaining reason why creation failed Param Type Description attributes FileAttributes | DirectoryAttributes Attributes of the created file/directory attributes.data File | Blob | string | ArrayBuffer Will be used as content of the created file", "title": "fileCollection.create(attributes)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionupdatefiledata-params-object", "text": "updateFile - Updates a file\u2019s data Kind : instance method of FileCollection Returns : object - Updated document Throws : Error - explaining reason why update failed Param Type Description data File | Blob | Stream | string | ArrayBuffer file to be uploaded params FileAttributes Additional parameters params.options object Options to pass to doUpload method (additional headers)", "title": "fileCollection.updateFile(data, params) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiondownloadfile-versionid-filename", "text": "Download a file or a specific version of the file Kind : instance method of FileCollection Param Type Default Description file object io.cozy.files object versionId string null Id of the io.cozy.files.version filename string The name you want for the downloaded file (by default the same as the file)", "title": "fileCollection.download(file, versionId, filename)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionfetchfilecontentbyidid", "text": "Fetch the binary of a file or a specific version of a file Useful for instance when you can\u2019t download the file directly (via a content-disposition attachement header) and need to store it before doing an operation. Kind : instance method of FileCollection Param Type Description id string Id of the io.cozy.files or io.cozy.files.version", "title": "fileCollection.fetchFileContentById(id)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiongetbeautifulsizefile-decimal", "text": "Get a beautified size for a given file 1024B => 1KB 102404500404B => 95.37 GB Kind : instance method of FileCollection Param Type Description file object io.cozy.files object decimal number number of decimal", "title": "fileCollection.getBeautifulSize(file, decimal)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiondownloadarchivefileids-notsecurefilename-options", "text": "Download an archive of the files Kind : instance method of FileCollection Param Type Description fileIds Array. List of file ids [notSecureFilename] string Name of the archive (default: \u2018files\u2019) [options] object Additional options [options.pages] Array. Array of objects, with id the file identifier, and page the page number (1 is the first page)", "title": "fileCollection.downloadArchive(fileIds, [notSecureFilename], [options])"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiongetarchivelinkbyids", "text": "Deprecated Kind : instance method of FileCollection", "title": "~~fileCollection.getArchiveLinkByIds()~~"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectioncreatearchivelinkbyidsparams-promisestring", "text": "Create the archive link for a list of files The generated archive is temporary and is not persisted Kind : instance method of FileCollection Returns : Promise. - - The archive link Param Type Description params object Parameters params.ids Array. List of file ids [params.name] string Name of the archive (default: \u2018files\u2019) [params.pages] Array. Array of objects, with id the file identifier, and page the page number (1 is the first page)", "title": "fileCollection.createArchiveLinkByIds(params) \u21d2 Promise.<string>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionischildofchild-parent-boolean", "text": "Checks if the file belongs to the parent\u2019s hierarchy. Kind : instance method of FileCollection Returns : boolean - Whether the file is a parent\u2019s child Param Type Description child string | object The file which can either be an id or an object parent string | object The parent target which can either be an id or an object", "title": "fileCollection.isChildOf(child, parent) \u21d2 boolean"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionstatbyidid-options-object", "text": "statById - Fetches the metadata about a document. For folders, the results include the list of child files and folders. Kind : instance method of FileCollection Returns : object - A promise resolving to an object containing \u201cdata\u201d (the document metadata), \u201cincluded\u201d (the child documents) and \u201clinks\u201d (pagination informations) Param Type Description id string ID of the document options object | null Pagination options [options.page[limit]] number | null For pagination, the number of results to return. [options.page[skip]] number | null For skip-based pagination, the number of referenced files to skip. [options.page[cursor]] CouchDBViewCursor | null For cursor-based pagination, the index cursor.", "title": "fileCollection.statById(id, options) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectioncreatedirectorybypathpath-object", "text": "async createDirectoryByPath - Creates one or more folders until the given path exists Kind : instance method of FileCollection Returns : object - The document corresponding to the last segment of the path Param Type Description path string Path of the created directory", "title": "fileCollection.createDirectoryByPath(path) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectioncreatefilemetadataattributes-promiseobject", "text": "Send a metadata object that can be associated to a file uploaded after that, via the MetadataID query parameter. See https://github.com/cozy/cozy-stack/blob/master/docs/files.md#post-filesuploadmetadata Kind : instance method of FileCollection Returns : Promise. - The Metadata object Param Type Description attributes object The file\u2019s metadata", "title": "fileCollection.createFileMetadata(attributes) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionupdatemetadataattributeid-metadata-promiseobject", "text": "Updates the metadata attribute of a io.cozy.files Creates a new version of the file without having to upload again the file\u2019s content To see available content of the metadata attribute see : https://docs.cozy.io/en/cozy-doctypes/docs/io.cozy.files_metadata/ Kind : instance method of FileCollection Returns : Promise. - io.cozy.files updated Param Type Description id string File id metadata object io.cozy.files.metadata attributes", "title": "fileCollection.updateMetadataAttribute(id, metadata) \u21d2 Promise.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiongetfiletypefromnamename-string", "text": "Get the file mime-type based on its name Kind : instance method of FileCollection Returns : string - the inferred file mime-type Param Type Description name string The file name", "title": "fileCollection.getFileTypeFromName(name) \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectiondouploaddataarg-path-options-method", "text": "This method should not be called directly to upload a file. You should use createFile Kind : instance method of FileCollection Param Type Default Description dataArg File | Blob | Stream | string | ArrayBuffer file to be uploaded path string Uri to call the stack from. Something like /files/${dirId}?Name=${name}&Type=file&Executable=${executable}&MetadataID=${metadataId} options object Additional headers method string \"POST\" POST / PUT / PATCH", "title": "fileCollection.doUpload(dataArg, path, options, method)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionfindnotsynchronizeddirectoriesoauthclient-options-arrayobjectiocozyfolder", "text": "async findNotSynchronizedDirectories - Returns the list of directories not synchronized on the given OAuth client (mainly Cozy Desktop clients) \u2014 see https://docs.cozy.io/en/cozy-stack/not-synchronized-vfs/#get-datatypedoc-idrelationshipsnot_synchronizing Kind : instance method of FileCollection Returns : Array.<(object|IOCozyFolder)> - The JSON API conformant response. Param Type Description oauthClient OAuthClient A JSON representing an OAuth client, with at least a _type and _id field. options object | null Pagination options options.skip number | null For skip-based pagination, the number of referenced files to skip. options.limit number | null For pagination, the number of results to return. options.cursor CouchDBViewCursor | null For cursor-based pagination, the index cursor. options.includeFiles boolean Include the whole file documents in the results list", "title": "fileCollection.findNotSynchronizedDirectories(oauthClient, options) \u21d2 Array.<(object|IOCozyFolder)>"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionaddnotsynchronizeddirectoriesoauthclient-directories", "text": "Add directory synchronization exclusions to an OAuth client \u2014 see https://docs.cozy.io/en/cozy-stack/not-synchronized-vfs/#post-datatypedoc-idrelationshipsnot_synchronizing For example, to exclude directory /Photos from My Computer \u2018s desktop synchronization: addNotSynchronizedDirectories({_id: 123, _type: \"io.cozy.oauth.clients\", clientName: \"Cozy Drive (My Computer)\", clientKind: \"desktop\"}, [{_id: 456, _type: \"io.cozy.files\", name: \"Photos\", path: \"/Photos\"}]) Kind : instance method of FileCollection Param Type Description oauthClient OAuthClient A JSON representing the OAuth client directories Array An array of JSON documents having a _type and _id fields and representing directories. Returns 204 No Content", "title": "fileCollection.addNotSynchronizedDirectories(oauthClient, directories)"}, {"location": "cozy-client/api/cozy-stack-client/#filecollectionremovenotsynchronizeddirectoriesoauthclient-directories", "text": "Remove directory synchronization exclusions from an OAuth client \u2014 see https://docs.cozy.io/en/cozy-stack/not-synchronized-vfs/#delete-datatypedoc-idrelationshipsnot_synchronizing For example, to re-include directory /Photos into My Computer \u2018s desktop synchronization: removeNotSynchronizedDirectories({_id: 123, _type: \"io.cozy.oauth.clients\", clientName: \"Cozy Drive (My Computer)\", clientKind: \"desktop\"}, [{_id: 456, _type: \"io.cozy.files\", name: \"Photos\", path: \"/Photos\"}]) Kind : instance method of FileCollection Param Type Description oauthClient OAuthClient A JSON representing the OAuth client directories Array An array of JSON documents having a _type and _id field and representing directories. Returns 204 No Content", "title": "fileCollection.removeNotSynchronizedDirectories(oauthClient, directories)"}, {"location": "cozy-client/api/cozy-stack-client/#notescollection", "text": "Implements DocumentCollection API to interact with the /notes endpoint of the stack Kind : global class NotesCollection .get(id) \u21d2 Object .all() \u21d2 Object .destroy(note) \u21d2 Object .create(options) \u21d2 Object .fetchURL(note) \u21d2 Object .getDefaultSchema() \u21d2 object", "title": "NotesCollection"}, {"location": "cozy-client/api/cozy-stack-client/#notescollectiongetid-object", "text": "Fetches the note data Kind : instance method of NotesCollection Returns : Object - Information about the note Param Type Description id string Note id", "title": "notesCollection.get(id) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#notescollectionall-object", "text": "Fetches all notes Kind : instance method of NotesCollection Returns : Object - The JSON API conformant response.", "title": "notesCollection.all() \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#notescollectiondestroynote-object", "text": "Destroys the note on the server Kind : instance method of NotesCollection Returns : Object - The deleted note Param Type Description note object The io.cozy.notes document to destroy [note._id] string The note\u2019s id", "title": "notesCollection.destroy(note) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#notescollectioncreateoptions-object", "text": "Create a note Kind : instance method of NotesCollection Returns : Object - The JSON API conformant response. Param Type Description options object Options [options.dir_id] string dir_id where to create the note", "title": "notesCollection.create(options) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#notescollectionfetchurlnote-object", "text": "Returns the details to build the note\u2019s url Kind : instance method of NotesCollection Returns : Object - The note\u2019s url details See : https://github.com/cozy/cozy-stack/blob/master/docs/notes.md#get-notesidopen Param Type Description note object The io.cozy.notes document to open [note._id] string The note\u2019s id", "title": "notesCollection.fetchURL(note) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#notescollectiongetdefaultschema-object", "text": "Returns promise mirror schema for a note Kind : instance method of NotesCollection Returns : object - schema", "title": "notesCollection.getDefaultSchema() \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclient", "text": "Specialized CozyStackClient for mobile, implementing stack registration through OAuth. Kind : global class OAuthClient .doRegistration() .register() \u21d2 Promise .unregister() \u21d2 Promise .fetchInformation() \u21d2 Promise .updateInformation(information, resetSecret) \u21d2 Promise .generateStateCode() \u21d2 string .getAuthCodeURL(options) \u21d2 string .getAccessCodeFromURL(pageURL, stateCode) \u21d2 string .fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise .fetchKonnectorToken(slug) \u21d2 Promise. .fetchSessionCode() \u21d2 Promise. .fetchSessionCodeWithPassword() \u21d2 Promise. .loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> .refreshToken() \u21d2 Promise .setToken(token) .setOAuthOptions(options) .resetClient() .setPassphraseFlagship(params) \u21d2 object .checkForRevocation() \u21d2 Promise.", "title": "OAuthClient"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientdoregistration", "text": "Performs the HTTP call to register the client to the server Kind : instance method of OAuthClient", "title": "oAuthClient.doRegistration()"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientregister-promise", "text": "Registers the currenly configured client with the OAuth server and sets internal information from the server response Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a complete list of client information, including client ID and client secret. Throws : Error When the client is already registered", "title": "oAuthClient.register() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientunregister-promise", "text": "Unregisters the currenly configured client with the OAuth server. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information", "title": "oAuthClient.unregister() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchinformation-promise", "text": "Fetches the complete set of client information from the server after it has been registered. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information", "title": "oAuthClient.fetchInformation() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientupdateinformationinformation-resetsecret-promise", "text": "Overwrites the client own information. This method will update both the local information and the remote information on the OAuth server. Kind : instance method of OAuthClient Returns : Promise - Resolves to a complete, updated list of client information Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Default Description information object Set of information to update. Note that some fields such as clientID can\u2019t be updated. resetSecret boolean false = false Optionnal, whether to reset the client secret or not", "title": "oAuthClient.updateInformation(information, resetSecret) \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientgeneratestatecode-string", "text": "Generates a random state code to be used during the OAuth process Kind : instance method of OAuthClient", "title": "oAuthClient.generateStateCode() \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientgetauthcodeurloptions-string", "text": "Generates the URL that the user should be sent to in order to accept the app\u2019s permissions. Kind : instance method of OAuthClient Returns : string - The URL Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description options object URL generation options options.stateCode string A random code to be included in the URl for security. Can be generated with client.generateStateCode() [options.scopes] Array An array of permission scopes for the token. [options.sessionCode] SessionCode A session code that can be used to create a session. [options.codeChallenge] string A code challenge that can be used in a PKCE verification process.", "title": "oAuthClient.getAuthCodeURL(options) \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientgetaccesscodefromurlpageurl-statecode-string", "text": "Retrieves the access code contained in the URL to which the user is redirected after accepting the app\u2019s permissions (the redirectURI ). Kind : instance method of OAuthClient Returns : string - The access code Throws : Error The URL should contain the same state code as the one generated with client.getAuthCodeURL() . If not, it will throw an error Param Type Description pageURL string The redirected page URL, containing the state code and the access code stateCode string The state code that was contained in the original URL the user was sent to (see client.getAuthCodeURL() )", "title": "oAuthClient.getAccessCodeFromURL(pageURL, stateCode) \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchaccesstokenaccesscode-oauthoptionsarg-uri-codeverifier-promise", "text": "Exchanges an access code for an access token. This function does not update the client\u2019s token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with an AccessToken object. Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description accessCode string The access code contained in the redirection URL \u2014 see client.getAccessCodeFromURL() oauthOptionsArg object \u2014 To use when OAuthClient is not yet registered (during login process) uri string \u2014 To use when OAuthClient is not yet registered (during login process) codeVerifier string \u2014 The PKCE code verifier (see https://docs.cozy.io/en/cozy-stack/auth/#pkce-extension)", "title": "oAuthClient.fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchkonnectortokenslug-promisestring", "text": "Used by the flagship application in order to create a token for the konnector with the given slug. This token can then be used by the client-side konnector to make requests to cozy-stack. The flagship app will need to use its own access token to request the konnector token. Kind : instance method of OAuthClient Returns : Promise. - - A promise that resolves with a new token Param Type Description slug string The slug of the konnector", "title": "oAuthClient.fetchKonnectorToken(slug) \u21d2 Promise.<string>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchsessioncode-promisesessioncoderes", "text": "Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application", "title": "oAuthClient.fetchSessionCode() \u21d2 Promise.<SessionCodeRes>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchsessioncodewithpassword-promisesessioncoderes", "text": "Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application", "title": "oAuthClient.fetchSessionCodeWithPassword() \u21d2 Promise.<SessionCodeRes>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientloginflagship-promiseaccesstokenrestwofactorneededressessioncoderes", "text": "Get OAuth access and register tokens without having to make OAuth dance This endpoint returns registration tokens only from a Flagship app, otherwise it returns a session_code that should be used in an OAuth dance More info: https://docs.cozy.io/en/cozy-stack/flagship/ More info: https://docs.cozy.io/en/cozy-stack/auth/#post-authloginflagship Kind : instance method of OAuthClient Returns : Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> - A promise that resolves with an access token, a session_code or a 2FA code", "title": "oAuthClient.loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientrefreshtoken-promise", "text": "Retrieves a new access token by refreshing the currently used token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Error The client should already have an access token to use this function", "title": "oAuthClient.refreshToken() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientsettokentoken", "text": "Updates the client\u2019s stored token Kind : instance method of OAuthClient Param Type Description token string = null The new token to use \u2014 can be a string, a json object or an AccessToken instance.", "title": "oAuthClient.setToken(token)"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientsetoauthoptionsoptions", "text": "Updates the OAuth informations Kind : instance method of OAuthClient Param Type Description options object Map of OAuth options", "title": "oAuthClient.setOAuthOptions(options)"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientresetclient", "text": "Reset the current OAuth client Kind : instance method of OAuthClient", "title": "oAuthClient.resetClient()"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientsetpassphraseflagshipparams-object", "text": "This method should be used in flagship app onboarding process to finalize the cozy creation by setting the user password into the cozy-stack More info: https://docs.cozy.io/en/cozy-stack/settings/#post-settingspassphraseflagship Kind : instance method of OAuthClient Returns : object - token - The OAauth token Param Type Description params object parameters needed to set passphrase params.registerToken string registration token provided by the onboarding link params.passwordHash string hash of the master password params.hint string hint for the master password params.key string key (crypted) used for the vault encryption params.publicKey string public key used for sharing ciphers from the vault params.privateKey string private key (crypted) used for sharing ciphers from the vault params.iterations string number of KDF iterations applied when hashing the master password", "title": "oAuthClient.setPassphraseFlagship(params) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientcheckforrevocation-promiseboolean", "text": "Check if the OAuth client\u2019s has been revoked. If this is the case, call the onRevocationChange callback Kind : instance method of OAuthClient Returns : Promise. - A Promise that resolves to false if client is still valid, or true if it has been revoked.", "title": "oAuthClient.checkForRevocation() \u21d2 Promise.<boolean>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientscollection", "text": "Implements DocumentCollection API to interact with the /settings/clients endpoint of the stack Kind : global class OAuthClientsCollection .all(options) \u21d2 object .get(id) \u21d2 object .destroy(oauthClient) \u21d2 Object", "title": "OAuthClientsCollection"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientscollectionalloptions-object", "text": "Fetches all OAuth clients Kind : instance method of OAuthClientsCollection Returns : object - The JSON API conformant response. Param Type Description options object Query options [options.limit] number For pagination, the number of results to return. [options.bookmark] string For bookmark-based pagination, the document _id to start from [options.keys] Array. Ids of specific clients to return (within the current page),", "title": "oAuthClientsCollection.all(options) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientscollectiongetid-object", "text": "Get an OAuth client by id Kind : instance method of OAuthClientsCollection Returns : object - JsonAPI response containing normalized client as data attribute Param Type Description id string The client id.", "title": "oAuthClientsCollection.get(id) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientscollectiondestroyoauthclient-object", "text": "Destroys the OAuth client on the server Kind : instance method of OAuthClientsCollection Returns : Object - The deleted client Param Type Description oauthClient object The io.cozy.oauth.clients document to destroy", "title": "oAuthClientsCollection.destroy(oauthClient) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollection", "text": "Implements DocumentCollection API along with specific methods for io.cozy.permissions . Kind : global class PermissionCollection .create(permission) .add(document, permission) \u21d2 Promise ~~ .findApps() ~~ .createSharingLink(document, options) .fetchPermissionsByLink(permissions) .fetchAllLinks(document) \u21d2 object .revokeSharingLink(document)", "title": "PermissionCollection"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollectioncreatepermission", "text": "Create a new set of permissions It can also associates one or more codes to it, via the codes parameter Kind : instance method of PermissionCollection See : https://docs.cozy.io/en/cozy-stack/permissions/#post-permissions Param Type Description permission object permission to create permission.codes string A comma separed list of values (defaulted to code) permission.ttl string Make the codes expire after a delay (bigduration format) permission.tiny boolean If set to true then the generated shortcode will be 6 digits Cozy-Stack has a few conditions to be able to use this tiny shortcode ATM you have to specifiy a ttl < 1h, but it can change. see https://docs.cozy.io/en/cozy-stack/permissions/#post-permissions for exact informations bigduration format: https://github.com/justincampbell/bigduration/blob/master/README.md", "title": "permissionCollection.create(permission)"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollectionadddocument-permission-promise", "text": "Adds a permission to the given document. Document type must be io.cozy.apps , io.cozy.konnectors or io.cozy.permissions Kind : instance method of PermissionCollection Param Type Description document object Document which receives the permission permission object Describes the permission Example const permissions = await client .collection('io.cozy.permissions') .add(konnector, { folder: { type: 'io.cozy.files', verbs: ['GET', 'PUT'], values: [`io.cozy.files.bc57b60eb2954537b0dcdc6ebd8e9d23`] } })", "title": "permissionCollection.add(document, permission) \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollectionfindapps", "text": "Deprecated Kind : instance method of PermissionCollection", "title": "~~permissionCollection.findApps()~~"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollectioncreatesharinglinkdocument-options", "text": "Create a share link Kind : instance method of PermissionCollection Param Type Description document Object cozy document options object options options.verbs Array. explicit permissions to use", "title": "permissionCollection.createSharingLink(document, options)"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollectionfetchpermissionsbylinkpermissions", "text": "Follow the next link to fetch the next permissions Kind : instance method of PermissionCollection Param Type Description permissions object JSON-API based permissions document", "title": "permissionCollection.fetchPermissionsByLink(permissions)"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollectionfetchalllinksdocument-object", "text": "Kind : instance method of PermissionCollection Returns : object - with all the permissions Param Type Description document object Cozy doc", "title": "permissionCollection.fetchAllLinks(document) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#permissioncollectionrevokesharinglinkdocument", "text": "Destroy a sharing link and the related permissions Kind : instance method of PermissionCollection Param Type Description document object document to revoke sharing link", "title": "permissionCollection.revokeSharingLink(document)"}, {"location": "cozy-client/api/cozy-stack-client/#promisecache", "text": "Caches promises while they are pending Serves to dedupe equal queries requested at the same time Kind : global class PromiseCache .pending : Object. .exec(promiseFunc, keyFunc) \u21d2 Promise. .get(keyFunc) \u21d2 Promise | null", "title": "PromiseCache"}, {"location": "cozy-client/api/cozy-stack-client/#promisecachepending-objectstring-promise", "text": "Holds pending promises Kind : instance property of PromiseCache", "title": "promiseCache.pending : Object.<string, Promise>"}, {"location": "cozy-client/api/cozy-stack-client/#promisecacheexecpromisefunc-keyfunc-promiset", "text": "Tries to find a pending promise corresponding to the result of keyFunc - If not found, promiseFunc is executed and the resulting promise is stored while it\u2019s pending - If found, it is immediately returned Kind : instance method of PromiseCache Param Type Description promiseFunc function Not executed only if an \u201cequal\u201d promise is already pending. keyFunc function Returns a key to find in cache to find a pending promise.", "title": "promiseCache.exec(promiseFunc, keyFunc) \u21d2 Promise.<T>"}, {"location": "cozy-client/api/cozy-stack-client/#promisecachegetkeyfunc-promise-null", "text": "Kind : instance method of PromiseCache Param Type Description keyFunc function Returns a key to find in cache to find a pending promise.", "title": "promiseCache.get(keyFunc) \u21d2 Promise | null"}, {"location": "cozy-client/api/cozy-stack-client/#settingscollection", "text": "Implements DocumentCollection API to interact with the /settings endpoint of the stack Kind : global class SettingsCollection .get(id) \u21d2 object .update(document)", "title": "SettingsCollection"}, {"location": "cozy-client/api/cozy-stack-client/#settingscollectiongetid-object", "text": "async get - Calls a route on the /settings API Kind : instance method of SettingsCollection Returns : object - The response from the route Param Type Description id string The setting id to call, eg io.cozy.settings.instance for instance route or io.cozy.settings.context for context route", "title": "settingsCollection.get(id) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#settingscollectionupdatedocument", "text": "Updates a settings document Kind : instance method of SettingsCollection Param Type Description document object Document to update. Do not forget the _id attribute", "title": "settingsCollection.update(document)"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollection", "text": "Implements the DocumentCollection API along with specific methods for io.cozy.sharings . Kind : global class SharingCollection .get(id) \u21d2 Sharing .create(params) ~~ .share(document, recipients, sharingType, description, [previewPath]) ~~ .getDiscoveryLink(sharingId, sharecode) \u21d2 string .addRecipients(options) .revokeRecipient(sharing, recipientIndex) .revokeGroup(sharing, groupIndex) .revokeSelf(sharing) .revokeAllRecipients(sharing)", "title": "SharingCollection"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectiongetid-sharing", "text": "Fetches a sharing by id Kind : instance method of SharingCollection Returns : Sharing - sharing Param Type Description id string Sharing\u2019s id", "title": "sharingCollection.get(id) \u21d2 Sharing"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectioncreateparams", "text": "Creates a new Sharing. See https://docs.cozy.io/en/cozy-stack/sharing/#post-sharings Kind : instance method of SharingCollection Param Type Description params object Sharing params params.document Sharing The document to share params.description string Description of the sharing [params.previewPath] string The preview path [params.rules] Array. The rules defined to the sharing. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing [params.recipients] Array. Recipients to add to the sharings (will have the same permissions given by the rules defined by the sharing ) [params.readOnlyRecipients] Array. Recipients to add to the sharings with only read only access [params.openSharing] boolean If someone else than the owner can add a recipient to the sharing [params.appSlug] string Slug of the targeted app", "title": "sharingCollection.create(params)"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectionsharedocument-recipients-sharingtype-description-previewpath", "text": "Deprecated Kind : instance method of SharingCollection Param Type Default Description document Sharing The document to share. Should have and _id and a name. recipients Array A list of io.cozy.contacts sharingType string If \u201ctwo-way\u201d, will set the open_sharing attribute to true description string Describes the sharing [previewPath] string null Relative URL of the sharings preview page", "title": "~~sharingCollection.share(document, recipients, sharingType, description, [previewPath])~~"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectiongetdiscoverylinksharingid-sharecode-string", "text": "getDiscoveryLink - Returns the URL of the page that can be used to accept a sharing. See https://docs.cozy.io/en/cozy-stack/sharing/#get-sharingssharing-iddiscovery Kind : instance method of SharingCollection Param Type Description sharingId string Id of the sharing sharecode string Code of the sharing", "title": "sharingCollection.getDiscoveryLink(sharingId, sharecode) \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectionaddrecipientsoptions", "text": "Add an array of contacts to the Sharing Kind : instance method of SharingCollection Param Type Description options object Object options.document Sharing Sharing Object [options.recipients] Array. Recipients to add to the sharing [options.readOnlyRecipients] Array. Recipients to add to the sharings with only read only access", "title": "sharingCollection.addRecipients(options)"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectionrevokerecipientsharing-recipientindex", "text": "Revoke only one recipient of the sharing. Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Object recipientIndex number Index of this recipient in the members array of the sharing", "title": "sharingCollection.revokeRecipient(sharing, recipientIndex)"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectionrevokegroupsharing-groupindex", "text": "Revoke only one group of the sharing. Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Object groupIndex number Index of this group in the groups array of the sharing", "title": "sharingCollection.revokeGroup(sharing, groupIndex)"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectionrevokeselfsharing", "text": "Remove self from the sharing. Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Object", "title": "sharingCollection.revokeSelf(sharing)"}, {"location": "cozy-client/api/cozy-stack-client/#sharingcollectionrevokeallrecipientssharing", "text": "Revoke the sharing for all the members. Must be called from the owner\u2019s cozy Kind : instance method of SharingCollection Param Type Description sharing Sharing Sharing Objects", "title": "sharingCollection.revokeAllRecipients(sharing)"}, {"location": "cozy-client/api/cozy-stack-client/#triggercollection", "text": "Implements DocumentCollection API along with specific methods for io.cozy.triggers . Kind : global class TriggerCollection .all(options) \u21d2 Object .create(attributes) \u21d2 object .destroy(document) \u21d2 object .find(selector, options) \u21d2 Object .launch(trigger) \u21d2 object .update(trigger) \u21d2 object", "title": "TriggerCollection"}, {"location": "cozy-client/api/cozy-stack-client/#triggercollectionalloptions-object", "text": "Get the list of triggers. Kind : instance method of TriggerCollection Returns : Object - The JSON API conformant response. Throws : FetchError See : https://docs.cozy.io/en/cozy-stack/jobs/#get-jobstriggers Param Type Description options Object The fetch options: Worker allow to filter only triggers associated with a specific worker.", "title": "triggerCollection.all(options) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#triggercollectioncreateattributes-object", "text": "Creates a Trigger document Kind : instance method of TriggerCollection Returns : object - Stack response, containing trigger document under data attribute. See : https://docs.cozy.io/en/cozy-stack/jobs/#post-jobstriggers Param Type Description attributes object Trigger\u2019s attributes", "title": "triggerCollection.create(attributes) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#triggercollectiondestroydocument-object", "text": "Deletes a trigger Kind : instance method of TriggerCollection Returns : object - The deleted document See : https://docs.cozy.io/en/cozy-stack/jobs/#delete-jobstriggerstrigger-id Param Type Description document object The trigger to delete \u2014 must have an _id field", "title": "triggerCollection.destroy(document) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#triggercollectionfindselector-options-object", "text": "Be warned, ATM /jobs/triggers does not return the same informations than /data/io.cozy.triggers (used by the super.find method). See https://github.com/cozy/cozy-stack/pull/2010 Kind : instance method of TriggerCollection Returns : Object - The JSON API conformant response. Throws : FetchError Param Type Description selector object Which kind of worker options object Options", "title": "triggerCollection.find(selector, options) \u21d2 Object"}, {"location": "cozy-client/api/cozy-stack-client/#triggercollectionlaunchtrigger-object", "text": "Force given trigger execution. Kind : instance method of TriggerCollection Returns : object - Stack response, containing job launched by trigger, under data attribute. See : https://docs.cozy.io/en/cozy-stack/jobs/#post-jobstriggerstrigger-idlaunch Param Type Description trigger object Trigger to launch", "title": "triggerCollection.launch(trigger) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#triggercollectionupdatetrigger-object", "text": "Updates a Trigger document. Only updatable attributes plus _id are allowed. Kind : instance method of TriggerCollection Returns : object - Stack response, containing resulting trigger document under data attribute. Param Type Description trigger object Trigger\u2019s attributes to update + id", "title": "triggerCollection.update(trigger) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#dontthrownotfounderror-object", "text": "Handler for error response which return a empty value for \u201cnot found\u201d error Kind : global constant Returns : object - JsonAPI response with empty data in case of \u201cnot found\u201d error. Param Type Description error Error An error data Array | object | null Data to return in case of \u201cnot found\u201d error", "title": "dontThrowNotFoundError \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#isindexnotfounderror-array-null", "text": "Helper to identify an index not found error Kind : global constant Returns : Array | null - - Whether or not the error is an index not found error Param Type Description error Error An error", "title": "isIndexNotFoundError \u21d2 Array | null"}, {"location": "cozy-client/api/cozy-stack-client/#isindexconflicterror-array-null", "text": "Helper to identify an index conflict Kind : global constant Returns : Array | null - - Whether or not the error is an index conflict error Param Type Description error Error An error", "title": "isIndexConflictError \u21d2 Array | null"}, {"location": "cozy-client/api/cozy-stack-client/#isindexnotusedwarning-array-null", "text": "Helper to identify a not used index Kind : global constant Returns : Array | null - Whether or not this is a not used index warning Param Type Description warning string The warning returned by CouchDB", "title": "isIndexNotUsedWarning \u21d2 Array | null"}, {"location": "cozy-client/api/cozy-stack-client/#isnousableindexerror-array-null", "text": "Helper to identify a no usable index error Kind : global constant Returns : Array | null - - Whether or not the error is a no usable index error Param Type Description error Error An error", "title": "isNoUsableIndexError \u21d2 Array | null"}, {"location": "cozy-client/api/cozy-stack-client/#isdocumentupdateconflict-array-null", "text": "Helper to identify a document conflict Kind : global constant Returns : Array | null - - Whether or not the error is a document conflict error Param Type Description error Error An error", "title": "isDocumentUpdateConflict \u21d2 Array | null"}, {"location": "cozy-client/api/cozy-stack-client/#isfile-boolean", "text": "Returns true when parameter has type directory, file or has _type io.cozy.files Kind : global constant Returns : boolean - true when objects has type directory, file or has _type io.cozy.files or false Param Type Description doc object The document whose type is checked [doc._type] string The document\u2019s doctype [doc.type] 'directory' | 'file' The io.cozy-files document type", "title": "isFile \u21d2 boolean"}, {"location": "cozy-client/api/cozy-stack-client/#isdirectory-boolean", "text": "Returns true when parameters has type directory Kind : global constant Returns : boolean - true when parameters has type directory or false Param Type Description args object File args.type string The type of the file", "title": "isDirectory \u21d2 boolean"}, {"location": "cozy-client/api/cozy-stack-client/#getillegalcharacters-string", "text": "Get the list of illegal characters in the file name Kind : global constant Returns : string - illegal characters separated by spaces Access : public Param Type Description name string the file name", "title": "getIllegalCharacters \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#makekeyfrompartialfilter-string", "text": "Process a partial filter to generate a string key Kind : global constant Returns : string - - The string key of the processed partial filter Param Type Description condition object An object representing the partial filter or a sub-condition of the partial filter", "title": "makeKeyFromPartialFilter \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#getindexnamefromfields-string", "text": "Name an index, based on its indexed fields and partial filter. It follows this naming convention: by_{indexed_field1}_and_{indexed_field2}_filter_({partial_filter.key1}_{partial_filter.value1})_and_({partial_filter.key2}_{partial_filter.value2}) Kind : global constant Returns : string - The index name, built from the fields Param Type Description fields Array. The indexed fields [partialFilter] object The partial filter", "title": "getIndexNameFromFields \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#transformsort-mangosort", "text": "Transform sort into Array Kind : global constant Param Type Description sort MangoSort The sorting parameters", "title": "transformSort \u21d2 MangoSort"}, {"location": "cozy-client/api/cozy-stack-client/#getindexfields-array", "text": "Compute fields that should be indexed for a mango query to work Kind : global constant Returns : Array - - Fields to index", "title": "getIndexFields \u21d2 Array"}, {"location": "cozy-client/api/cozy-stack-client/#ismatchingindex-boolean", "text": "Check if an index is matching the given fields Kind : global constant Returns : boolean - True if the index is matches the given fields Param Type Description index DesignDoc The index to check fields Array The fields that the index must have partialFilter object An optional partial filter", "title": "isMatchingIndex \u21d2 boolean"}, {"location": "cozy-client/api/cozy-stack-client/#makeoperatorsexplicit-object", "text": "Transform a query to make all operators explicit Kind : global constant Returns : object - - The transformed query with all operators explicit Param Type Description query object The query to transform reverseEq boolean If true, $eq will be transformed to $ne (useful for manage $nor)", "title": "makeOperatorsExplicit \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#getpermissionsfor-object", "text": "Build a permission set Kind : global constant Returns : object - permissions object that can be sent through /permissions/* Param Type Description document Object cozy document publicLink boolean are the permissions for a public link ? options object options options.verbs Array. explicit permissions to use", "title": "getPermissionsFor \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#normalizesettings-object", "text": "Normalizing a document for SettingsCollection context Kind : global constant Returns : object - normalized document Param Type Description doc object Document to normalize", "title": "normalizeSettings \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#getsharingrules-arrayrule", "text": "Rules determine the behavior of the sharing when changes are made to the shared document See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global constant Returns : Array. - The rules that define how to share the document Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing", "title": "getSharingRules \u21d2 Array.<Rule>"}, {"location": "cozy-client/api/cozy-stack-client/#forcedownload", "text": "Force a download from the given href Kind : global constant Param Type Description href string The link to download filename string The file name to download", "title": "forceDownload"}, {"location": "cozy-client/api/cozy-stack-client/#encodepath-string", "text": "Encode a path for use in a URL by encoding special characters but keeping slashes Kind : global constant Returns : string - - The encoded path with special characters for parentheses and spaces Param Type Description path string The path to encode", "title": "encodePath \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#getaccesstoken-string", "text": "Get the access token string Kind : global function Returns : string - token See : CozyStackClient.getAccessToken", "title": "getAccessToken() \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#getaccesstoken-string_1", "text": "Get the app token string Kind : global function Returns : string - token See : CozyStackClient.getAccessToken", "title": "getAccessToken() \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#geticonurl", "text": "Get Icon URL using blob mechanism if OAuth connected or using preloaded url when blob not needed Kind : global function", "title": "getIconURL()"}, {"location": "cozy-client/api/cozy-stack-client/#handlenoroperatorconditions-array", "text": "Handle the $nor operator in a query CouchDB transforms $nor into $and with $ne operators Kind : global function Returns : Array - - The reversed conditions Param Type Description conditions Array The conditions inside the $nor operator", "title": "handleNorOperator(conditions) \u21d2 Array"}, {"location": "cozy-client/api/cozy-stack-client/#garbagecollect", "text": "Delete outdated results from cache Kind : global function", "title": "garbageCollect()"}, {"location": "cozy-client/api/cozy-stack-client/#memoize", "text": "Memoize with maxDuration and custom key Kind : global function", "title": "memoize()"}, {"location": "cozy-client/api/cozy-stack-client/#getsharingrulesforphotosalbumdocument-sharingtype-arrayrule", "text": "Compute the rules that define how to share a Photo Album. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global function Returns : Array. - The rules that define how to share a Photo Album Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing", "title": "getSharingRulesForPhotosAlbum(document, sharingType) \u21d2 Array.<Rule>"}, {"location": "cozy-client/api/cozy-stack-client/#getsharingpolicyforreferencedfilessharingtype-sharingpolicy", "text": "Compute the sharing policy for a ReferencedFile based on its sharing type Kind : global function Returns : SharingPolicy - The sharing policy for the ReferencedFile Param Type Description sharingType SharingType The type of the sharing", "title": "getSharingPolicyForReferencedFiles(sharingType) \u21d2 SharingPolicy"}, {"location": "cozy-client/api/cozy-stack-client/#getsharingpolicyforalbumsharingtype-arrayrule", "text": "Compute the sharing policy for an Album based on its sharing type Kind : global function Returns : Array. - The sharing policy for the Album Param Type Description sharingType SharingType The type of the sharing", "title": "getSharingPolicyForAlbum(sharingType) \u21d2 Array.<Rule>"}, {"location": "cozy-client/api/cozy-stack-client/#getsharingrulesforfiledocument-sharingtype-arrayrule", "text": "Compute the rules that define how to share a File. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global function Returns : Array. - The rules that define how to share a File Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing", "title": "getSharingRulesForFile(document, sharingType) \u21d2 Array.<Rule>"}, {"location": "cozy-client/api/cozy-stack-client/#getsharingpolicyforfiledocument-sharingtype-sharingpolicy", "text": "Compute the sharing policy for a File based on its sharing type Kind : global function Returns : SharingPolicy - The sharing policy for the File Param Type Description document Sharing The document to share. Should have and _id and a name sharingType SharingType The type of the sharing", "title": "getSharingPolicyForFile(document, sharingType) \u21d2 SharingPolicy"}, {"location": "cozy-client/api/cozy-stack-client/#getsharingrulesfororganizationsdocument-arrayrule", "text": "Compute the rules that define how to share an Organization. See https://docs.cozy.io/en/cozy-stack/sharing-design/#description-of-a-sharing Kind : global function Returns : Array. - The rules that define how to share an Organization Param Type Description document Sharing The document to share. Should have and _id and a name", "title": "getSharingRulesForOrganizations(document) \u21d2 Array.<Rule>"}, {"location": "cozy-client/api/cozy-stack-client/#torelationshipitemitem-relationshipitem", "text": "Compute the RelationshipItem that can be referenced as a sharing recipient Kind : global function Returns : RelationshipItem - The RelationshipItem that can be referenced as a sharing recipient Param Type Description item Recipient The recipient of a sharing", "title": "toRelationshipItem(item) \u21d2 RelationshipItem"}, {"location": "cozy-client/api/cozy-stack-client/#getcozyurl", "text": "Get a uniform formatted URL and SSL information according to a provided URL Kind : global function", "title": "getCozyURL()"}, {"location": "cozy-client/api/cozy-stack-client/#joinpathstart-end-string", "text": "Join two paths together ensuring there is only one slash between them Kind : global function Returns : string - The joined path Param Type Description start string The starting part of the path end string The ending part of the path", "title": "joinPath(start, end) \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#fetchchangesreturnvalue-promisefetchchangesreturnvalue", "text": "Use Couch _changes API Deleted and design docs are filtered by default, thus documents are retrieved in the response (include_docs is set to true in the parameters of _changes). You should use fetchChangesRaw to have low level control on _changes parameters. Kind : global typedef Param Type Description couchOptions object Couch options for changes [couchOptions.since] string Bookmark telling CouchDB from which point in time should changes be returned [couchOptions.doc_ids] Array. Only return changes for a subset of documents options object Further options on the returned documents. By default, it is set to [options.includeDesign] boolean Whether to include changes from design docs (needs include_docs to be true) [options.includeDeleted] boolean Whether to include changes for deleted documents (needs include_docs to be true) Properties Name Type newLastSeq string documents Array.", "title": "FetchChangesReturnValue \u21d2 Promise.<FetchChangesReturnValue>"}, {"location": "cozy-client/api/cozy-stack-client/#iocozyfolder-object", "text": "Folder Kind : global typedef", "title": "IOCozyFolder : object"}, {"location": "cozy-client/api/cozy-stack-client/#specificfileattributesforkonnector-object", "text": "Specific file attributes for creation for konnector Kind : global typedef Properties Name Type Description sourceAccount string the id of the source account used by a konnector sourceAccountIdentifier string the unique identifier of the account targeted by the connector", "title": "SpecificFileAttributesForKonnector : object"}, {"location": "cozy-client/api/cozy-stack-client/#couchdbviewcursor-arraystring-string", "text": "Cursor used for Mango queries pagination Kind : global typedef", "title": "CouchDBViewCursor : Array.<string> | string"}, {"location": "cozy-client/api/cozy-stack-client/#directoryattributes-object", "text": "Attributes used for directory creation Kind : global typedef Properties Name Type Description dirId string Id of the parent directory. name boolean Name of the created directory. executable boolean Indicates whether the file will be executable. [metadata] object io.cozy.files.metadata to attach to the directory", "title": "DirectoryAttributes : object"}, {"location": "cozy-client/api/cozy-stack-client/#fileattributes-object", "text": "Attributes used for file creation Kind : global typedef Properties Name Type Description id string Id of the document _id string Id of the document dirId string Id of the parent directory. name string Name of the created file. lastModifiedDate Date Can be used to set the last modified date of a file. executable boolean Whether or not the file is executable encrypted boolean Whether or not the file is client-side encrypted metadata object io.cozy.files.metadata to attach to the file", "title": "FileAttributes : object"}, {"location": "cozy-client/api/cozy-stack-client/#filedocument-object", "text": "Document representing a io.cozy.files Kind : global typedef Properties Name Type Description _id string Id of the file attributes FileAttributes Attributes of the file meta object Meta relationships object Relationships referenced_by object Referenced by", "title": "FileDocument : object"}, {"location": "cozy-client/api/cozy-stack-client/#stream-object", "text": "Stream is not defined in a browser, but is on NodeJS environment Kind : global typedef", "title": "Stream : object"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclient-object", "text": "Document representing a io.cozy.oauth.clients Kind : global typedef Properties Name Type Description _id string Id of the client _type string Doctype of the client (i.e. io.cozy.oauth.clients) OAuthClient : object .doRegistration() .register() \u21d2 Promise .unregister() \u21d2 Promise .fetchInformation() \u21d2 Promise .updateInformation(information, resetSecret) \u21d2 Promise .generateStateCode() \u21d2 string .getAuthCodeURL(options) \u21d2 string .getAccessCodeFromURL(pageURL, stateCode) \u21d2 string .fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise .fetchKonnectorToken(slug) \u21d2 Promise. .fetchSessionCode() \u21d2 Promise. .fetchSessionCodeWithPassword() \u21d2 Promise. .loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> .refreshToken() \u21d2 Promise .setToken(token) .setOAuthOptions(options) .resetClient() .setPassphraseFlagship(params) \u21d2 object .checkForRevocation() \u21d2 Promise.", "title": "OAuthClient : object"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientdoregistration_1", "text": "Performs the HTTP call to register the client to the server Kind : instance method of OAuthClient", "title": "oAuthClient.doRegistration()"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientregister-promise_1", "text": "Registers the currenly configured client with the OAuth server and sets internal information from the server response Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a complete list of client information, including client ID and client secret. Throws : Error When the client is already registered", "title": "oAuthClient.register() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientunregister-promise_1", "text": "Unregisters the currenly configured client with the OAuth server. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information", "title": "oAuthClient.unregister() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchinformation-promise_1", "text": "Fetches the complete set of client information from the server after it has been registered. Kind : instance method of OAuthClient Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information", "title": "oAuthClient.fetchInformation() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientupdateinformationinformation-resetsecret-promise_1", "text": "Overwrites the client own information. This method will update both the local information and the remote information on the OAuth server. Kind : instance method of OAuthClient Returns : Promise - Resolves to a complete, updated list of client information Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Default Description information object Set of information to update. Note that some fields such as clientID can\u2019t be updated. resetSecret boolean false = false Optionnal, whether to reset the client secret or not", "title": "oAuthClient.updateInformation(information, resetSecret) \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientgeneratestatecode-string_1", "text": "Generates a random state code to be used during the OAuth process Kind : instance method of OAuthClient", "title": "oAuthClient.generateStateCode() \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientgetauthcodeurloptions-string_1", "text": "Generates the URL that the user should be sent to in order to accept the app\u2019s permissions. Kind : instance method of OAuthClient Returns : string - The URL Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description options object URL generation options options.stateCode string A random code to be included in the URl for security. Can be generated with client.generateStateCode() [options.scopes] Array An array of permission scopes for the token. [options.sessionCode] SessionCode A session code that can be used to create a session. [options.codeChallenge] string A code challenge that can be used in a PKCE verification process.", "title": "oAuthClient.getAuthCodeURL(options) \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientgetaccesscodefromurlpageurl-statecode-string_1", "text": "Retrieves the access code contained in the URL to which the user is redirected after accepting the app\u2019s permissions (the redirectURI ). Kind : instance method of OAuthClient Returns : string - The access code Throws : Error The URL should contain the same state code as the one generated with client.getAuthCodeURL() . If not, it will throw an error Param Type Description pageURL string The redirected page URL, containing the state code and the access code stateCode string The state code that was contained in the original URL the user was sent to (see client.getAuthCodeURL() )", "title": "oAuthClient.getAccessCodeFromURL(pageURL, stateCode) \u21d2 string"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchaccesstokenaccesscode-oauthoptionsarg-uri-codeverifier-promise_1", "text": "Exchanges an access code for an access token. This function does not update the client\u2019s token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with an AccessToken object. Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Param Type Description accessCode string The access code contained in the redirection URL \u2014 see client.getAccessCodeFromURL() oauthOptionsArg object \u2014 To use when OAuthClient is not yet registered (during login process) uri string \u2014 To use when OAuthClient is not yet registered (during login process) codeVerifier string \u2014 The PKCE code verifier (see https://docs.cozy.io/en/cozy-stack/auth/#pkce-extension)", "title": "oAuthClient.fetchAccessToken(accessCode, oauthOptionsArg, uri, codeVerifier) \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchkonnectortokenslug-promisestring_1", "text": "Used by the flagship application in order to create a token for the konnector with the given slug. This token can then be used by the client-side konnector to make requests to cozy-stack. The flagship app will need to use its own access token to request the konnector token. Kind : instance method of OAuthClient Returns : Promise. - - A promise that resolves with a new token Param Type Description slug string The slug of the konnector", "title": "oAuthClient.fetchKonnectorToken(slug) \u21d2 Promise.<string>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchsessioncode-promisesessioncoderes_1", "text": "Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application", "title": "oAuthClient.fetchSessionCode() \u21d2 Promise.<SessionCodeRes>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientfetchsessioncodewithpassword-promisesessioncoderes_1", "text": "Fetches a new session code. Only usable by the Flagship application Kind : instance method of OAuthClient Returns : Promise. - A promise that resolves with a new session_code Throws : NotRegisteredException When the client isn\u2019t certified to be the Flagship application", "title": "oAuthClient.fetchSessionCodeWithPassword() \u21d2 Promise.<SessionCodeRes>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientloginflagship-promiseaccesstokenrestwofactorneededressessioncoderes_1", "text": "Get OAuth access and register tokens without having to make OAuth dance This endpoint returns registration tokens only from a Flagship app, otherwise it returns a session_code that should be used in an OAuth dance More info: https://docs.cozy.io/en/cozy-stack/flagship/ More info: https://docs.cozy.io/en/cozy-stack/auth/#post-authloginflagship Kind : instance method of OAuthClient Returns : Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)> - A promise that resolves with an access token, a session_code or a 2FA code", "title": "oAuthClient.loginFlagship() \u21d2 Promise.<(AccessTokenRes|TwoFactorNeededRes|SessionCodeRes)>"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientrefreshtoken-promise_1", "text": "Retrieves a new access token by refreshing the currently used token. Kind : instance method of OAuthClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : NotRegisteredException When the client doesn\u2019t have it\u2019s registration information Error The client should already have an access token to use this function", "title": "oAuthClient.refreshToken() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientsettokentoken_1", "text": "Updates the client\u2019s stored token Kind : instance method of OAuthClient Param Type Description token string = null The new token to use \u2014 can be a string, a json object or an AccessToken instance.", "title": "oAuthClient.setToken(token)"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientsetoauthoptionsoptions_1", "text": "Updates the OAuth informations Kind : instance method of OAuthClient Param Type Description options object Map of OAuth options", "title": "oAuthClient.setOAuthOptions(options)"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientresetclient_1", "text": "Reset the current OAuth client Kind : instance method of OAuthClient", "title": "oAuthClient.resetClient()"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientsetpassphraseflagshipparams-object_1", "text": "This method should be used in flagship app onboarding process to finalize the cozy creation by setting the user password into the cozy-stack More info: https://docs.cozy.io/en/cozy-stack/settings/#post-settingspassphraseflagship Kind : instance method of OAuthClient Returns : object - token - The OAauth token Param Type Description params object parameters needed to set passphrase params.registerToken string registration token provided by the onboarding link params.passwordHash string hash of the master password params.hint string hint for the master password params.key string key (crypted) used for the vault encryption params.publicKey string public key used for sharing ciphers from the vault params.privateKey string private key (crypted) used for sharing ciphers from the vault params.iterations string number of KDF iterations applied when hashing the master password", "title": "oAuthClient.setPassphraseFlagship(params) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#oauthclientcheckforrevocation-promiseboolean_1", "text": "Check if the OAuth client\u2019s has been revoked. If this is the case, call the onRevocationChange callback Kind : instance method of OAuthClient Returns : Promise. - A Promise that resolves to false if client is still valid, or true if it has been revoked.", "title": "oAuthClient.checkForRevocation() \u21d2 Promise.<boolean>"}, {"location": "cozy-client/api/cozy-stack-client/#archivepages-object", "text": "Attributes used for create archive link by ids Kind : global typedef Properties Name Type Description id string Id of the file page number The page number. PDF files only (1 is the first page)", "title": "ArchivePages : object"}, {"location": "cozy-client/api/cozy-stack-client/#fetchchangesreturnvalue-fetchchangesreturnvalue", "text": "Use cozy-stack\u2019s _changes API for io.cozy.files Design docs are filtered by default, thus documents are retrieved in the response (includeDocs is set to true in the parameters of _changes). Deleted and trashed documents can be filtered on demand and files\u2019 paths can be requested as well. Since deleted and trashed documents are skipped by cozy-stack rather than CouchDB, when either option is set to true, the response can contain less documents than the defined limit. Thus one should rely solely on the pending result attribute to determine if more documents can be fetched or not. You should use fetchChangesRaw to call CouchDB\u2019s _changes API. Kind : global typedef Param Type Description couchOptions CouchOptions Couch options for changes options FetchChangesOptions Further options on the returned documents. By default, it is set to Properties Name Type Description since string Bookmark telling CouchDB from which point in time should changes be returned limit number The maximum number of returned documents for one call includeDocs boolean Whether or not complete documents should be returned fields Array. The list of fields that should be returned for each document includeFilePath boolean Whether to include the path of file changes (needs includeDocs to be true) skipDeleted boolean Whether to skip changes for deleted documents skipTrashed boolean Whether to skip changes for trashed documents (needs includeDocs to be true) newLastSeq string pending boolean documents Array.", "title": "FetchChangesReturnValue \u21d2 FetchChangesReturnValue"}, {"location": "cozy-client/api/cozy-stack-client/#jobdocument-object", "text": "Document representing a io.cozy.jobs Kind : global typedef Properties Name Type Description _id string Id of the job attributes.state string state of the job. Can be \u2018errored\u2019, \u2018running\u2019, \u2018queued\u2019, \u2018done\u2019 attributes.error string Error message of the job if any", "title": "JobDocument : object"}, {"location": "cozy-client/api/cozy-stack-client/#mangopartialfilter-object", "text": "Kind : global typedef", "title": "MangoPartialFilter : Object"}, {"location": "cozy-client/api/cozy-stack-client/#mangoselector-object", "text": "Kind : global typedef", "title": "MangoSelector : object"}, {"location": "cozy-client/api/cozy-stack-client/#mangosort-arrayobject", "text": "Kind : global typedef", "title": "MangoSort : Array.<object>"}, {"location": "cozy-client/api/cozy-stack-client/#mangoqueryoptions-object", "text": "Kind : global typedef Properties Name Type Description [selector] MangoSelector Selector [sort] MangoSort The sorting parameters [fields] Array. The fields to return [partialFilterFields] Array. The partial filter fields [limit] number | null For pagination, the number of results to return [skip] number | null For skip-based pagination, the number of referenced files to skip [indexId] string | null The _id of the CouchDB index to use for this request [bookmark] string | null For bookmark-based pagination, the document _id to start from [indexedFields] Array. [use_index] string Name of the index to use [execution_stats] boolean If true, we request the stats from Couch [partialFilter] MangoPartialFilter | null An optional partial filter", "title": "MangoQueryOptions : object"}, {"location": "cozy-client/api/cozy-stack-client/#designdoc-object", "text": "Attributes representing a design doc Kind : global typedef Properties Name Type Description _id string Id of the design doc. Can be named, e.g. \u2018_design/by_indexed_attribute\u2019 or not, e.g. \u2018_design/12345\u2019 language string The index language. Can be \u2018query\u2019 for mango index or \u2018javascript\u2019 for views. views object Views definition, i.e. the index. _rev string Rev version", "title": "DesignDoc : object"}, {"location": "cozy-client/api/cozy-stack-client/#sessioncode-string", "text": "Kind : global typedef", "title": "SessionCode : string"}, {"location": "cozy-client/api/cozy-stack-client/#sessioncoderes", "text": "Kind : global typedef Properties Name Type Description session_code string The value of the session code", "title": "SessionCodeRes"}, {"location": "cozy-client/api/cozy-stack-client/#accesstokenres", "text": "Kind : global typedef Properties Name Type Description email_verified_code string The email verified code to skip 2FA access_token string The OAuth access token refresh_token string The OAuth refresh token token_type string The OAuth token type scope string The OAuth scope", "title": "AccessTokenRes"}, {"location": "cozy-client/api/cozy-stack-client/#twofactorneededres", "text": "Kind : global typedef Properties Name Type Description two_factor_token string The 2FA token", "title": "TwoFactorNeededRes"}, {"location": "cozy-client/api/cozy-stack-client/#permission-permission", "text": "async getOwnPermissions - deprecated: please use fetchOwnPermissions instead Kind : global typedef Returns : Permission - permission", "title": "Permission \u21d2 Permission"}, {"location": "cozy-client/api/cozy-stack-client/#permission-permission_1", "text": "async fetchOwnPermissions - Fetches permissions Kind : global typedef Returns : Permission - permission", "title": "Permission \u21d2 Permission"}, {"location": "cozy-client/api/cozy-stack-client/#rule-object", "text": "A sharing rule Kind : global typedef Properties Name Type title string doctype string values Array [add] string [update] string [remove] string", "title": "Rule : object"}, {"location": "cozy-client/api/cozy-stack-client/#recipient-object", "text": "An io.cozy.contact Kind : global typedef", "title": "Recipient : object"}, {"location": "cozy-client/api/cozy-stack-client/#sharing-object", "text": "An io.cozy.sharings document Kind : global typedef", "title": "Sharing : object"}, {"location": "cozy-client/api/cozy-stack-client/#sharingpolicy-object", "text": "Define the add/update/remove policies for a sharing Kind : global typedef Properties Name Type add string update string remove string", "title": "SharingPolicy : object"}, {"location": "cozy-client/api/cozy-stack-client/#sharingtype-undefined-one-way-two-way", "text": "Define how a document is synced between sharing\u2019s owner and receivers. Kind : global typedef", "title": "SharingType : undefined | 'one-way' | 'two-way'"}, {"location": "cozy-client/api/cozy-stack-client/#relationshipitem-object", "text": "Define a recipient that can be used as target of a sharing Kind : global typedef Properties Name Type Description id string Recipient\u2019s ID type string Reciptient\u2019s type (should be \u2018io.cozy.contacts\u2019)", "title": "RelationshipItem : object"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclient-object", "text": "Kind : global typedef Properties Name Type Description oauthOptions object oauthOptions uri string CozyUri fetch function fetchMethod fetchJSON function fetchJSON CozyStackClient : object .collection(doctype) \u21d2 DocumentCollection .fetch(method, path, [body], [opts]) \u21d2 object .refreshToken() \u21d2 Promise .fetchJSON(method, path, body, options) \u21d2 object .setToken(token) .getAccessToken() \u21d2 string", "title": "CozyStackClient : object"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientcollectiondoctype-documentcollection_1", "text": "Creates a DocumentCollection instance. Kind : instance method of CozyStackClient Param Type Description doctype string The collection doctype.", "title": "cozyStackClient.collection(doctype) \u21d2 DocumentCollection"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientfetchmethod-path-body-opts-object_1", "text": "Fetches an endpoint in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Default Description method string The HTTP method. path string The URI. [body] object The payload. [opts] object Options for fetch", "title": "cozyStackClient.fetch(method, path, [body], [opts]) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientrefreshtoken-promise_1", "text": "Retrieves a new app token by refreshing the currently used token. Kind : instance method of CozyStackClient Returns : Promise - A promise that resolves with a new AccessToken object Throws : Error The client should already have an access token to use this function Error The client couldn\u2019t fetch a new token", "title": "cozyStackClient.refreshToken() \u21d2 Promise"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientfetchjsonmethod-path-body-options-object_1", "text": "Fetches JSON in an authorized way. Kind : instance method of CozyStackClient Throws : FetchError Param Type Description method string The HTTP method. path string The URI. body object The payload. options object Options", "title": "cozyStackClient.fetchJSON(method, path, body, options) \u21d2 object"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientsettokentoken_1", "text": "Change or set the API token Kind : instance method of CozyStackClient Param Type Description token string | AppToken | AccessToken Stack API token", "title": "cozyStackClient.setToken(token)"}, {"location": "cozy-client/api/cozy-stack-client/#cozystackclientgetaccesstoken-string_1", "text": "Get the access token string, being an oauth token or an app token Kind : instance method of CozyStackClient Returns : string - token", "title": "cozyStackClient.getAccessToken() \u21d2 string"}, {"location": "cozy-client/api/cozy-client/", "text": "cozy-client cozy-client \u00b6 Namespaces \u00b6 manifest models useMutation Classes \u00b6 Association BlockedCozyError BulkEditError CozyClient CozyLink CozyProvider HasMany HasManyInPlace HasManyTriggers HasOne HasOneInPlace InvalidCozyUrlError InvalidProtocolError InvalidRedirectLinkError Query QueryDefinition Registry StackLink Properties \u00b6 RealTimeQueries \u00b6 \u2022 RealTimeQueries : MemoExoticComponent <( options : { doctype : string }) => null > Variables \u00b6 MutationTypes \u00b6 \u2022 Const MutationTypes : Object Type declaration Name Type ADD_REFERENCED_BY string ADD_REFERENCES_TO string CREATE_DOCUMENT string DELETE_DOCUMENT string REMOVE_REFERENCED_BY string REMOVE_REFERENCES_TO string UPDATE_DOCUMENT string UPDATE_DOCUMENTS string UPLOAD_FILE string Defined in packages/cozy-client/src/queries/dsl.js:510 Mutations \u00b6 \u2022 Const Mutations : Object Type declaration Name Type addReferencedBy ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.ADD_REFERENCED_BY; referencedDocuments : any } addReferencesTo ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.ADD_REFERENCES_TO; referencedDocuments : any } createDocument ( document : any ) => { document : any ; mutationType : string = MutationTypes.CREATE_DOCUMENT } deleteDocument ( document : any ) => { document : any ; mutationType : string = MutationTypes.DELETE_DOCUMENT } removeReferencedBy ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.REMOVE_REFERENCED_BY; referencedDocuments : any } removeReferencesTo ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.REMOVE_REFERENCES_TO; referencedDocuments : any } updateDocument ( document : any ) => { document : any ; mutationType : string = MutationTypes.UPDATE_DOCUMENT } updateDocuments ( documents : any ) => { documents : any ; mutationType : string = MutationTypes.UPDATE_DOCUMENTS } uploadFile ( file : any , dirPath : any ) => { dirPath : any ; file : any ; mutationType : string = MutationTypes.UPLOAD_FILE } Defined in packages/cozy-client/src/queries/dsl.js:498 fetchPolicies \u00b6 \u2022 Const fetchPolicies : Object Use those fetch policies with to limit the number of re-fetch. example import { fetchPolicies } from 'cozy-client' const olderThan30s = fetchPolicies . olderThan ( 30 * 1000 ) < Query fetchPolicy = { olderThan30s } /> Type declaration Name Type noFetch () => boolean olderThan ( delay : number ) => Function Defined in packages/cozy-client/src/policies.js:11 useMutation \u00b6 \u2022 Const useMutation : Object Call signature \u00b6 \u25b8 ( __namedParameters? ): UseMutationReturnValue This hook manages the state during the saving of a document Parameters Name Type __namedParameters Object __namedParameters.onError any __namedParameters.onSuccess any Returns UseMutationReturnValue Type declaration Name Type propTypes { onError : Requireable <(\u2026 args : any []) => any > = PropTypes.func; onSuccess : Requireable <(\u2026 args : any []) => any > = PropTypes.func } propTypes.onError Requireable <(\u2026 args : any []) => any > propTypes.onSuccess Requireable <(\u2026 args : any []) => any > Defined in packages/cozy-client/src/hooks/useMutation.jsx:11 Functions \u00b6 Q \u00b6 \u25b8 Q ( doctype ): QueryDefinition Helper to create a QueryDefinition. Recommended way to create query definitions. example import { Q } from 'cozy-client' const qDef = Q ( 'io.cozy.todos' ) . where ({ _id : '1234' }) Parameters Name Type Description doctype string Doctype of the query definition Returns QueryDefinition Defined in packages/cozy-client/src/queries/dsl.js:394 cancelable \u00b6 \u25b8 cancelable ( promise ): CancelablePromise Wraps a promise so that it can be canceled Rejects with canceled: true as soon as cancel is called Parameters Name Type Description promise Promise < any > Promise Returns CancelablePromise Promise with .cancel method Defined in packages/cozy-client/src/utils.js:16 createFakeClient \u00b6 \u25b8 createFakeClient ( options? ): CozyClient Creates a client with pre-filled store This can be useful for demo in documentation (e.g. storybook) client.{query,save} are replaced with empty functions client.stackClient.fetchJSON is replaced with empty functions Parameters Name Type Description options Object Options options.clientFunctions any - options.clientOptions any - options.queries any - options.remote any - Returns CozyClient Defined in packages/cozy-client/src/mock.js:92 createMockClient \u00b6 \u25b8 createMockClient ( options? ): CozyClient Creates a client suitable for use in tests client.{query,save} are mocked client.stackClient.fetchJSON is mocked Parameters Name Type Description options Object Options options.clientFunctions any - options.clientOptions any - options.queries any - options.remote any - Returns CozyClient Defined in packages/cozy-client/src/mock.js:48 deconstructCozyWebLinkWithSlug \u00b6 \u25b8 deconstructCozyWebLinkWithSlug ( webLink , subDomainType? ): CozyLinkData Deconstruct the given link in order to retrieve useful data like Cozy\u2019s name, domain, or slug The given link MUST contain a slug Parameters Name Type Default value Description webLink string undefined link to deconstruct. It should be a link from a Cozy and containing a slug subDomainType SubdomainType 'flat' - Returns CozyLinkData Deconstructed link Defined in packages/cozy-client/src/helpers/urlHelper.js:64 deconstructRedirectLink \u00b6 \u25b8 deconstructRedirectLink ( redirectLink ): RedirectLinkData Deconstruct the given redirect link in order to retrieve slug, pathname and hash throws {InvalidRedirectLinkError} Thrown when redirect link is invalid Parameters Name Type Description redirectLink string redirect link to deconstruct (i.e. \u2018drive/public/#/folder/SOME_ID\u2019) Returns RedirectLinkData Deconstructed link Defined in packages/cozy-client/src/helpers/urlHelper.js:106 dehydrate \u00b6 \u25b8 dehydrate ( document ): Object Parameters Name Type document any Returns Object Defined in packages/cozy-client/src/helpers/dehydrateHelper.js:3 ensureFirstSlash \u00b6 \u25b8 ensureFirstSlash ( path ): any Parameters Name Type path any Returns any Defined in packages/cozy-client/src/helpers/urlHelper.js:1 generateWebLink \u00b6 \u25b8 generateWebLink ( options ): string generateWebLink - Construct a link to a web app This function does not get its cozy url from a CozyClient instance so it can be used to build urls that point to other Cozies than the user\u2019s own Cozy. This is useful when pointing to the Cozy of the owner of a shared note for example. Parameters Name Type Description options Object Object of options options.cozyUrl string Base URL of the cozy, eg. cozy.tools or test.mycozy.cloud options.hash string - options.pathname string - options.searchParams any [] - options.slug string - options.subDomainType string - Returns string Generated URL Defined in packages/cozy-client/src/helpers/urlHelper.js:27 getDoctypeFromOperation \u00b6 \u25b8 getDoctypeFromOperation ( operation ): any Parameters Name Type operation any Returns any Defined in packages/cozy-client/src/queries/dsl.js:474 getQueryFromState \u00b6 \u25b8 getQueryFromState ( state , queryId ): any Parameters Name Type state any queryId any Returns any Defined in packages/cozy-client/src/store/index.js:108 getReferencedBy \u00b6 \u25b8 getReferencedBy ( file , referencedBy ): Reference [] Get array of reference by an specific doctype Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced Returns Reference [] Array of references found Defined in packages/cozy-client/src/associations/helpers.js:133 getReferencedById \u00b6 \u25b8 getReferencedById ( file , referencedBy , referencedId ): Reference [] Get array of reference by an specific doctype and a specific Id of that reference Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced referencedId string Id of the referenced document Returns Reference [] Array of the reference found Defined in packages/cozy-client/src/associations/helpers.js:147 hasQueriesBeenLoaded \u00b6 \u25b8 hasQueriesBeenLoaded ( queriesResults ): boolean Returns whether queries have been loaded at least once Parameters Name Type queriesResults any Returns boolean Defined in packages/cozy-client/src/utils.js:66 hasQueryBeenLoaded \u00b6 \u25b8 hasQueryBeenLoaded ( col ): any Returns whether a query has been loaded at least once Parameters Name Type col any Returns any Defined in packages/cozy-client/src/utils.js:50 isQueriesLoading \u00b6 \u25b8 isQueriesLoading ( queriesResults ): boolean Returns whether the result of queries are loading Parameters Name Type queriesResults any Returns boolean Defined in packages/cozy-client/src/utils.js:57 isQueryLoading \u00b6 \u25b8 isQueryLoading ( col ): boolean Returns whether the result of a query (given via queryConnect or Query) is loading. Parameters Name Type col any Returns boolean Defined in packages/cozy-client/src/utils.js:39 isReferencedBy \u00b6 \u25b8 isReferencedBy ( file , referencedBy ): boolean Checks if the file is referenced by a specific doctype Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced Returns boolean If a reference is found Defined in packages/cozy-client/src/associations/helpers.js:101 isReferencedById \u00b6 \u25b8 isReferencedById ( file , referencedBy , referencedId ): boolean Checks if the file is referenced by a specific doctype and a specific Id of that reference Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced referencedId string Id of the referenced document Returns boolean If a reference is found Defined in packages/cozy-client/src/associations/helpers.js:116 queryConnect \u00b6 \u25b8 queryConnect ( querySpecs ): Function function description HOC creator to connect component to several queries in a declarative manner Parameters Name Type Description querySpecs any Definition of the queries Returns Function HOC to apply to a component Defined in packages/cozy-client/src/hoc.jsx:74 queryConnectFlat \u00b6 \u25b8 queryConnectFlat ( querySpecs ): Function function description HOC creator to connect component to several queries in a declarative manner The only difference with queryConnect is that it does not wrap the component in N component if there are N queries, only 1 extra level of nesting is introduced. Parameters Name Type Description querySpecs any Definition of the queries Returns Function HOC to apply to a component Defined in packages/cozy-client/src/hoc.jsx:90 rootCozyUrl \u00b6 \u25b8 rootCozyUrl ( url ): Promise < URL > rootCozyUrl - Get the root URL of a Cozy from more precise ones The goal is to allow users to use any URL copied from their browser as their Cozy URL rather than trying to explain to them what we expect (e.g. when requesting the Cozy URL to connect an app). If we can\u2019t get the root URL either because there\u2019s no Cozy or the domain does not exist or anything else, we\u2019ll throw an InvalidCozyUrlError. Also, since we communicate only via HTTP or HTTPS, we\u2019ll throw an InvalidProtocolError if any other protocol is used. This function expects a fully qualified URL thus with a protocol and a valid hostname. If your application accepts Cozy intances as input (e.g. claude when the Cozy can be found at https://claude.mycozy.cloud ), it is your responsibility to add the appropriate domain to the hostname before calling this function. Examples: getting the root URL when your user gives you its instance name const userInput = \u2018claude\u2019 const rootUrl = await rootCozyUrl(new URL( https://${userInput}.mycozy.cloud )) // \u2192 returns new URL(\u2018https://claude.mycozy.cloud\u2019) getting the root URL when your user gives you a Cozy Drive URL const userInput = \u2018https://claude-drive.mycozy.cloud/#/folder/io.cozy.files.root-dir\u2019 const rootUrl = await rootCozyUrl(new URL(userInput)) // \u2192 returns new URL(\u2018https://claude.mycozy.cloud\u2019) getting the root URL when the Cozy uses nested sub-domains const userInput = \u2018http://photos.camille.nimbus.com:8080/#/album/1234567890\u2019 const rootCozyUrl = await rootCozyUrl(new URL(userInput)) // \u2192 returns new URL(\u2018http://camille.nimbus.com:8080\u2019) Parameters Name Type Description url URL The URL from which we\u2019ll try to get the root Cozy URL Returns Promise < URL > The root Cozy URL Defined in packages/cozy-client/src/helpers/urlHelper.js:268 useAppLinkWithStoreFallback \u00b6 \u25b8 useAppLinkWithStoreFallback ( slug , client , path? ): Object Parameters Name Type Default value slug any undefined client any undefined path string '' Returns Object Name Type fetchStatus string isInstalled boolean url any Defined in packages/cozy-client/src/hooks/useAppLinkWithStoreFallback.jsx:9 useAppsInMaintenance \u00b6 \u25b8 useAppsInMaintenance (): \"io.cozy.apps\" [] Returns all apps in maintenance Returns \"io.cozy.apps\" [] An array with all apps in maintenance Defined in packages/cozy-client/src/hooks/useAppsInMaintenance.jsx:12 useCapabilities \u00b6 \u25b8 useCapabilities ( client ): Object Parameters Name Type client any Returns Object Name Type capabilities undefined fetchStatus string Defined in packages/cozy-client/src/hooks/useCapabilities.jsx:5 useClient \u00b6 \u25b8 useClient (): CozyClient Returns the cozy client from the context Returns CozyClient Current cozy client Defined in packages/cozy-client/src/hooks/useClient.js:9 useFetchShortcut \u00b6 \u25b8 useFetchShortcut ( client , id ): Object Parameters Name Type client any id any Returns Object Name Type fetchStatus string shortcutImg any shortcutInfos any Defined in packages/cozy-client/src/hooks/useFetchShortcut.jsx:8 useInstanceInfo \u00b6 \u25b8 useInstanceInfo (): InstanceInfo Retrieve intance info like context, uuid, disk usage etc Returns InstanceInfo Defined in packages/cozy-client/src/hooks/useInstanceInfo.js:11 useQueries \u00b6 \u25b8 useQueries ( querySpecs ): Object Parameters Name Type querySpecs any Returns Object Defined in packages/cozy-client/src/hooks/useQuery.js:93 useQuery \u00b6 \u25b8 useQuery ( queryDefinition , options ): UseQueryReturnValue Fetches a queryDefinition and returns the queryState Parameters Name Type Description queryDefinition QueryDefinition () => QueryDefinition options QueryOptions Options created with Q() Returns UseQueryReturnValue Defined in packages/cozy-client/src/hooks/useQuery.js:28 useQueryAll \u00b6 \u25b8 useQueryAll ( queryDefinition , options ): UseQueryReturnValue Fetches a queryDefinition and run fetchMore on the query until the query is fully loaded Parameters Name Type Description queryDefinition QueryDefinition Definition created with Q() options QueryOptions Options created with Q() Returns UseQueryReturnValue Defined in packages/cozy-client/src/hooks/useQueryAll.jsx:14 useSettings \u00b6 \u25b8 useSettings < T >( slug , keys ): UseSettingsReturnValue < T > Query the cozy-app settings corresponding to the given slug and return: the values corresponding to the given keys the save() method that can be used to edit the setting\u2019s value the query that manages the state during the fetching of the setting the mutation that manages the state during the saving of the setting Type parameters \u00b6 Name Type T extends string Parameters Name Type Description slug string the cozy-app\u2019s slug containing the setting (special cases are: \u2018instance\u2019 for global settings and \u2018passwords\u2019 for bitwarden settings) keys T [] The name of the setting to retrieve Returns UseSettingsReturnValue < T > Defined in packages/cozy-client/src/hooks/useSetting.js:24 withClient \u00b6 \u25b8 withClient ( WrappedComponent ): Function function description HOC to provide client from context as prop Parameters Name Type Description WrappedComponent Component < any , any , any > wrapped component Returns Function Component that will receive client as prop Defined in packages/cozy-client/src/hoc.jsx:16 withMutation \u00b6 \u25b8 withMutation ( mutation , options? ): Function Parameters Name Type mutation any options Object Returns Function Defined in packages/cozy-client/src/withMutation.jsx:8 withMutations \u00b6 \u25b8 withMutations (\u2026 mutations ): Function function description HOC to provide mutations to components. Needs client in context or as prop. deprecated Prefer to use withClient and access directly the client. Parameters Name Type Description ...mutations Function [] One ore more mutations, which are function taking CozyClient as parameter and returning an object containing one or more mutations as attributes. Returns Function Component that will receive mutations as props Defined in packages/cozy-client/src/withMutations.jsx:24", "title": "Cozy Client API"}, {"location": "cozy-client/api/cozy-client/#cozy-client", "text": "", "title": "cozy-client"}, {"location": "cozy-client/api/cozy-client/#namespaces", "text": "manifest models useMutation", "title": "Namespaces"}, {"location": "cozy-client/api/cozy-client/#classes", "text": "Association BlockedCozyError BulkEditError CozyClient CozyLink CozyProvider HasMany HasManyInPlace HasManyTriggers HasOne HasOneInPlace InvalidCozyUrlError InvalidProtocolError InvalidRedirectLinkError Query QueryDefinition Registry StackLink", "title": "Classes"}, {"location": "cozy-client/api/cozy-client/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/#realtimequeries", "text": "\u2022 RealTimeQueries : MemoExoticComponent <( options : { doctype : string }) => null >", "title": "RealTimeQueries"}, {"location": "cozy-client/api/cozy-client/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/#mutationtypes", "text": "\u2022 Const MutationTypes : Object Type declaration Name Type ADD_REFERENCED_BY string ADD_REFERENCES_TO string CREATE_DOCUMENT string DELETE_DOCUMENT string REMOVE_REFERENCED_BY string REMOVE_REFERENCES_TO string UPDATE_DOCUMENT string UPDATE_DOCUMENTS string UPLOAD_FILE string Defined in packages/cozy-client/src/queries/dsl.js:510", "title": "MutationTypes"}, {"location": "cozy-client/api/cozy-client/#mutations", "text": "\u2022 Const Mutations : Object Type declaration Name Type addReferencedBy ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.ADD_REFERENCED_BY; referencedDocuments : any } addReferencesTo ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.ADD_REFERENCES_TO; referencedDocuments : any } createDocument ( document : any ) => { document : any ; mutationType : string = MutationTypes.CREATE_DOCUMENT } deleteDocument ( document : any ) => { document : any ; mutationType : string = MutationTypes.DELETE_DOCUMENT } removeReferencedBy ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.REMOVE_REFERENCED_BY; referencedDocuments : any } removeReferencesTo ( document : any , referencedDocuments : any ) => { document : any ; mutationType : string = MutationTypes.REMOVE_REFERENCES_TO; referencedDocuments : any } updateDocument ( document : any ) => { document : any ; mutationType : string = MutationTypes.UPDATE_DOCUMENT } updateDocuments ( documents : any ) => { documents : any ; mutationType : string = MutationTypes.UPDATE_DOCUMENTS } uploadFile ( file : any , dirPath : any ) => { dirPath : any ; file : any ; mutationType : string = MutationTypes.UPLOAD_FILE } Defined in packages/cozy-client/src/queries/dsl.js:498", "title": "Mutations"}, {"location": "cozy-client/api/cozy-client/#fetchpolicies", "text": "\u2022 Const fetchPolicies : Object Use those fetch policies with to limit the number of re-fetch. example import { fetchPolicies } from 'cozy-client' const olderThan30s = fetchPolicies . olderThan ( 30 * 1000 ) < Query fetchPolicy = { olderThan30s } /> Type declaration Name Type noFetch () => boolean olderThan ( delay : number ) => Function Defined in packages/cozy-client/src/policies.js:11", "title": "fetchPolicies"}, {"location": "cozy-client/api/cozy-client/#usemutation", "text": "\u2022 Const useMutation : Object", "title": "useMutation"}, {"location": "cozy-client/api/cozy-client/#call-signature", "text": "\u25b8 ( __namedParameters? ): UseMutationReturnValue This hook manages the state during the saving of a document Parameters Name Type __namedParameters Object __namedParameters.onError any __namedParameters.onSuccess any Returns UseMutationReturnValue Type declaration Name Type propTypes { onError : Requireable <(\u2026 args : any []) => any > = PropTypes.func; onSuccess : Requireable <(\u2026 args : any []) => any > = PropTypes.func } propTypes.onError Requireable <(\u2026 args : any []) => any > propTypes.onSuccess Requireable <(\u2026 args : any []) => any > Defined in packages/cozy-client/src/hooks/useMutation.jsx:11", "title": "Call signature"}, {"location": "cozy-client/api/cozy-client/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/#q", "text": "\u25b8 Q ( doctype ): QueryDefinition Helper to create a QueryDefinition. Recommended way to create query definitions. example import { Q } from 'cozy-client' const qDef = Q ( 'io.cozy.todos' ) . where ({ _id : '1234' }) Parameters Name Type Description doctype string Doctype of the query definition Returns QueryDefinition Defined in packages/cozy-client/src/queries/dsl.js:394", "title": "Q"}, {"location": "cozy-client/api/cozy-client/#cancelable", "text": "\u25b8 cancelable ( promise ): CancelablePromise Wraps a promise so that it can be canceled Rejects with canceled: true as soon as cancel is called Parameters Name Type Description promise Promise < any > Promise Returns CancelablePromise Promise with .cancel method Defined in packages/cozy-client/src/utils.js:16", "title": "cancelable"}, {"location": "cozy-client/api/cozy-client/#createfakeclient", "text": "\u25b8 createFakeClient ( options? ): CozyClient Creates a client with pre-filled store This can be useful for demo in documentation (e.g. storybook) client.{query,save} are replaced with empty functions client.stackClient.fetchJSON is replaced with empty functions Parameters Name Type Description options Object Options options.clientFunctions any - options.clientOptions any - options.queries any - options.remote any - Returns CozyClient Defined in packages/cozy-client/src/mock.js:92", "title": "createFakeClient"}, {"location": "cozy-client/api/cozy-client/#createmockclient", "text": "\u25b8 createMockClient ( options? ): CozyClient Creates a client suitable for use in tests client.{query,save} are mocked client.stackClient.fetchJSON is mocked Parameters Name Type Description options Object Options options.clientFunctions any - options.clientOptions any - options.queries any - options.remote any - Returns CozyClient Defined in packages/cozy-client/src/mock.js:48", "title": "createMockClient"}, {"location": "cozy-client/api/cozy-client/#deconstructcozyweblinkwithslug", "text": "\u25b8 deconstructCozyWebLinkWithSlug ( webLink , subDomainType? ): CozyLinkData Deconstruct the given link in order to retrieve useful data like Cozy\u2019s name, domain, or slug The given link MUST contain a slug Parameters Name Type Default value Description webLink string undefined link to deconstruct. It should be a link from a Cozy and containing a slug subDomainType SubdomainType 'flat' - Returns CozyLinkData Deconstructed link Defined in packages/cozy-client/src/helpers/urlHelper.js:64", "title": "deconstructCozyWebLinkWithSlug"}, {"location": "cozy-client/api/cozy-client/#deconstructredirectlink", "text": "\u25b8 deconstructRedirectLink ( redirectLink ): RedirectLinkData Deconstruct the given redirect link in order to retrieve slug, pathname and hash throws {InvalidRedirectLinkError} Thrown when redirect link is invalid Parameters Name Type Description redirectLink string redirect link to deconstruct (i.e. \u2018drive/public/#/folder/SOME_ID\u2019) Returns RedirectLinkData Deconstructed link Defined in packages/cozy-client/src/helpers/urlHelper.js:106", "title": "deconstructRedirectLink"}, {"location": "cozy-client/api/cozy-client/#dehydrate", "text": "\u25b8 dehydrate ( document ): Object Parameters Name Type document any Returns Object Defined in packages/cozy-client/src/helpers/dehydrateHelper.js:3", "title": "dehydrate"}, {"location": "cozy-client/api/cozy-client/#ensurefirstslash", "text": "\u25b8 ensureFirstSlash ( path ): any Parameters Name Type path any Returns any Defined in packages/cozy-client/src/helpers/urlHelper.js:1", "title": "ensureFirstSlash"}, {"location": "cozy-client/api/cozy-client/#generateweblink", "text": "\u25b8 generateWebLink ( options ): string generateWebLink - Construct a link to a web app This function does not get its cozy url from a CozyClient instance so it can be used to build urls that point to other Cozies than the user\u2019s own Cozy. This is useful when pointing to the Cozy of the owner of a shared note for example. Parameters Name Type Description options Object Object of options options.cozyUrl string Base URL of the cozy, eg. cozy.tools or test.mycozy.cloud options.hash string - options.pathname string - options.searchParams any [] - options.slug string - options.subDomainType string - Returns string Generated URL Defined in packages/cozy-client/src/helpers/urlHelper.js:27", "title": "generateWebLink"}, {"location": "cozy-client/api/cozy-client/#getdoctypefromoperation", "text": "\u25b8 getDoctypeFromOperation ( operation ): any Parameters Name Type operation any Returns any Defined in packages/cozy-client/src/queries/dsl.js:474", "title": "getDoctypeFromOperation"}, {"location": "cozy-client/api/cozy-client/#getqueryfromstate", "text": "\u25b8 getQueryFromState ( state , queryId ): any Parameters Name Type state any queryId any Returns any Defined in packages/cozy-client/src/store/index.js:108", "title": "getQueryFromState"}, {"location": "cozy-client/api/cozy-client/#getreferencedby", "text": "\u25b8 getReferencedBy ( file , referencedBy ): Reference [] Get array of reference by an specific doctype Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced Returns Reference [] Array of references found Defined in packages/cozy-client/src/associations/helpers.js:133", "title": "getReferencedBy"}, {"location": "cozy-client/api/cozy-client/#getreferencedbyid", "text": "\u25b8 getReferencedById ( file , referencedBy , referencedId ): Reference [] Get array of reference by an specific doctype and a specific Id of that reference Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced referencedId string Id of the referenced document Returns Reference [] Array of the reference found Defined in packages/cozy-client/src/associations/helpers.js:147", "title": "getReferencedById"}, {"location": "cozy-client/api/cozy-client/#hasqueriesbeenloaded", "text": "\u25b8 hasQueriesBeenLoaded ( queriesResults ): boolean Returns whether queries have been loaded at least once Parameters Name Type queriesResults any Returns boolean Defined in packages/cozy-client/src/utils.js:66", "title": "hasQueriesBeenLoaded"}, {"location": "cozy-client/api/cozy-client/#hasquerybeenloaded", "text": "\u25b8 hasQueryBeenLoaded ( col ): any Returns whether a query has been loaded at least once Parameters Name Type col any Returns any Defined in packages/cozy-client/src/utils.js:50", "title": "hasQueryBeenLoaded"}, {"location": "cozy-client/api/cozy-client/#isqueriesloading", "text": "\u25b8 isQueriesLoading ( queriesResults ): boolean Returns whether the result of queries are loading Parameters Name Type queriesResults any Returns boolean Defined in packages/cozy-client/src/utils.js:57", "title": "isQueriesLoading"}, {"location": "cozy-client/api/cozy-client/#isqueryloading", "text": "\u25b8 isQueryLoading ( col ): boolean Returns whether the result of a query (given via queryConnect or Query) is loading. Parameters Name Type col any Returns boolean Defined in packages/cozy-client/src/utils.js:39", "title": "isQueryLoading"}, {"location": "cozy-client/api/cozy-client/#isreferencedby", "text": "\u25b8 isReferencedBy ( file , referencedBy ): boolean Checks if the file is referenced by a specific doctype Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced Returns boolean If a reference is found Defined in packages/cozy-client/src/associations/helpers.js:101", "title": "isReferencedBy"}, {"location": "cozy-client/api/cozy-client/#isreferencedbyid", "text": "\u25b8 isReferencedById ( file , referencedBy , referencedId ): boolean Checks if the file is referenced by a specific doctype and a specific Id of that reference Parameters Name Type Description file IOCozyFile io.cozy.files document referencedBy string Doctype where document is referenced referencedId string Id of the referenced document Returns boolean If a reference is found Defined in packages/cozy-client/src/associations/helpers.js:116", "title": "isReferencedById"}, {"location": "cozy-client/api/cozy-client/#queryconnect", "text": "\u25b8 queryConnect ( querySpecs ): Function function description HOC creator to connect component to several queries in a declarative manner Parameters Name Type Description querySpecs any Definition of the queries Returns Function HOC to apply to a component Defined in packages/cozy-client/src/hoc.jsx:74", "title": "queryConnect"}, {"location": "cozy-client/api/cozy-client/#queryconnectflat", "text": "\u25b8 queryConnectFlat ( querySpecs ): Function function description HOC creator to connect component to several queries in a declarative manner The only difference with queryConnect is that it does not wrap the component in N component if there are N queries, only 1 extra level of nesting is introduced. Parameters Name Type Description querySpecs any Definition of the queries Returns Function HOC to apply to a component Defined in packages/cozy-client/src/hoc.jsx:90", "title": "queryConnectFlat"}, {"location": "cozy-client/api/cozy-client/#rootcozyurl", "text": "\u25b8 rootCozyUrl ( url ): Promise < URL > rootCozyUrl - Get the root URL of a Cozy from more precise ones The goal is to allow users to use any URL copied from their browser as their Cozy URL rather than trying to explain to them what we expect (e.g. when requesting the Cozy URL to connect an app). If we can\u2019t get the root URL either because there\u2019s no Cozy or the domain does not exist or anything else, we\u2019ll throw an InvalidCozyUrlError. Also, since we communicate only via HTTP or HTTPS, we\u2019ll throw an InvalidProtocolError if any other protocol is used. This function expects a fully qualified URL thus with a protocol and a valid hostname. If your application accepts Cozy intances as input (e.g. claude when the Cozy can be found at https://claude.mycozy.cloud ), it is your responsibility to add the appropriate domain to the hostname before calling this function. Examples: getting the root URL when your user gives you its instance name const userInput = \u2018claude\u2019 const rootUrl = await rootCozyUrl(new URL( https://${userInput}.mycozy.cloud )) // \u2192 returns new URL(\u2018https://claude.mycozy.cloud\u2019) getting the root URL when your user gives you a Cozy Drive URL const userInput = \u2018https://claude-drive.mycozy.cloud/#/folder/io.cozy.files.root-dir\u2019 const rootUrl = await rootCozyUrl(new URL(userInput)) // \u2192 returns new URL(\u2018https://claude.mycozy.cloud\u2019) getting the root URL when the Cozy uses nested sub-domains const userInput = \u2018http://photos.camille.nimbus.com:8080/#/album/1234567890\u2019 const rootCozyUrl = await rootCozyUrl(new URL(userInput)) // \u2192 returns new URL(\u2018http://camille.nimbus.com:8080\u2019) Parameters Name Type Description url URL The URL from which we\u2019ll try to get the root Cozy URL Returns Promise < URL > The root Cozy URL Defined in packages/cozy-client/src/helpers/urlHelper.js:268", "title": "rootCozyUrl"}, {"location": "cozy-client/api/cozy-client/#useapplinkwithstorefallback", "text": "\u25b8 useAppLinkWithStoreFallback ( slug , client , path? ): Object Parameters Name Type Default value slug any undefined client any undefined path string '' Returns Object Name Type fetchStatus string isInstalled boolean url any Defined in packages/cozy-client/src/hooks/useAppLinkWithStoreFallback.jsx:9", "title": "useAppLinkWithStoreFallback"}, {"location": "cozy-client/api/cozy-client/#useappsinmaintenance", "text": "\u25b8 useAppsInMaintenance (): \"io.cozy.apps\" [] Returns all apps in maintenance Returns \"io.cozy.apps\" [] An array with all apps in maintenance Defined in packages/cozy-client/src/hooks/useAppsInMaintenance.jsx:12", "title": "useAppsInMaintenance"}, {"location": "cozy-client/api/cozy-client/#usecapabilities", "text": "\u25b8 useCapabilities ( client ): Object Parameters Name Type client any Returns Object Name Type capabilities undefined fetchStatus string Defined in packages/cozy-client/src/hooks/useCapabilities.jsx:5", "title": "useCapabilities"}, {"location": "cozy-client/api/cozy-client/#useclient", "text": "\u25b8 useClient (): CozyClient Returns the cozy client from the context Returns CozyClient Current cozy client Defined in packages/cozy-client/src/hooks/useClient.js:9", "title": "useClient"}, {"location": "cozy-client/api/cozy-client/#usefetchshortcut", "text": "\u25b8 useFetchShortcut ( client , id ): Object Parameters Name Type client any id any Returns Object Name Type fetchStatus string shortcutImg any shortcutInfos any Defined in packages/cozy-client/src/hooks/useFetchShortcut.jsx:8", "title": "useFetchShortcut"}, {"location": "cozy-client/api/cozy-client/#useinstanceinfo", "text": "\u25b8 useInstanceInfo (): InstanceInfo Retrieve intance info like context, uuid, disk usage etc Returns InstanceInfo Defined in packages/cozy-client/src/hooks/useInstanceInfo.js:11", "title": "useInstanceInfo"}, {"location": "cozy-client/api/cozy-client/#usequeries", "text": "\u25b8 useQueries ( querySpecs ): Object Parameters Name Type querySpecs any Returns Object Defined in packages/cozy-client/src/hooks/useQuery.js:93", "title": "useQueries"}, {"location": "cozy-client/api/cozy-client/#usequery", "text": "\u25b8 useQuery ( queryDefinition , options ): UseQueryReturnValue Fetches a queryDefinition and returns the queryState Parameters Name Type Description queryDefinition QueryDefinition () => QueryDefinition options QueryOptions Options created with Q() Returns UseQueryReturnValue Defined in packages/cozy-client/src/hooks/useQuery.js:28", "title": "useQuery"}, {"location": "cozy-client/api/cozy-client/#usequeryall", "text": "\u25b8 useQueryAll ( queryDefinition , options ): UseQueryReturnValue Fetches a queryDefinition and run fetchMore on the query until the query is fully loaded Parameters Name Type Description queryDefinition QueryDefinition Definition created with Q() options QueryOptions Options created with Q() Returns UseQueryReturnValue Defined in packages/cozy-client/src/hooks/useQueryAll.jsx:14", "title": "useQueryAll"}, {"location": "cozy-client/api/cozy-client/#usesettings", "text": "\u25b8 useSettings < T >( slug , keys ): UseSettingsReturnValue < T > Query the cozy-app settings corresponding to the given slug and return: the values corresponding to the given keys the save() method that can be used to edit the setting\u2019s value the query that manages the state during the fetching of the setting the mutation that manages the state during the saving of the setting", "title": "useSettings"}, {"location": "cozy-client/api/cozy-client/#type-parameters", "text": "Name Type T extends string Parameters Name Type Description slug string the cozy-app\u2019s slug containing the setting (special cases are: \u2018instance\u2019 for global settings and \u2018passwords\u2019 for bitwarden settings) keys T [] The name of the setting to retrieve Returns UseSettingsReturnValue < T > Defined in packages/cozy-client/src/hooks/useSetting.js:24", "title": "Type parameters"}, {"location": "cozy-client/api/cozy-client/#withclient", "text": "\u25b8 withClient ( WrappedComponent ): Function function description HOC to provide client from context as prop Parameters Name Type Description WrappedComponent Component < any , any , any > wrapped component Returns Function Component that will receive client as prop Defined in packages/cozy-client/src/hoc.jsx:16", "title": "withClient"}, {"location": "cozy-client/api/cozy-client/#withmutation", "text": "\u25b8 withMutation ( mutation , options? ): Function Parameters Name Type mutation any options Object Returns Function Defined in packages/cozy-client/src/withMutation.jsx:8", "title": "withMutation"}, {"location": "cozy-client/api/cozy-client/#withmutations", "text": "\u25b8 withMutations (\u2026 mutations ): Function function description HOC to provide mutations to components. Needs client in context or as prop. deprecated Prefer to use withClient and access directly the client. Parameters Name Type Description ...mutations Function [] One ore more mutations, which are function taking CozyClient as parameter and returning an object containing one or more mutations as attributes. Returns Function Component that will receive mutations as props Defined in packages/cozy-client/src/withMutations.jsx:24", "title": "withMutations"}, {"location": "cozy-client/api/cozy-client/classes/Association/", "text": "cozy-client / Association Class: Association \u00b6 Associations are used by components to access related store documents that are linked in a document. They are also responsible for building the QueryDefinition that is used by the client to automatically fetch relationship data. Hydrated documents used by components come with Association instances. interface description Example: The schema defines an author relationship : const BOOK_SCHEMA = { relationships : { author : 'has-one' } } Hydrated books will have the author association instance under the author key. Accessing hydratedBook.author.data gives you the author from the store, for example : { \"name\" : \"St-Exupery\" , \"firstName\" : \"Antoine\" , \"_id\" : \"antoine\" } It is the responsibility of the relationship to decide how the relationship data is stored. For example, here since we use the default has-one relationship, the relationship data is stored in the relationships attribute of the original document (in our case here, our book would be { \"title\" : \"Le petit prince\" , \"relationships\" : { \"author\" : { \"data\" : { \"doctype\" : \"io.cozy.authors\" , \"_id\" : \"antoine\" } } } } In the case of an \u201cin-place\u201d relationship, the relationship data is stored directly under the attribute named by the relationship (in our case author ). Our book would be { \"title\" : \"Le petit prince\" , \"author\" : \"antoine\" } Each different type of Association may change: get raw : how the relationship data is stored (either as per the JSON API spec or in a custom way) get data : how the store documents are then fetched from the store to be added to the hydrated document (.data method). View components will access hydratedDoc[relationshipName].data . get query : how to build the query to fetch related documents Hierarchy \u00b6 Association \u21b3 HasMany \u21b3 HasOne \u21b3 HasOneInPlace \u21b3 HasManyInPlace Constructors \u00b6 constructor \u00b6 \u2022 new Association ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Defined in packages/cozy-client/src/associations/Association.js:87 Properties \u00b6 dispatch \u00b6 \u2022 dispatch : Function Dispatch an action on the store. Defined in packages/cozy-client/src/associations/Association.js:144 doctype \u00b6 \u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Defined in packages/cozy-client/src/associations/Association.js:109 get \u00b6 \u2022 get : Function Returns the document from the store Defined in packages/cozy-client/src/associations/Association.js:116 mutate \u00b6 \u2022 mutate : Function Performs a mutation on the relationship. function Defined in packages/cozy-client/src/associations/Association.js:131 name \u00b6 \u2022 name : string The name of the relationship. example \u2018author\u2019 Defined in packages/cozy-client/src/associations/Association.js:101 query \u00b6 \u2022 query : Function Performs a query to retrieve relationship documents. param function Defined in packages/cozy-client/src/associations/Association.js:124 save \u00b6 \u2022 save : Function Saves the relationship in store. Defined in packages/cozy-client/src/associations/Association.js:138 target \u00b6 \u2022 target : any The original document declaring the relationship Defined in packages/cozy-client/src/associations/Association.js:94 Accessors \u00b6 data \u00b6 \u2022 get data (): any Returns the document(s) from the store For document with relationships stored as JSON API spec : const book = { title : 'Moby Dick' , relationships : { author : { data : { doctype : 'io.cozy.authors' , id : 'herman' } } } } data will be { \"_id\" : \"herman\" \"_type\" : \"io.cozy.authors\" , \"firstName\" : \"herman\" , \"name\" : \"Melville\" } Derived Association s need to implement this method. Returns any Defined in packages/cozy-client/src/associations/Association.js:218 raw \u00b6 \u2022 get raw (): any Returns the raw relationship data as stored in the original document For a document with relationships stored as JSON API spec: const book = { title : 'Moby Dick' , relationships : { author : { data : { doctype : 'io.cozy.authors' , id : 'herman' } } } } Raw value will be { \"doctype\" : \"io.cozy.authors\" , \"id\" : \"herman\" } Derived Association s need to implement this method. Returns any Defined in packages/cozy-client/src/associations/Association.js:180 Methods \u00b6 query \u00b6 \u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Derived Association s need to implement this method. Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association Association containing info on how to build the query to fetch related documents Returns CozyClientDocument | QueryDefinition Defined in packages/cozy-client/src/associations/Association.js:231", "title": "Association"}, {"location": "cozy-client/api/cozy-client/classes/Association/#class-association", "text": "Associations are used by components to access related store documents that are linked in a document. They are also responsible for building the QueryDefinition that is used by the client to automatically fetch relationship data. Hydrated documents used by components come with Association instances. interface description Example: The schema defines an author relationship : const BOOK_SCHEMA = { relationships : { author : 'has-one' } } Hydrated books will have the author association instance under the author key. Accessing hydratedBook.author.data gives you the author from the store, for example : { \"name\" : \"St-Exupery\" , \"firstName\" : \"Antoine\" , \"_id\" : \"antoine\" } It is the responsibility of the relationship to decide how the relationship data is stored. For example, here since we use the default has-one relationship, the relationship data is stored in the relationships attribute of the original document (in our case here, our book would be { \"title\" : \"Le petit prince\" , \"relationships\" : { \"author\" : { \"data\" : { \"doctype\" : \"io.cozy.authors\" , \"_id\" : \"antoine\" } } } } In the case of an \u201cin-place\u201d relationship, the relationship data is stored directly under the attribute named by the relationship (in our case author ). Our book would be { \"title\" : \"Le petit prince\" , \"author\" : \"antoine\" } Each different type of Association may change: get raw : how the relationship data is stored (either as per the JSON API spec or in a custom way) get data : how the store documents are then fetched from the store to be added to the hydrated document (.data method). View components will access hydratedDoc[relationshipName].data . get query : how to build the query to fetch related documents", "title": "Class: Association"}, {"location": "cozy-client/api/cozy-client/classes/Association/#hierarchy", "text": "Association \u21b3 HasMany \u21b3 HasOne \u21b3 HasOneInPlace \u21b3 HasManyInPlace", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/Association/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/Association/#constructor", "text": "\u2022 new Association ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Defined in packages/cozy-client/src/associations/Association.js:87", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/Association/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/Association/#dispatch", "text": "\u2022 dispatch : Function Dispatch an action on the store. Defined in packages/cozy-client/src/associations/Association.js:144", "title": "dispatch"}, {"location": "cozy-client/api/cozy-client/classes/Association/#doctype", "text": "\u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Defined in packages/cozy-client/src/associations/Association.js:109", "title": "doctype"}, {"location": "cozy-client/api/cozy-client/classes/Association/#get", "text": "\u2022 get : Function Returns the document from the store Defined in packages/cozy-client/src/associations/Association.js:116", "title": "get"}, {"location": "cozy-client/api/cozy-client/classes/Association/#mutate", "text": "\u2022 mutate : Function Performs a mutation on the relationship. function Defined in packages/cozy-client/src/associations/Association.js:131", "title": "mutate"}, {"location": "cozy-client/api/cozy-client/classes/Association/#name", "text": "\u2022 name : string The name of the relationship. example \u2018author\u2019 Defined in packages/cozy-client/src/associations/Association.js:101", "title": "name"}, {"location": "cozy-client/api/cozy-client/classes/Association/#query", "text": "\u2022 query : Function Performs a query to retrieve relationship documents. param function Defined in packages/cozy-client/src/associations/Association.js:124", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/Association/#save", "text": "\u2022 save : Function Saves the relationship in store. Defined in packages/cozy-client/src/associations/Association.js:138", "title": "save"}, {"location": "cozy-client/api/cozy-client/classes/Association/#target", "text": "\u2022 target : any The original document declaring the relationship Defined in packages/cozy-client/src/associations/Association.js:94", "title": "target"}, {"location": "cozy-client/api/cozy-client/classes/Association/#accessors", "text": "", "title": "Accessors"}, {"location": "cozy-client/api/cozy-client/classes/Association/#data", "text": "\u2022 get data (): any Returns the document(s) from the store For document with relationships stored as JSON API spec : const book = { title : 'Moby Dick' , relationships : { author : { data : { doctype : 'io.cozy.authors' , id : 'herman' } } } } data will be { \"_id\" : \"herman\" \"_type\" : \"io.cozy.authors\" , \"firstName\" : \"herman\" , \"name\" : \"Melville\" } Derived Association s need to implement this method. Returns any Defined in packages/cozy-client/src/associations/Association.js:218", "title": "data"}, {"location": "cozy-client/api/cozy-client/classes/Association/#raw", "text": "\u2022 get raw (): any Returns the raw relationship data as stored in the original document For a document with relationships stored as JSON API spec: const book = { title : 'Moby Dick' , relationships : { author : { data : { doctype : 'io.cozy.authors' , id : 'herman' } } } } Raw value will be { \"doctype\" : \"io.cozy.authors\" , \"id\" : \"herman\" } Derived Association s need to implement this method. Returns any Defined in packages/cozy-client/src/associations/Association.js:180", "title": "raw"}, {"location": "cozy-client/api/cozy-client/classes/Association/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/Association/#query_1", "text": "\u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Derived Association s need to implement this method. Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association Association containing info on how to build the query to fetch related documents Returns CozyClientDocument | QueryDefinition Defined in packages/cozy-client/src/associations/Association.js:231", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/BlockedCozyError/", "text": "cozy-client / BlockedCozyError Class: BlockedCozyError \u00b6 Hierarchy \u00b6 Error \u21b3 BlockedCozyError Constructors \u00b6 constructor \u00b6 \u2022 new BlockedCozyError ( url ) Parameters Name Type url any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:138 Properties \u00b6 url \u00b6 \u2022 url : any Defined in packages/cozy-client/src/helpers/urlHelper.js:141", "title": "BlockedCozyError"}, {"location": "cozy-client/api/cozy-client/classes/BlockedCozyError/#class-blockedcozyerror", "text": "", "title": "Class: BlockedCozyError"}, {"location": "cozy-client/api/cozy-client/classes/BlockedCozyError/#hierarchy", "text": "Error \u21b3 BlockedCozyError", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/BlockedCozyError/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/BlockedCozyError/#constructor", "text": "\u2022 new BlockedCozyError ( url ) Parameters Name Type url any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:138", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/BlockedCozyError/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/BlockedCozyError/#url", "text": "\u2022 url : any Defined in packages/cozy-client/src/helpers/urlHelper.js:141", "title": "url"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/", "text": "cozy-client / BulkEditError Class: BulkEditError \u00b6 Hierarchy \u00b6 Error \u21b3 BulkEditError Constructors \u00b6 constructor \u00b6 \u2022 new BulkEditError ( bulkResponse , updatedDocs ) Indicates that a bulk edit has (potentially partially) failed Parameters Name Type Description bulkResponse CouchDBBulkResult [] CouchDB Bulk response updatedDocs CozyClientDocument [] Docs with updated _id and _rev Overrides Error.constructor Defined in packages/cozy-client/src/errors.js:10 Properties \u00b6 name \u00b6 \u2022 name : string Inherited from Error.name Defined in packages/cozy-client/src/errors.js:12 results \u00b6 \u2022 results : { doc : CozyClientDocument ; error : string ; id : string ; ok : boolean ; reason : string ; rev : string }[] Defined in packages/cozy-client/src/errors.js:13 Methods \u00b6 getErrors \u00b6 \u25b8 getErrors (): CouchDBBulkResult & { doc : CozyClientDocument }[] Get bulk errors results Returns CouchDBBulkResult & { doc : CozyClientDocument }[] } Defined in packages/cozy-client/src/errors.js:32 getUpdatedDocuments \u00b6 \u25b8 getUpdatedDocuments (): CozyClientDocument [] Get documents that have been correctly updated Returns CozyClientDocument [] Defined in packages/cozy-client/src/errors.js:23", "title": "BulkEditError"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#class-bulkediterror", "text": "", "title": "Class: BulkEditError"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#hierarchy", "text": "Error \u21b3 BulkEditError", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#constructor", "text": "\u2022 new BulkEditError ( bulkResponse , updatedDocs ) Indicates that a bulk edit has (potentially partially) failed Parameters Name Type Description bulkResponse CouchDBBulkResult [] CouchDB Bulk response updatedDocs CozyClientDocument [] Docs with updated _id and _rev Overrides Error.constructor Defined in packages/cozy-client/src/errors.js:10", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#name", "text": "\u2022 name : string Inherited from Error.name Defined in packages/cozy-client/src/errors.js:12", "title": "name"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#results", "text": "\u2022 results : { doc : CozyClientDocument ; error : string ; id : string ; ok : boolean ; reason : string ; rev : string }[] Defined in packages/cozy-client/src/errors.js:13", "title": "results"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#geterrors", "text": "\u25b8 getErrors (): CouchDBBulkResult & { doc : CozyClientDocument }[] Get bulk errors results Returns CouchDBBulkResult & { doc : CozyClientDocument }[] } Defined in packages/cozy-client/src/errors.js:32", "title": "getErrors"}, {"location": "cozy-client/api/cozy-client/classes/BulkEditError/#getupdateddocuments", "text": "\u25b8 getUpdatedDocuments (): CozyClientDocument [] Get documents that have been correctly updated Returns CozyClientDocument [] Defined in packages/cozy-client/src/errors.js:23", "title": "getUpdatedDocuments"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/", "text": "cozy-client / CozyClient Class: CozyClient \u00b6 Responsible for Creating observable queries Hydration Creating plan for saving documents Associations Constructors \u00b6 constructor \u00b6 \u2022 new CozyClient ( rawOptions? ) example const client = new CozyClient ({ schema : { todos : { doctype : 'io.cozy.todos' , relationships : { authors : { type : 'has-many' , doctype : 'io.cozy.persons' } } } } }) Cozy-Client will automatically call this.login() if provided with a token and an uri Parameters Name Type Description rawOptions ClientOptions Options Defined in packages/cozy-client/src/CozyClient.js:151 Properties \u00b6 appMetadata \u00b6 \u2022 appMetadata : AppMetadata Defined in packages/cozy-client/src/CozyClient.js:164 capabilities \u00b6 \u2022 capabilities : ClientCapabilities Defined in packages/cozy-client/src/CozyClient.js:192 chain \u00b6 \u2022 chain : any Defined in packages/cozy-client/src/CozyClient.js:185 client \u00b6 \u2022 client : any Defined in packages/cozy-client/src/CozyClient.js:1632 instanceOptions \u00b6 \u2022 instanceOptions : Object Defined in packages/cozy-client/src/CozyClient.js:172 isLogged \u00b6 \u2022 isLogged : boolean Defined in packages/cozy-client/src/CozyClient.js:171 isRevoked \u00b6 \u2022 isRevoked : boolean Defined in packages/cozy-client/src/CozyClient.js:486 links \u00b6 \u2022 links : any [] Defined in packages/cozy-client/src/CozyClient.js:182 loginPromise \u00b6 \u2022 loginPromise : Promise < void > Defined in packages/cozy-client/src/CozyClient.js:165 options \u00b6 \u2022 options : Object Type declaration Name Type Description autoHydrate boolean - backgroundFetching boolean If set to true, backgroundFetching will be enabled by default on every query. Meaning that, when the fetchStatus has already been loaded, it won\u2019t be updated during future fetches. Instead, a isFetching attribute will be used to indicate when background fetching is started. client any - oauth any - onError Function Default callback if a query is errored onTokenRefresh Function - stackClient any - store boolean If set to false, the client will not instantiate a Redux store automatically. Use this if you want to merge cozy-client\u2019s store with your own redux store. See here for more information. token any - uri string - warningForCustomHandlers boolean - Defined in packages/cozy-client/src/CozyClient.js:168 plugins \u00b6 \u2022 plugins : Object Defined in packages/cozy-client/src/CozyClient.js:195 queryIdGenerator \u00b6 \u2022 queryIdGenerator : QueryIDGenerator Defined in packages/cozy-client/src/CozyClient.js:170 schema \u00b6 \u2022 schema : Schema Defined in packages/cozy-client/src/CozyClient.js:187 stackClient \u00b6 \u2022 stackClient : any Defined in packages/cozy-client/src/CozyClient.js:1607 store \u00b6 \u2022 store : any Defined in packages/cozy-client/src/CozyClient.js:1537 storeAccesors \u00b6 \u2022 storeAccesors : any Defined in packages/cozy-client/src/CozyClient.js:220 storeAccessors \u00b6 \u2022 storeAccessors : Object Type declaration Name Type dispatch any get any mutate ( def : any , opts : any ) => any query ( def : any , opts : any ) => any save ( document : any , opts : any ) => any Defined in packages/cozy-client/src/CozyClient.js:1290 fetchPolicies \u00b6 \u25aa Static fetchPolicies : Object Type declaration Name Type noFetch () => boolean olderThan ( delay : number ) => Function hooks \u00b6 \u25aa Static hooks : Object version \u00b6 \u25aa Static version : string Methods \u00b6 _login \u00b6 \u25b8 _login ( options ): Promise < void > Parameters Name Type options any Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:465 addSchema \u00b6 \u25b8 addSchema ( schemaDefinition ): void Parameters Name Type schemaDefinition any Returns void Defined in packages/cozy-client/src/CozyClient.js:421 all \u00b6 \u25b8 all ( doctype ): QueryDefinition Parameters Name Type doctype any Returns QueryDefinition Defined in packages/cozy-client/src/CozyClient.js:566 authorize \u00b6 \u25b8 authorize ( [options]? ): Promise < any > Creates an OAuth token with needed permissions for the current client. The authorization page URL generation can be overriding by passing a function pointer as openURLCallback parameter It is possible to skip the session creation process (when using an in-app browser) by passing a sessionCode (see https://docs.cozy.io/en/cozy-stack/auth/#post-authsession_code) Parameters Name Type Description [options] Object Authorization options [options].openURLCallback OpenURLCallback - [options].pkceCodes PKCECodes - [options].sessionCode string - Returns Promise < any > Contains the fetched token and the client information. These should be stored and used to restore the client. Defined in packages/cozy-client/src/CozyClient.js:1453 certifyFlagship \u00b6 \u25b8 certifyFlagship (): Promise < void > Perform the Flagship certification process for verifying that the current running app is a genuine Cozy application This mechanism is described in https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/flagship-certification/README.md Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:1434 checkForRevocation \u00b6 \u25b8 checkForRevocation (): Promise < any > Returns whether the client has been revoked on the server Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:1549 collection \u00b6 \u25b8 collection ( doctype ): any Forwards to a stack client instance and returns a DocumentCollection instance. Parameters Name Type Description doctype string The collection doctype. Returns any Collection corresponding to the doctype Defined in packages/cozy-client/src/CozyClient.js:558 create \u00b6 \u25b8 create ( type , doc , references , options? ): Promise < any > Creates a document and saves it on the server example await client . create ( 'io.cozy.todos' , { label : 'My todo' , relationships : { authors : { data : [{ _id : 1 , _type : 'io.cozy.persons' }] } } }) Parameters Name Type Description type string Doctype of the document doc any Document to save references Object - options any Mutation options Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:613 createClient \u00b6 \u25b8 createClient (): void If no stack client has been passed in options, creates a default stack client and attaches handlers for revocation and token refresh. If a stackClient has been passed in options, ensure it has handlers for revocation and token refresh. If oauth options are passed, stackClient is an OAuthStackClient. Returns void Defined in packages/cozy-client/src/CozyClient.js:1587 destroy \u00b6 \u25b8 destroy ( document , mutationOptions? ): Promise < CozyClientDocument > Destroys a document. {before,after}:destroy hooks will be fired. Parameters Name Type Description document CozyClientDocument Document to be deleted mutationOptions Object - Returns Promise < CozyClientDocument > The document that has been deleted Defined in packages/cozy-client/src/CozyClient.js:869 dispatch \u00b6 \u25b8 dispatch ( action ): any Parameters Name Type action any Returns any Defined in packages/cozy-client/src/CozyClient.js:1658 emit \u00b6 \u25b8 emit (\u2026 args ): void Gets overrided by MicroEE.mixin This is here just so typescript does not scream TODO Find a better way to make TS understand that emit is a method from cozy-client Parameters Name Type ...args any [] Returns void Defined in packages/cozy-client/src/CozyClient.js:234 ensureCozyMetadata \u00b6 \u25b8 ensureCozyMetadata ( document , options? ): CozyClientDocument Parameters Name Type Description document CozyClientDocument Document that will be saved options Object - options.event string - Returns CozyClientDocument Defined in packages/cozy-client/src/CozyClient.js:683 ensureQueryExists \u00b6 \u25b8 ensureQueryExists ( queryId , queryDefinition , options ): void Makes sure that the query exists in the store Parameters Name Type Description queryId string Id of the query queryDefinition QueryDefinition Definition of the query options QueryOptions - Returns void Defined in packages/cozy-client/src/CozyClient.js:890 ensureStore \u00b6 \u25b8 ensureStore (): void Returns void Defined in packages/cozy-client/src/CozyClient.js:1540 fetch \u00b6 \u25b8 fetch ( method , path , body , options? ): any Parameters Name Type method any path any body any options Object Returns any Defined in packages/cozy-client/src/CozyClient.js:562 fetchQueryAndGetFromState \u00b6 \u25b8 fetchQueryAndGetFromState ( query ): Promise < QueryState > Executes a query and returns the results from internal store. Can be useful in pure JS context (without React) Has a behavior close to or useQuery Parameters Name Type Description query Object Query with definition and options query.definition QueryDefinition Query Definition query.options QueryOptions Query Options Returns Promise < QueryState > Query state Defined in packages/cozy-client/src/CozyClient.js:1387 find \u00b6 \u25b8 find ( doctype , selector? ): QueryDefinition Parameters Name Type Default value doctype any undefined selector any undefined Returns QueryDefinition Defined in packages/cozy-client/src/CozyClient.js:575 generateRandomId \u00b6 \u25b8 generateRandomId (): string Returns string Defined in packages/cozy-client/src/CozyClient.js:1265 get \u00b6 \u25b8 get ( doctype , id ): QueryDefinition Parameters Name Type doctype any id any Returns QueryDefinition Defined in packages/cozy-client/src/CozyClient.js:582 getAssociation \u00b6 \u25b8 getAssociation ( document , associationName ): any Creates an association that is linked to the store. Parameters Name Type document any associationName any Returns any Defined in packages/cozy-client/src/CozyClient.js:1272 getClient \u00b6 \u25b8 getClient (): any Returns any Defined in packages/cozy-client/src/CozyClient.js:1640 getCollectionFromState \u00b6 \u25b8 getCollectionFromState ( type ): CozyClientDocument [] Get a collection of documents from the internal store. Parameters Name Type Description type string Doctype of the collection Returns CozyClientDocument [] Array of documents or null if the collection does not exist. Defined in packages/cozy-client/src/CozyClient.js:1308 getDocumentFromState \u00b6 \u25b8 getDocumentFromState ( type , id ): CozyClientDocument Get a document from the internal store. Parameters Name Type Description type string Doctype of the document id string Id of the document Returns CozyClientDocument Document or null if the object does not exist. Defined in packages/cozy-client/src/CozyClient.js:1325 getDocumentSavePlan \u00b6 \u25b8 getDocumentSavePlan ( document , referencesByName ): any Creates a list of mutations to execute to create a document and its relationships. const baseDoc = { _type : 'io.cozy.todo' , label : 'Go hiking' } // relations can be arrays or single objects const relationships = { attachments : [{ _id : 12345 , _type : 'io.cozy.files' }, { _id : 6789 , _type : 'io.cozy.files' }], bills : { _id : 9999 , _type : 'io.cozy.bills' } } client . getDocumentSavePlan ( baseDoc , relationships ) Parameters Name Type Description document CozyClientDocument Document to create referencesByName Object - Returns any One or more mutation to execute Defined in packages/cozy-client/src/CozyClient.js:782 getIncludesRelationships \u00b6 \u25b8 getIncludesRelationships ( queryDefinition ): Dictionary < any > Parameters Name Type queryDefinition any Returns Dictionary < any > Defined in packages/cozy-client/src/CozyClient.js:1192 getInstanceOptions \u00b6 \u25b8 getInstanceOptions (): any getInstanceOptions - Returns current instance options, such as domain or app slug Returns any Defined in packages/cozy-client/src/CozyClient.js:1667 getQueryFromState \u00b6 \u25b8 getQueryFromState ( id , options? ): QueryState Get a query from the internal store. Parameters Name Type Description id string Id of the query (set via Query.props.as) options Object Options options.hydrated boolean - options.singleDocData any - Returns QueryState Query state or null if it does not exist. Defined in packages/cozy-client/src/CozyClient.js:1346 getRelationshipStoreAccessors \u00b6 \u25b8 getRelationshipStoreAccessors (): Object Returns the accessors that are given to the relationships for them to deal with the stores. Relationships need to have access to the store to ping it when a modification (addById/removeById etc\u2026) has been done. This wakes the store up, which in turn will update the s and re-render the data. Returns Object Name Type dispatch any get any mutate ( def : any , opts : any ) => any query ( def : any , opts : any ) => any save ( document : any , opts : any ) => any Defined in packages/cozy-client/src/CozyClient.js:1288 getSettings \u00b6 \u25b8 getSettings < T >( slug , keys ): Promise < Record < T , any >> Query the cozy-app settings corresponding to the given slug and extract the value corresponding to the given key Type parameters \u00b6 Name Type T extends string Parameters Name Type Description slug string the cozy-app\u2019s slug containing the setting (can be \u2018instance\u2019 for global settings) keys T [] The names of the settings to retrieve Returns Promise < Record < T , any >> The value of the requested setting Defined in packages/cozy-client/src/CozyClient.js:1768 getStackClient \u00b6 \u25b8 getStackClient (): any Returns any Defined in packages/cozy-client/src/CozyClient.js:1647 handleRevocationChange \u00b6 \u25b8 handleRevocationChange ( state ): void Sets public attribute and emits event related to revocation Parameters Name Type state any Returns void Defined in packages/cozy-client/src/CozyClient.js:1558 handleTokenRefresh \u00b6 \u25b8 handleTokenRefresh ( token ): void Emits event when token is refreshed Parameters Name Type token any Returns void Defined in packages/cozy-client/src/CozyClient.js:1569 hydrateDocument \u00b6 \u25b8 hydrateDocument ( document , schemaArg ): any Resolves relationships on a document. The original document is kept in the target attribute of the relationship Parameters Name Type Description document CozyClientDocument for which relationships must be resolved schemaArg Schema - Returns any Defined in packages/cozy-client/src/CozyClient.js:1235 hydrateDocuments \u00b6 \u25b8 hydrateDocuments ( doctype , documents ): any [] Returns documents with their relationships resolved according to their schema. If related documents are not in the store, they will not be fetched automatically. Instead, the relationships will have null documents. Parameters Name Type Description doctype string Doctype of the documents being hydrated documents CozyClientDocument [] Documents to be hydrated Returns any [] Defined in packages/cozy-client/src/CozyClient.js:1212 hydrateRelationships \u00b6 \u25b8 hydrateRelationships ( document , schemaRelationships ): Object Parameters Name Type document any schemaRelationships any Returns Object Defined in packages/cozy-client/src/CozyClient.js:1246 isReactNative \u00b6 \u25b8 isReactNative (): boolean Returns boolean Defined in packages/cozy-client/src/CozyClient.js:1410 loadInstanceOptionsFromDOM \u00b6 \u25b8 loadInstanceOptionsFromDOM ( selector? ): void loadInstanceOptionsFromDOM - Loads the dataset injected by the Stack in web pages and exposes it through getInstanceOptions Parameters Name Type Default value selector string '[role=application]' Returns void Defined in packages/cozy-client/src/CozyClient.js:1678 loadInstanceOptionsFromStack \u00b6 \u25b8 loadInstanceOptionsFromStack (): Promise < void > loadInstanceOptionsFromStack - Loads the instance options from cozy-stack and exposes it through getInstanceOptions This method is not iso with loadInstanceOptionsFromDOM for now. Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:1699 login \u00b6 \u25b8 login ( options ): Promise < any > Notify the links that they can start and set isLogged to true. On mobile, where url/token are set after instantiation, use this method to set the token and uri via options. Emits \u201cbeforeLogin\u201d at the beginning, before links have been set up \u201clogin\u201d when the client is fully logged in and links have been set up Parameters Name Type Description options Object - options.token string If passed, the token is set on the client options.uri string If passed, the uri is set on the client Returns Promise < any > Resolves when all links have been setup and client is fully logged in Defined in packages/cozy-client/src/CozyClient.js:454 logout \u00b6 \u25b8 logout (): Promise < any > Logs out the client and reset all the links Emits \u201cbeforeLogout\u201d at the beginning, before links have been reset \u201clogout\u201d when the client is fully logged out and links have been reset Returns Promise < any > Resolves when all links have been reset and client is fully logged out Defined in packages/cozy-client/src/CozyClient.js:505 makeNewDocument \u00b6 \u25b8 makeNewDocument ( doctype ): any Creates (locally) a new document for the given doctype. This document is hydrated : its relationships are there and working. Parameters Name Type doctype any Returns any Defined in packages/cozy-client/src/CozyClient.js:1258 makeObservableQuery \u00b6 \u25b8 makeObservableQuery ( queryDefinition , options? ): default Parameters Name Type queryDefinition any options Object Returns default Defined in packages/cozy-client/src/CozyClient.js:1034 mutate \u00b6 \u25b8 mutate ( mutationDefinition , [options]? ): Promise < any > Mutate a document Parameters Name Type Description mutationDefinition any Describe the mutation [options] Object Options [options].as string - [options].update Function - [options].updateQueries Function - Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:1052 on \u00b6 \u25b8 on (\u2026 args ): void Parameters Name Type ...args any [] Returns void Defined in packages/cozy-client/src/CozyClient.js:235 prepareDocumentForSave \u00b6 \u25b8 prepareDocumentForSave ( doc ): CozyClientDocument Dehydrates and adds metadata before saving a document Parameters Name Type Description doc CozyClientDocument Document that will be saved Returns CozyClientDocument Defined in packages/cozy-client/src/CozyClient.js:753 query \u00b6 \u25b8 query ( queryDefinition , [options]? ): Promise < any > Executes a query and returns its results. Results from the query will be saved internally and can be retrieved via getQueryFromState or directly using . automatically executes its query when mounted if no fetch policy has been indicated. If the query is called under the fetch policy\u2019s delay, then the query is not executed and nothing is returned. If you need a result anyway, please use fetchQueryAndGetFromState instead Parameters Name Type Description queryDefinition QueryDefinition Definition that will be executed [options] QueryOptions Options Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:917 queryAll \u00b6 \u25b8 queryAll ( queryDefinition , options? ): Promise < any > Will fetch all documents for a queryDefinition , automatically fetching more documents if the total of documents is superior to the pagination limit. Can result in a lot of network requests. Parameters Name Type Description queryDefinition QueryDefinition Definition to be executed options QueryOptions - Returns Promise < any > All documents matching the query Defined in packages/cozy-client/src/CozyClient.js:994 reducer \u00b6 \u25b8 reducer (): ( state : { documents : {} = {}; queries : {} = {} }, action : any ) => { documents : any ; queries : QueriesStateSlice } Returns fn \u25b8 ( state? , action ): Object Parameters Name Type Default value state Object initialState state.documents Object {} state.queries Object {} action any undefined Returns Object Name Type documents any queries QueriesStateSlice Defined in packages/cozy-client/src/CozyClient.js:1654 register \u00b6 \u25b8 register ( cozyURL ): any Performs a complete OAuth flow using a Cordova webview or React Native WebView for auth. The register method\u2019s name has been chosen for compat reasons with the Authentication compo. Parameters Name Type Description cozyURL string Receives the URL of the cozy instance. Returns any Contains the fetched token and the client information. Defined in packages/cozy-client/src/CozyClient.js:1404 registerClientOnLinks \u00b6 \u25b8 registerClientOnLinks (): void Returns void Defined in packages/cozy-client/src/CozyClient.js:425 registerPlugin \u00b6 \u25b8 registerPlugin ( Plugin , options ): any A plugin is a class whose constructor receives the client as first argument. The main mean of interaction with the client should be with events like \u201clogin\u201d/\u201dlogout\u201d. The plugin system is meant to encourage separation of concerns, modularity and testability : instead of registering events at module level, please create a plugin that subscribes to events. Plugin instances are stored internally in the plugins attribute of the client and can be accessed via this mean. A plugin class must have the attribute pluginName that will be use as the key in the plugins object. Two plugins with the same pluginName cannot co-exist. example class AlertPlugin { constructor ( client , options ) { this . client = client this . options = options this . handleLogin = this . handleLogin . bind ( this ) this . handleLogout = this . handleLogout . bind ( this ) this . client . on ( \"login\" , this . handleLogin ) this . client . on ( \"logout\" , this . handleLogout ) } handleLogin () { alert ( this . options . onLoginAlert ) } handleLogout () { alert ( this . options . onLogoutAlert ) } } AlertPlugin . pluginName = 'alerts' client . registerPlugin ( AlertPlugin , { onLoginAlert : 'client has logged in !' , onLogoutAlert : 'client has logged out !' }) // the instance of the plugin is accessible via client . plugins . alerts Parameters Name Type Plugin any options any Returns any Defined in packages/cozy-client/src/CozyClient.js:285 removeListener \u00b6 \u25b8 removeListener (\u2026 args ): void Parameters Name Type ...args any [] Returns void Defined in packages/cozy-client/src/CozyClient.js:236 renewAuthorization \u00b6 \u25b8 renewAuthorization (): any Renews the token if, for instance, new permissions are required or token has expired. Returns any Contains the fetched token and the client information. Defined in packages/cozy-client/src/CozyClient.js:1499 requestMutation \u00b6 \u25b8 requestMutation ( definition ): any Parameters Name Type definition any Returns any Defined in packages/cozy-client/src/CozyClient.js:1176 resetQuery \u00b6 \u25b8 resetQuery ( queryId ): Promise < QueryState > Reset a query This method will reset the query state to its initial state and refetch it. Parameters Name Type Description queryId string Query id Returns Promise < QueryState > Query state Defined in packages/cozy-client/src/CozyClient.js:1797 save \u00b6 \u25b8 save ( doc , mutationOptions? ): Promise < any > Create or update a document on the server Parameters Name Type Description doc any Document to save mutationOptions any Mutation options Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:635 saveAfterFetchSettings \u00b6 \u25b8 saveAfterFetchSettings < T >( slug , itemsOrSetter , setterKeys ): Promise < any > Save the given value into the corresponding cozy-app setting This methods will first query the cozy-app\u2019s settings before injecting the new value and then save the new resulting settings into database Type parameters \u00b6 Name Type T extends string Parameters Name Type Description slug string the cozy-app\u2019s slug containing the setting (can be \u2018instance\u2019 for global settings) itemsOrSetter Record < string , any > ( oldValue : any ) => Record < T , any > setterKeys T [] The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary Returns Promise < any > The result of the client.save() call Defined in packages/cozy-client/src/CozyClient.js:1785 saveAll \u00b6 \u25b8 saveAll ( docs , mutationOptions? ): Promise < void > Saves multiple documents in one batch Can only be called with documents from the same doctype Does not support automatic creation of references Parameters Name Type Description docs CozyClientDocument [] Documents from the same doctype mutationOptions Object Mutation Options mutationOptions.as string - mutationOptions.update Function - mutationOptions.updateQueries Function - Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:656 setAppMetadata \u00b6 \u25b8 setAppMetadata ( newAppMetadata ): void Parameters Name Type Description newAppMetadata AppMetadata AppMetadata to update Returns void Defined in packages/cozy-client/src/CozyClient.js:1751 setData \u00b6 \u25b8 setData ( data ): void Directly set the data in the store, without using a query This is useful for cases like Pouch replication, which wants to set some data in the store. Parameters Name Type Description data any Data that is inserted in the store. Shape: Returns void Defined in packages/cozy-client/src/CozyClient.js:1724 setOnError \u00b6 \u25b8 setOnError ( onError ): void At any time put an error function throws {Error} onError should not have been defined yet Parameters Name Type onError Function Returns void Defined in packages/cozy-client/src/CozyClient.js:1737 setStore \u00b6 \u25b8 setStore ( store , [options]? ): void Sets the internal store of the client. Use this when you want to have cozy-client\u2019s internal store colocated with your existing Redux store. Typically, you would need to do this only once in your application, this is why setStore throws if you do it twice. If you really need to set the store again, use options.force = true. example const client = new CozyClient() const store = createStore(combineReducers({ todos: todoReducer, cozy: client.reducer() }) client.setStore(store) Parameters Name Type Description store any A redux store [options] Object Options [options].force boolean - Returns void Defined in packages/cozy-client/src/CozyClient.js:1525 startOAuthFlow \u00b6 \u25b8 startOAuthFlow ( openURLCallback ): Promise < any > Performs a complete OAuth flow, including updating the internal token at the end. Parameters Name Type Description openURLCallback OpenURLCallback Receives the URL to present to the user as a parameter, and should return a promise that resolves with the URL the user was redirected to after accepting the permissions. Returns Promise < any > Contains the fetched token and the client information. These should be stored and used to restore the client. Defined in packages/cozy-client/src/CozyClient.js:1420 toJSON \u00b6 \u25b8 toJSON (): CozyClient Returns CozyClient Defined in packages/cozy-client/src/CozyClient.js:1744 triggerHook \u00b6 \u25b8 triggerHook ( name , document ): void Parameters Name Type name any document any Returns void Defined in packages/cozy-client/src/CozyClient.js:854 upload \u00b6 \u25b8 upload ( file , dirPath , mutationOptions? ): Promise < any > Parameters Name Type file any dirPath any mutationOptions Object Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:879 validate \u00b6 \u25b8 validate ( document ): Promise <{}> Parameters Name Type document any Returns Promise <{}> Defined in packages/cozy-client/src/CozyClient.js:624 watchQuery \u00b6 \u25b8 watchQuery (\u2026 args ): default Parameters Name Type ...args any [] Returns default Defined in packages/cozy-client/src/CozyClient.js:1027 fromDOM \u00b6 \u25b8 Static fromDOM ( options? , selector? ): CozyClient When used from an app, CozyClient can be instantiated from the data injected by the stack in the DOM. Parameters Name Type Default value Description options any {} CozyClient constructor options selector string '[role=application]' Options Returns CozyClient CozyClient instance Defined in packages/cozy-client/src/CozyClient.js:388 fromEnv \u00b6 \u25b8 Static fromEnv ( envArg , options? ): CozyClient In konnector/service context, CozyClient can be instantiated from environment variables Parameters Name Type Description envArg any - options any Options Returns CozyClient Defined in packages/cozy-client/src/CozyClient.js:359 fromOldClient \u00b6 \u25b8 Static fromOldClient ( oldClient , options ): CozyClient To help with the transition from cozy-client-js to cozy-client, it is possible to instantiate a client with a cookie-based instance of cozy-client-js. Parameters Name Type Description oldClient any An instance of the deprecated cozy-client options any CozyStackClient options Returns CozyClient Defined in packages/cozy-client/src/CozyClient.js:309 fromOldOAuthClient \u00b6 \u25b8 Static fromOldOAuthClient ( oldClient , options ): Promise < CozyClient > To help with the transition from cozy-client-js to cozy-client, it is possible to instantiate a client with an OAuth-based instance of cozy-client-js. Warning: unlike other instantiators, this one needs to be awaited. Parameters Name Type Description oldClient any An OAuth instance of the deprecated cozy-client options any CozyStackClient options Returns Promise < CozyClient > An instance of a client, configured from the old client Defined in packages/cozy-client/src/CozyClient.js:327 registerHook \u00b6 \u25b8 Static registerHook ( doctype , name , fn ): void Hooks are an observable system for events on documents. There are at the moment only 2 hooks available. before:destroy, called just before a document is destroyed via CozyClient::destroy after:destroy, called after a document is destroyed via CozyClient::destroy example CozyClient.registerHook('io.cozy.bank.accounts', 'before:destroy', () => { console.log('A io.cozy.bank.accounts is being destroyed') }) Parameters Name Type Description doctype string Doctype on which the hook will be registered name string Name of the hook fn Function Callback to be executed Returns void Defined in packages/cozy-client/src/CozyClient.js:848", "title": "CozyClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#class-cozyclient", "text": "Responsible for Creating observable queries Hydration Creating plan for saving documents Associations", "title": "Class: CozyClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#constructor", "text": "\u2022 new CozyClient ( rawOptions? ) example const client = new CozyClient ({ schema : { todos : { doctype : 'io.cozy.todos' , relationships : { authors : { type : 'has-many' , doctype : 'io.cozy.persons' } } } } }) Cozy-Client will automatically call this.login() if provided with a token and an uri Parameters Name Type Description rawOptions ClientOptions Options Defined in packages/cozy-client/src/CozyClient.js:151", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#appmetadata", "text": "\u2022 appMetadata : AppMetadata Defined in packages/cozy-client/src/CozyClient.js:164", "title": "appMetadata"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#capabilities", "text": "\u2022 capabilities : ClientCapabilities Defined in packages/cozy-client/src/CozyClient.js:192", "title": "capabilities"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#chain", "text": "\u2022 chain : any Defined in packages/cozy-client/src/CozyClient.js:185", "title": "chain"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#client", "text": "\u2022 client : any Defined in packages/cozy-client/src/CozyClient.js:1632", "title": "client"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#instanceoptions", "text": "\u2022 instanceOptions : Object Defined in packages/cozy-client/src/CozyClient.js:172", "title": "instanceOptions"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#islogged", "text": "\u2022 isLogged : boolean Defined in packages/cozy-client/src/CozyClient.js:171", "title": "isLogged"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#isrevoked", "text": "\u2022 isRevoked : boolean Defined in packages/cozy-client/src/CozyClient.js:486", "title": "isRevoked"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#links", "text": "\u2022 links : any [] Defined in packages/cozy-client/src/CozyClient.js:182", "title": "links"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#loginpromise", "text": "\u2022 loginPromise : Promise < void > Defined in packages/cozy-client/src/CozyClient.js:165", "title": "loginPromise"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#options", "text": "\u2022 options : Object Type declaration Name Type Description autoHydrate boolean - backgroundFetching boolean If set to true, backgroundFetching will be enabled by default on every query. Meaning that, when the fetchStatus has already been loaded, it won\u2019t be updated during future fetches. Instead, a isFetching attribute will be used to indicate when background fetching is started. client any - oauth any - onError Function Default callback if a query is errored onTokenRefresh Function - stackClient any - store boolean If set to false, the client will not instantiate a Redux store automatically. Use this if you want to merge cozy-client\u2019s store with your own redux store. See here for more information. token any - uri string - warningForCustomHandlers boolean - Defined in packages/cozy-client/src/CozyClient.js:168", "title": "options"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#plugins", "text": "\u2022 plugins : Object Defined in packages/cozy-client/src/CozyClient.js:195", "title": "plugins"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#queryidgenerator", "text": "\u2022 queryIdGenerator : QueryIDGenerator Defined in packages/cozy-client/src/CozyClient.js:170", "title": "queryIdGenerator"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#schema", "text": "\u2022 schema : Schema Defined in packages/cozy-client/src/CozyClient.js:187", "title": "schema"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#stackclient", "text": "\u2022 stackClient : any Defined in packages/cozy-client/src/CozyClient.js:1607", "title": "stackClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#store", "text": "\u2022 store : any Defined in packages/cozy-client/src/CozyClient.js:1537", "title": "store"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#storeaccesors", "text": "\u2022 storeAccesors : any Defined in packages/cozy-client/src/CozyClient.js:220", "title": "storeAccesors"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#storeaccessors", "text": "\u2022 storeAccessors : Object Type declaration Name Type dispatch any get any mutate ( def : any , opts : any ) => any query ( def : any , opts : any ) => any save ( document : any , opts : any ) => any Defined in packages/cozy-client/src/CozyClient.js:1290", "title": "storeAccessors"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#fetchpolicies", "text": "\u25aa Static fetchPolicies : Object Type declaration Name Type noFetch () => boolean olderThan ( delay : number ) => Function", "title": "fetchPolicies"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#hooks", "text": "\u25aa Static hooks : Object", "title": "hooks"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#version", "text": "\u25aa Static version : string", "title": "version"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#_login", "text": "\u25b8 _login ( options ): Promise < void > Parameters Name Type options any Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:465", "title": "_login"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#addschema", "text": "\u25b8 addSchema ( schemaDefinition ): void Parameters Name Type schemaDefinition any Returns void Defined in packages/cozy-client/src/CozyClient.js:421", "title": "addSchema"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#all", "text": "\u25b8 all ( doctype ): QueryDefinition Parameters Name Type doctype any Returns QueryDefinition Defined in packages/cozy-client/src/CozyClient.js:566", "title": "all"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#authorize", "text": "\u25b8 authorize ( [options]? ): Promise < any > Creates an OAuth token with needed permissions for the current client. The authorization page URL generation can be overriding by passing a function pointer as openURLCallback parameter It is possible to skip the session creation process (when using an in-app browser) by passing a sessionCode (see https://docs.cozy.io/en/cozy-stack/auth/#post-authsession_code) Parameters Name Type Description [options] Object Authorization options [options].openURLCallback OpenURLCallback - [options].pkceCodes PKCECodes - [options].sessionCode string - Returns Promise < any > Contains the fetched token and the client information. These should be stored and used to restore the client. Defined in packages/cozy-client/src/CozyClient.js:1453", "title": "authorize"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#certifyflagship", "text": "\u25b8 certifyFlagship (): Promise < void > Perform the Flagship certification process for verifying that the current running app is a genuine Cozy application This mechanism is described in https://github.com/cozy/cozy-client/blob/master/packages/cozy-client/src/flagship-certification/README.md Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:1434", "title": "certifyFlagship"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#checkforrevocation", "text": "\u25b8 checkForRevocation (): Promise < any > Returns whether the client has been revoked on the server Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:1549", "title": "checkForRevocation"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#collection", "text": "\u25b8 collection ( doctype ): any Forwards to a stack client instance and returns a DocumentCollection instance. Parameters Name Type Description doctype string The collection doctype. Returns any Collection corresponding to the doctype Defined in packages/cozy-client/src/CozyClient.js:558", "title": "collection"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#create", "text": "\u25b8 create ( type , doc , references , options? ): Promise < any > Creates a document and saves it on the server example await client . create ( 'io.cozy.todos' , { label : 'My todo' , relationships : { authors : { data : [{ _id : 1 , _type : 'io.cozy.persons' }] } } }) Parameters Name Type Description type string Doctype of the document doc any Document to save references Object - options any Mutation options Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:613", "title": "create"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#createclient", "text": "\u25b8 createClient (): void If no stack client has been passed in options, creates a default stack client and attaches handlers for revocation and token refresh. If a stackClient has been passed in options, ensure it has handlers for revocation and token refresh. If oauth options are passed, stackClient is an OAuthStackClient. Returns void Defined in packages/cozy-client/src/CozyClient.js:1587", "title": "createClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#destroy", "text": "\u25b8 destroy ( document , mutationOptions? ): Promise < CozyClientDocument > Destroys a document. {before,after}:destroy hooks will be fired. Parameters Name Type Description document CozyClientDocument Document to be deleted mutationOptions Object - Returns Promise < CozyClientDocument > The document that has been deleted Defined in packages/cozy-client/src/CozyClient.js:869", "title": "destroy"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#dispatch", "text": "\u25b8 dispatch ( action ): any Parameters Name Type action any Returns any Defined in packages/cozy-client/src/CozyClient.js:1658", "title": "dispatch"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#emit", "text": "\u25b8 emit (\u2026 args ): void Gets overrided by MicroEE.mixin This is here just so typescript does not scream TODO Find a better way to make TS understand that emit is a method from cozy-client Parameters Name Type ...args any [] Returns void Defined in packages/cozy-client/src/CozyClient.js:234", "title": "emit"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#ensurecozymetadata", "text": "\u25b8 ensureCozyMetadata ( document , options? ): CozyClientDocument Parameters Name Type Description document CozyClientDocument Document that will be saved options Object - options.event string - Returns CozyClientDocument Defined in packages/cozy-client/src/CozyClient.js:683", "title": "ensureCozyMetadata"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#ensurequeryexists", "text": "\u25b8 ensureQueryExists ( queryId , queryDefinition , options ): void Makes sure that the query exists in the store Parameters Name Type Description queryId string Id of the query queryDefinition QueryDefinition Definition of the query options QueryOptions - Returns void Defined in packages/cozy-client/src/CozyClient.js:890", "title": "ensureQueryExists"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#ensurestore", "text": "\u25b8 ensureStore (): void Returns void Defined in packages/cozy-client/src/CozyClient.js:1540", "title": "ensureStore"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#fetch", "text": "\u25b8 fetch ( method , path , body , options? ): any Parameters Name Type method any path any body any options Object Returns any Defined in packages/cozy-client/src/CozyClient.js:562", "title": "fetch"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#fetchqueryandgetfromstate", "text": "\u25b8 fetchQueryAndGetFromState ( query ): Promise < QueryState > Executes a query and returns the results from internal store. Can be useful in pure JS context (without React) Has a behavior close to or useQuery Parameters Name Type Description query Object Query with definition and options query.definition QueryDefinition Query Definition query.options QueryOptions Query Options Returns Promise < QueryState > Query state Defined in packages/cozy-client/src/CozyClient.js:1387", "title": "fetchQueryAndGetFromState"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#find", "text": "\u25b8 find ( doctype , selector? ): QueryDefinition Parameters Name Type Default value doctype any undefined selector any undefined Returns QueryDefinition Defined in packages/cozy-client/src/CozyClient.js:575", "title": "find"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#generaterandomid", "text": "\u25b8 generateRandomId (): string Returns string Defined in packages/cozy-client/src/CozyClient.js:1265", "title": "generateRandomId"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#get", "text": "\u25b8 get ( doctype , id ): QueryDefinition Parameters Name Type doctype any id any Returns QueryDefinition Defined in packages/cozy-client/src/CozyClient.js:582", "title": "get"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getassociation", "text": "\u25b8 getAssociation ( document , associationName ): any Creates an association that is linked to the store. Parameters Name Type document any associationName any Returns any Defined in packages/cozy-client/src/CozyClient.js:1272", "title": "getAssociation"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getclient", "text": "\u25b8 getClient (): any Returns any Defined in packages/cozy-client/src/CozyClient.js:1640", "title": "getClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getcollectionfromstate", "text": "\u25b8 getCollectionFromState ( type ): CozyClientDocument [] Get a collection of documents from the internal store. Parameters Name Type Description type string Doctype of the collection Returns CozyClientDocument [] Array of documents or null if the collection does not exist. Defined in packages/cozy-client/src/CozyClient.js:1308", "title": "getCollectionFromState"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getdocumentfromstate", "text": "\u25b8 getDocumentFromState ( type , id ): CozyClientDocument Get a document from the internal store. Parameters Name Type Description type string Doctype of the document id string Id of the document Returns CozyClientDocument Document or null if the object does not exist. Defined in packages/cozy-client/src/CozyClient.js:1325", "title": "getDocumentFromState"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getdocumentsaveplan", "text": "\u25b8 getDocumentSavePlan ( document , referencesByName ): any Creates a list of mutations to execute to create a document and its relationships. const baseDoc = { _type : 'io.cozy.todo' , label : 'Go hiking' } // relations can be arrays or single objects const relationships = { attachments : [{ _id : 12345 , _type : 'io.cozy.files' }, { _id : 6789 , _type : 'io.cozy.files' }], bills : { _id : 9999 , _type : 'io.cozy.bills' } } client . getDocumentSavePlan ( baseDoc , relationships ) Parameters Name Type Description document CozyClientDocument Document to create referencesByName Object - Returns any One or more mutation to execute Defined in packages/cozy-client/src/CozyClient.js:782", "title": "getDocumentSavePlan"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getincludesrelationships", "text": "\u25b8 getIncludesRelationships ( queryDefinition ): Dictionary < any > Parameters Name Type queryDefinition any Returns Dictionary < any > Defined in packages/cozy-client/src/CozyClient.js:1192", "title": "getIncludesRelationships"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getinstanceoptions", "text": "\u25b8 getInstanceOptions (): any getInstanceOptions - Returns current instance options, such as domain or app slug Returns any Defined in packages/cozy-client/src/CozyClient.js:1667", "title": "getInstanceOptions"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getqueryfromstate", "text": "\u25b8 getQueryFromState ( id , options? ): QueryState Get a query from the internal store. Parameters Name Type Description id string Id of the query (set via Query.props.as) options Object Options options.hydrated boolean - options.singleDocData any - Returns QueryState Query state or null if it does not exist. Defined in packages/cozy-client/src/CozyClient.js:1346", "title": "getQueryFromState"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getrelationshipstoreaccessors", "text": "\u25b8 getRelationshipStoreAccessors (): Object Returns the accessors that are given to the relationships for them to deal with the stores. Relationships need to have access to the store to ping it when a modification (addById/removeById etc\u2026) has been done. This wakes the store up, which in turn will update the s and re-render the data. Returns Object Name Type dispatch any get any mutate ( def : any , opts : any ) => any query ( def : any , opts : any ) => any save ( document : any , opts : any ) => any Defined in packages/cozy-client/src/CozyClient.js:1288", "title": "getRelationshipStoreAccessors"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getsettings", "text": "\u25b8 getSettings < T >( slug , keys ): Promise < Record < T , any >> Query the cozy-app settings corresponding to the given slug and extract the value corresponding to the given key", "title": "getSettings"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#type-parameters", "text": "Name Type T extends string Parameters Name Type Description slug string the cozy-app\u2019s slug containing the setting (can be \u2018instance\u2019 for global settings) keys T [] The names of the settings to retrieve Returns Promise < Record < T , any >> The value of the requested setting Defined in packages/cozy-client/src/CozyClient.js:1768", "title": "Type parameters"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#getstackclient", "text": "\u25b8 getStackClient (): any Returns any Defined in packages/cozy-client/src/CozyClient.js:1647", "title": "getStackClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#handlerevocationchange", "text": "\u25b8 handleRevocationChange ( state ): void Sets public attribute and emits event related to revocation Parameters Name Type state any Returns void Defined in packages/cozy-client/src/CozyClient.js:1558", "title": "handleRevocationChange"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#handletokenrefresh", "text": "\u25b8 handleTokenRefresh ( token ): void Emits event when token is refreshed Parameters Name Type token any Returns void Defined in packages/cozy-client/src/CozyClient.js:1569", "title": "handleTokenRefresh"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#hydratedocument", "text": "\u25b8 hydrateDocument ( document , schemaArg ): any Resolves relationships on a document. The original document is kept in the target attribute of the relationship Parameters Name Type Description document CozyClientDocument for which relationships must be resolved schemaArg Schema - Returns any Defined in packages/cozy-client/src/CozyClient.js:1235", "title": "hydrateDocument"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#hydratedocuments", "text": "\u25b8 hydrateDocuments ( doctype , documents ): any [] Returns documents with their relationships resolved according to their schema. If related documents are not in the store, they will not be fetched automatically. Instead, the relationships will have null documents. Parameters Name Type Description doctype string Doctype of the documents being hydrated documents CozyClientDocument [] Documents to be hydrated Returns any [] Defined in packages/cozy-client/src/CozyClient.js:1212", "title": "hydrateDocuments"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#hydraterelationships", "text": "\u25b8 hydrateRelationships ( document , schemaRelationships ): Object Parameters Name Type document any schemaRelationships any Returns Object Defined in packages/cozy-client/src/CozyClient.js:1246", "title": "hydrateRelationships"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#isreactnative", "text": "\u25b8 isReactNative (): boolean Returns boolean Defined in packages/cozy-client/src/CozyClient.js:1410", "title": "isReactNative"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#loadinstanceoptionsfromdom", "text": "\u25b8 loadInstanceOptionsFromDOM ( selector? ): void loadInstanceOptionsFromDOM - Loads the dataset injected by the Stack in web pages and exposes it through getInstanceOptions Parameters Name Type Default value selector string '[role=application]' Returns void Defined in packages/cozy-client/src/CozyClient.js:1678", "title": "loadInstanceOptionsFromDOM"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#loadinstanceoptionsfromstack", "text": "\u25b8 loadInstanceOptionsFromStack (): Promise < void > loadInstanceOptionsFromStack - Loads the instance options from cozy-stack and exposes it through getInstanceOptions This method is not iso with loadInstanceOptionsFromDOM for now. Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:1699", "title": "loadInstanceOptionsFromStack"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#login", "text": "\u25b8 login ( options ): Promise < any > Notify the links that they can start and set isLogged to true. On mobile, where url/token are set after instantiation, use this method to set the token and uri via options. Emits \u201cbeforeLogin\u201d at the beginning, before links have been set up \u201clogin\u201d when the client is fully logged in and links have been set up Parameters Name Type Description options Object - options.token string If passed, the token is set on the client options.uri string If passed, the uri is set on the client Returns Promise < any > Resolves when all links have been setup and client is fully logged in Defined in packages/cozy-client/src/CozyClient.js:454", "title": "login"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#logout", "text": "\u25b8 logout (): Promise < any > Logs out the client and reset all the links Emits \u201cbeforeLogout\u201d at the beginning, before links have been reset \u201clogout\u201d when the client is fully logged out and links have been reset Returns Promise < any > Resolves when all links have been reset and client is fully logged out Defined in packages/cozy-client/src/CozyClient.js:505", "title": "logout"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#makenewdocument", "text": "\u25b8 makeNewDocument ( doctype ): any Creates (locally) a new document for the given doctype. This document is hydrated : its relationships are there and working. Parameters Name Type doctype any Returns any Defined in packages/cozy-client/src/CozyClient.js:1258", "title": "makeNewDocument"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#makeobservablequery", "text": "\u25b8 makeObservableQuery ( queryDefinition , options? ): default Parameters Name Type queryDefinition any options Object Returns default Defined in packages/cozy-client/src/CozyClient.js:1034", "title": "makeObservableQuery"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#mutate", "text": "\u25b8 mutate ( mutationDefinition , [options]? ): Promise < any > Mutate a document Parameters Name Type Description mutationDefinition any Describe the mutation [options] Object Options [options].as string - [options].update Function - [options].updateQueries Function - Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:1052", "title": "mutate"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#on", "text": "\u25b8 on (\u2026 args ): void Parameters Name Type ...args any [] Returns void Defined in packages/cozy-client/src/CozyClient.js:235", "title": "on"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#preparedocumentforsave", "text": "\u25b8 prepareDocumentForSave ( doc ): CozyClientDocument Dehydrates and adds metadata before saving a document Parameters Name Type Description doc CozyClientDocument Document that will be saved Returns CozyClientDocument Defined in packages/cozy-client/src/CozyClient.js:753", "title": "prepareDocumentForSave"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#query", "text": "\u25b8 query ( queryDefinition , [options]? ): Promise < any > Executes a query and returns its results. Results from the query will be saved internally and can be retrieved via getQueryFromState or directly using . automatically executes its query when mounted if no fetch policy has been indicated. If the query is called under the fetch policy\u2019s delay, then the query is not executed and nothing is returned. If you need a result anyway, please use fetchQueryAndGetFromState instead Parameters Name Type Description queryDefinition QueryDefinition Definition that will be executed [options] QueryOptions Options Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:917", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#queryall", "text": "\u25b8 queryAll ( queryDefinition , options? ): Promise < any > Will fetch all documents for a queryDefinition , automatically fetching more documents if the total of documents is superior to the pagination limit. Can result in a lot of network requests. Parameters Name Type Description queryDefinition QueryDefinition Definition to be executed options QueryOptions - Returns Promise < any > All documents matching the query Defined in packages/cozy-client/src/CozyClient.js:994", "title": "queryAll"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#reducer", "text": "\u25b8 reducer (): ( state : { documents : {} = {}; queries : {} = {} }, action : any ) => { documents : any ; queries : QueriesStateSlice } Returns fn \u25b8 ( state? , action ): Object Parameters Name Type Default value state Object initialState state.documents Object {} state.queries Object {} action any undefined Returns Object Name Type documents any queries QueriesStateSlice Defined in packages/cozy-client/src/CozyClient.js:1654", "title": "reducer"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#register", "text": "\u25b8 register ( cozyURL ): any Performs a complete OAuth flow using a Cordova webview or React Native WebView for auth. The register method\u2019s name has been chosen for compat reasons with the Authentication compo. Parameters Name Type Description cozyURL string Receives the URL of the cozy instance. Returns any Contains the fetched token and the client information. Defined in packages/cozy-client/src/CozyClient.js:1404", "title": "register"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#registerclientonlinks", "text": "\u25b8 registerClientOnLinks (): void Returns void Defined in packages/cozy-client/src/CozyClient.js:425", "title": "registerClientOnLinks"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#registerplugin", "text": "\u25b8 registerPlugin ( Plugin , options ): any A plugin is a class whose constructor receives the client as first argument. The main mean of interaction with the client should be with events like \u201clogin\u201d/\u201dlogout\u201d. The plugin system is meant to encourage separation of concerns, modularity and testability : instead of registering events at module level, please create a plugin that subscribes to events. Plugin instances are stored internally in the plugins attribute of the client and can be accessed via this mean. A plugin class must have the attribute pluginName that will be use as the key in the plugins object. Two plugins with the same pluginName cannot co-exist. example class AlertPlugin { constructor ( client , options ) { this . client = client this . options = options this . handleLogin = this . handleLogin . bind ( this ) this . handleLogout = this . handleLogout . bind ( this ) this . client . on ( \"login\" , this . handleLogin ) this . client . on ( \"logout\" , this . handleLogout ) } handleLogin () { alert ( this . options . onLoginAlert ) } handleLogout () { alert ( this . options . onLogoutAlert ) } } AlertPlugin . pluginName = 'alerts' client . registerPlugin ( AlertPlugin , { onLoginAlert : 'client has logged in !' , onLogoutAlert : 'client has logged out !' }) // the instance of the plugin is accessible via client . plugins . alerts Parameters Name Type Plugin any options any Returns any Defined in packages/cozy-client/src/CozyClient.js:285", "title": "registerPlugin"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#removelistener", "text": "\u25b8 removeListener (\u2026 args ): void Parameters Name Type ...args any [] Returns void Defined in packages/cozy-client/src/CozyClient.js:236", "title": "removeListener"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#renewauthorization", "text": "\u25b8 renewAuthorization (): any Renews the token if, for instance, new permissions are required or token has expired. Returns any Contains the fetched token and the client information. Defined in packages/cozy-client/src/CozyClient.js:1499", "title": "renewAuthorization"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#requestmutation", "text": "\u25b8 requestMutation ( definition ): any Parameters Name Type definition any Returns any Defined in packages/cozy-client/src/CozyClient.js:1176", "title": "requestMutation"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#resetquery", "text": "\u25b8 resetQuery ( queryId ): Promise < QueryState > Reset a query This method will reset the query state to its initial state and refetch it. Parameters Name Type Description queryId string Query id Returns Promise < QueryState > Query state Defined in packages/cozy-client/src/CozyClient.js:1797", "title": "resetQuery"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#save", "text": "\u25b8 save ( doc , mutationOptions? ): Promise < any > Create or update a document on the server Parameters Name Type Description doc any Document to save mutationOptions any Mutation options Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:635", "title": "save"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#saveafterfetchsettings", "text": "\u25b8 saveAfterFetchSettings < T >( slug , itemsOrSetter , setterKeys ): Promise < any > Save the given value into the corresponding cozy-app setting This methods will first query the cozy-app\u2019s settings before injecting the new value and then save the new resulting settings into database", "title": "saveAfterFetchSettings"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#type-parameters_1", "text": "Name Type T extends string Parameters Name Type Description slug string the cozy-app\u2019s slug containing the setting (can be \u2018instance\u2019 for global settings) itemsOrSetter Record < string , any > ( oldValue : any ) => Record < T , any > setterKeys T [] The new values of the settings to save. It can be a raw dictionnary, or a callback that should return a new dictionnary Returns Promise < any > The result of the client.save() call Defined in packages/cozy-client/src/CozyClient.js:1785", "title": "Type parameters"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#saveall", "text": "\u25b8 saveAll ( docs , mutationOptions? ): Promise < void > Saves multiple documents in one batch Can only be called with documents from the same doctype Does not support automatic creation of references Parameters Name Type Description docs CozyClientDocument [] Documents from the same doctype mutationOptions Object Mutation Options mutationOptions.as string - mutationOptions.update Function - mutationOptions.updateQueries Function - Returns Promise < void > Defined in packages/cozy-client/src/CozyClient.js:656", "title": "saveAll"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#setappmetadata", "text": "\u25b8 setAppMetadata ( newAppMetadata ): void Parameters Name Type Description newAppMetadata AppMetadata AppMetadata to update Returns void Defined in packages/cozy-client/src/CozyClient.js:1751", "title": "setAppMetadata"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#setdata", "text": "\u25b8 setData ( data ): void Directly set the data in the store, without using a query This is useful for cases like Pouch replication, which wants to set some data in the store. Parameters Name Type Description data any Data that is inserted in the store. Shape: Returns void Defined in packages/cozy-client/src/CozyClient.js:1724", "title": "setData"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#setonerror", "text": "\u25b8 setOnError ( onError ): void At any time put an error function throws {Error} onError should not have been defined yet Parameters Name Type onError Function Returns void Defined in packages/cozy-client/src/CozyClient.js:1737", "title": "setOnError"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#setstore", "text": "\u25b8 setStore ( store , [options]? ): void Sets the internal store of the client. Use this when you want to have cozy-client\u2019s internal store colocated with your existing Redux store. Typically, you would need to do this only once in your application, this is why setStore throws if you do it twice. If you really need to set the store again, use options.force = true. example const client = new CozyClient() const store = createStore(combineReducers({ todos: todoReducer, cozy: client.reducer() }) client.setStore(store) Parameters Name Type Description store any A redux store [options] Object Options [options].force boolean - Returns void Defined in packages/cozy-client/src/CozyClient.js:1525", "title": "setStore"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#startoauthflow", "text": "\u25b8 startOAuthFlow ( openURLCallback ): Promise < any > Performs a complete OAuth flow, including updating the internal token at the end. Parameters Name Type Description openURLCallback OpenURLCallback Receives the URL to present to the user as a parameter, and should return a promise that resolves with the URL the user was redirected to after accepting the permissions. Returns Promise < any > Contains the fetched token and the client information. These should be stored and used to restore the client. Defined in packages/cozy-client/src/CozyClient.js:1420", "title": "startOAuthFlow"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#tojson", "text": "\u25b8 toJSON (): CozyClient Returns CozyClient Defined in packages/cozy-client/src/CozyClient.js:1744", "title": "toJSON"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#triggerhook", "text": "\u25b8 triggerHook ( name , document ): void Parameters Name Type name any document any Returns void Defined in packages/cozy-client/src/CozyClient.js:854", "title": "triggerHook"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#upload", "text": "\u25b8 upload ( file , dirPath , mutationOptions? ): Promise < any > Parameters Name Type file any dirPath any mutationOptions Object Returns Promise < any > Defined in packages/cozy-client/src/CozyClient.js:879", "title": "upload"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#validate", "text": "\u25b8 validate ( document ): Promise <{}> Parameters Name Type document any Returns Promise <{}> Defined in packages/cozy-client/src/CozyClient.js:624", "title": "validate"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#watchquery", "text": "\u25b8 watchQuery (\u2026 args ): default Parameters Name Type ...args any [] Returns default Defined in packages/cozy-client/src/CozyClient.js:1027", "title": "watchQuery"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#fromdom", "text": "\u25b8 Static fromDOM ( options? , selector? ): CozyClient When used from an app, CozyClient can be instantiated from the data injected by the stack in the DOM. Parameters Name Type Default value Description options any {} CozyClient constructor options selector string '[role=application]' Options Returns CozyClient CozyClient instance Defined in packages/cozy-client/src/CozyClient.js:388", "title": "fromDOM"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#fromenv", "text": "\u25b8 Static fromEnv ( envArg , options? ): CozyClient In konnector/service context, CozyClient can be instantiated from environment variables Parameters Name Type Description envArg any - options any Options Returns CozyClient Defined in packages/cozy-client/src/CozyClient.js:359", "title": "fromEnv"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#fromoldclient", "text": "\u25b8 Static fromOldClient ( oldClient , options ): CozyClient To help with the transition from cozy-client-js to cozy-client, it is possible to instantiate a client with a cookie-based instance of cozy-client-js. Parameters Name Type Description oldClient any An instance of the deprecated cozy-client options any CozyStackClient options Returns CozyClient Defined in packages/cozy-client/src/CozyClient.js:309", "title": "fromOldClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#fromoldoauthclient", "text": "\u25b8 Static fromOldOAuthClient ( oldClient , options ): Promise < CozyClient > To help with the transition from cozy-client-js to cozy-client, it is possible to instantiate a client with an OAuth-based instance of cozy-client-js. Warning: unlike other instantiators, this one needs to be awaited. Parameters Name Type Description oldClient any An OAuth instance of the deprecated cozy-client options any CozyStackClient options Returns Promise < CozyClient > An instance of a client, configured from the old client Defined in packages/cozy-client/src/CozyClient.js:327", "title": "fromOldOAuthClient"}, {"location": "cozy-client/api/cozy-client/classes/CozyClient/#registerhook", "text": "\u25b8 Static registerHook ( doctype , name , fn ): void Hooks are an observable system for events on documents. There are at the moment only 2 hooks available. before:destroy, called just before a document is destroyed via CozyClient::destroy after:destroy, called after a document is destroyed via CozyClient::destroy example CozyClient.registerHook('io.cozy.bank.accounts', 'before:destroy', () => { console.log('A io.cozy.bank.accounts is being destroyed') }) Parameters Name Type Description doctype string Doctype on which the hook will be registered name string Name of the hook fn Function Callback to be executed Returns void Defined in packages/cozy-client/src/CozyClient.js:848", "title": "registerHook"}, {"location": "cozy-client/api/cozy-client/classes/CozyLink/", "text": "cozy-client / CozyLink Class: CozyLink \u00b6 Hierarchy \u00b6 CozyLink \u21b3 StackLink Constructors \u00b6 constructor \u00b6 \u2022 new CozyLink ( requestHandler ) Parameters Name Type requestHandler any Defined in packages/cozy-client/src/CozyLink.js:2 Methods \u00b6 request \u00b6 \u25b8 request ( operation , result , forward ): void Parameters Name Type operation any result any forward any Returns void Defined in packages/cozy-client/src/CozyLink.js:8", "title": "CozyLink"}, {"location": "cozy-client/api/cozy-client/classes/CozyLink/#class-cozylink", "text": "", "title": "Class: CozyLink"}, {"location": "cozy-client/api/cozy-client/classes/CozyLink/#hierarchy", "text": "CozyLink \u21b3 StackLink", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/CozyLink/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/CozyLink/#constructor", "text": "\u2022 new CozyLink ( requestHandler ) Parameters Name Type requestHandler any Defined in packages/cozy-client/src/CozyLink.js:2", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/CozyLink/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/CozyLink/#request", "text": "\u25b8 request ( operation , result , forward ): void Parameters Name Type operation any result any forward any Returns void Defined in packages/cozy-client/src/CozyLink.js:8", "title": "request"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/", "text": "cozy-client / CozyProvider Class: CozyProvider \u00b6 Hierarchy \u00b6 Component \u21b3 CozyProvider Constructors \u00b6 constructor \u00b6 \u2022 new CozyProvider ( props , context ) Parameters Name Type props any context any Overrides Component.constructor Defined in packages/cozy-client/src/Provider.jsx:21 Properties \u00b6 childContextTypes \u00b6 \u25aa Static childContextTypes : Object Type declaration Name Type client Validator < object > store Requireable < object > Defined in packages/cozy-client/src/Provider.jsx:31 contextTypes \u00b6 \u25aa Static contextTypes : Object Type declaration Name Type store Requireable < object > Defined in packages/cozy-client/src/Provider.jsx:36 propTypes \u00b6 \u25aa Static propTypes : Object Type declaration Name Type children Validator < ReactElementLike client Validator < object > store Requireable < InferProps <{ dispatch : Validator <(\u2026 args : any []) => any > = PropTypes.func.isRequired; getState : Validator <(\u2026 args : any []) => any > = PropTypes.func.isRequired; subscribe : Validator <(\u2026 args : any []) => any > = PropTypes.func.isRequired }>> Defined in packages/cozy-client/src/Provider.jsx:12 Methods \u00b6 getChildContext \u00b6 \u25b8 getChildContext (): Object Returns Object Name Type client any store any Defined in packages/cozy-client/src/Provider.jsx:40 render \u00b6 \u25b8 render (): Element Returns Element Overrides Component.render Defined in packages/cozy-client/src/Provider.jsx:47", "title": "CozyProvider"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#class-cozyprovider", "text": "", "title": "Class: CozyProvider"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#hierarchy", "text": "Component \u21b3 CozyProvider", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#constructor", "text": "\u2022 new CozyProvider ( props , context ) Parameters Name Type props any context any Overrides Component.constructor Defined in packages/cozy-client/src/Provider.jsx:21", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#childcontexttypes", "text": "\u25aa Static childContextTypes : Object Type declaration Name Type client Validator < object > store Requireable < object > Defined in packages/cozy-client/src/Provider.jsx:31", "title": "childContextTypes"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#contexttypes", "text": "\u25aa Static contextTypes : Object Type declaration Name Type store Requireable < object > Defined in packages/cozy-client/src/Provider.jsx:36", "title": "contextTypes"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#proptypes", "text": "\u25aa Static propTypes : Object Type declaration Name Type children Validator < ReactElementLike client Validator < object > store Requireable < InferProps <{ dispatch : Validator <(\u2026 args : any []) => any > = PropTypes.func.isRequired; getState : Validator <(\u2026 args : any []) => any > = PropTypes.func.isRequired; subscribe : Validator <(\u2026 args : any []) => any > = PropTypes.func.isRequired }>> Defined in packages/cozy-client/src/Provider.jsx:12", "title": "propTypes"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#getchildcontext", "text": "\u25b8 getChildContext (): Object Returns Object Name Type client any store any Defined in packages/cozy-client/src/Provider.jsx:40", "title": "getChildContext"}, {"location": "cozy-client/api/cozy-client/classes/CozyProvider/#render", "text": "\u25b8 render (): Element Returns Element Overrides Component.render Defined in packages/cozy-client/src/Provider.jsx:47", "title": "render"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/", "text": "cozy-client / HasMany Class: HasMany \u00b6 Related documents are stored in the relationships attribute of the object, following the JSON API spec. Responsible for Creating relationships Removing relationships description const schema = { todos: { doctype: 'io.cozy.todos', relationships: { tasks: { doctype: 'io.cozy.tasks', type: 'has-many' } } } } const todo = { label: \"Protect people's privacy\", relationships: { tasks: { data: [ {_id: 1, _type: 'io.cozy.tasks'}, {_id: 2, _type: 'io.cozy.tasks'} ] } } } Hierarchy \u00b6 Association \u21b3 HasMany \u21b3\u21b3 HasManyTriggers Constructors \u00b6 constructor \u00b6 \u2022 new HasMany ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87 Properties \u00b6 dispatch \u00b6 \u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144 doctype \u00b6 \u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109 get \u00b6 \u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116 mutate \u00b6 \u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131 name \u00b6 \u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101 query \u00b6 \u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124 save \u00b6 \u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138 target \u00b6 \u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94 Accessors \u00b6 count \u00b6 \u2022 get count (): number Returns the total number of documents in the relationship. Does not handle documents absent from the store. If you want to do that, you can use .data.length. Returns number Total number of documents in the relationships Defined in packages/cozy-client/src/associations/HasMany.js:93 data \u00b6 \u2022 get data (): any Returns store documents Returns any Overrides Association.data Defined in packages/cozy-client/src/associations/HasMany.js:76 hasMore \u00b6 \u2022 get hasMore (): any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:82 raw \u00b6 \u2022 get raw (): any Returns any Overrides Association.raw Defined in packages/cozy-client/src/associations/HasMany.js:69 Methods \u00b6 add \u00b6 \u25b8 add ( docsArg ): CozyClientDocument Add the relationships to the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to add as relationships Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasMany.js:124 addById \u00b6 \u25b8 addById ( idsArg ): any Add a referenced document by id. You need to call save() in order to synchronize your document with the store. todo We shouldn\u2019t create the array of relationship manually since it\u2019ll not be present in the store as well. We certainly should use something like updateRelationship Parameters Name Type idsArg any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:174 addTargetRelationships \u00b6 \u25b8 addTargetRelationships ( idsArg ): void Update target document with relationships Parameters Name Type Description idsArg string [] The ids to add as a relationship Returns void Defined in packages/cozy-client/src/associations/HasMany.js:147 containsById \u00b6 \u25b8 containsById ( id ): boolean Parameters Name Type id any Returns boolean Defined in packages/cozy-client/src/associations/HasMany.js:108 dehydrate \u00b6 \u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:256 exists \u00b6 \u25b8 exists ( document ): boolean Parameters Name Type document any Returns boolean Defined in packages/cozy-client/src/associations/HasMany.js:104 existsById \u00b6 \u25b8 existsById ( id ): boolean Parameters Name Type id any Returns boolean Defined in packages/cozy-client/src/associations/HasMany.js:114 fetchMore \u00b6 \u25b8 fetchMore (): void Returns void Defined in packages/cozy-client/src/associations/HasMany.js:100 getRelationship \u00b6 \u25b8 getRelationship (): any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:207 remove \u00b6 \u25b8 remove ( docsArg ): CozyClientDocument Remove the relationships from the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to remove as relationships Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasMany.js:136 removeById \u00b6 \u25b8 removeById ( idsArg ): any Parameters Name Type idsArg any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:193 removeTargetRelationships \u00b6 \u25b8 removeTargetRelationships ( idsArg ): void Remove relationships from target document Parameters Name Type Description idsArg string [] The ids to remove from the target relationships Returns void Defined in packages/cozy-client/src/associations/HasMany.js:184 updateMetaCount \u00b6 \u25b8 updateMetaCount (): void Returns void Defined in packages/cozy-client/src/associations/HasMany.js:198 updateRelationship \u00b6 \u25b8 updateRelationship ( target , updateFn ): any Parameters Name Type target any updateFn any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:228 updateRelationshipData \u00b6 \u25b8 updateRelationshipData ( getUpdatedRelationshipData ): ( dispatch : any , getState : any ) => void Parameters Name Type getUpdatedRelationshipData any Returns fn \u25b8 ( dispatch , getState ): void Parameters Name Type dispatch any getState any Returns void Defined in packages/cozy-client/src/associations/HasMany.js:232 updateTargetRelationship \u00b6 \u25b8 updateTargetRelationship ( store , updateFn ): void Parameters Name Type store any updateFn any Returns void Defined in packages/cozy-client/src/associations/HasMany.js:221 getHasManyItem \u00b6 \u25b8 Static getHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Defined in packages/cozy-client/src/associations/HasMany.js:289 getHasManyItems \u00b6 \u25b8 Static getHasManyItems ( doc , relName ): any Parameters Name Type doc any relName any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:298 query \u00b6 \u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasMany.js:275 removeHasManyItem \u00b6 \u25b8 Static removeHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Defined in packages/cozy-client/src/associations/HasMany.js:336 setHasManyItem \u00b6 \u25b8 Static setHasManyItem ( doc , relName , relItemId , relItemAttrs ): any Parameters Name Type doc any relName string relItemId string relItemAttrs any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:310 updateHasManyItem \u00b6 \u25b8 Static updateHasManyItem ( doc , relName , relItemId , updater ): any Parameters Name Type doc any relName string relItemId string updater Function Returns any Defined in packages/cozy-client/src/associations/HasMany.js:360 updateRelationship \u00b6 \u25b8 Static updateRelationship ( doc , relName , updateFn ): any Parameters Name Type doc any relName any updateFn any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:371", "title": "HasMany"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#class-hasmany", "text": "Related documents are stored in the relationships attribute of the object, following the JSON API spec. Responsible for Creating relationships Removing relationships description const schema = { todos: { doctype: 'io.cozy.todos', relationships: { tasks: { doctype: 'io.cozy.tasks', type: 'has-many' } } } } const todo = { label: \"Protect people's privacy\", relationships: { tasks: { data: [ {_id: 1, _type: 'io.cozy.tasks'}, {_id: 2, _type: 'io.cozy.tasks'} ] } } }", "title": "Class: HasMany"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#hierarchy", "text": "Association \u21b3 HasMany \u21b3\u21b3 HasManyTriggers", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#constructor", "text": "\u2022 new HasMany ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#dispatch", "text": "\u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144", "title": "dispatch"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#doctype", "text": "\u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109", "title": "doctype"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#get", "text": "\u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116", "title": "get"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#mutate", "text": "\u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131", "title": "mutate"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#name", "text": "\u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101", "title": "name"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#query", "text": "\u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#save", "text": "\u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138", "title": "save"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#target", "text": "\u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94", "title": "target"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#accessors", "text": "", "title": "Accessors"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#count", "text": "\u2022 get count (): number Returns the total number of documents in the relationship. Does not handle documents absent from the store. If you want to do that, you can use .data.length. Returns number Total number of documents in the relationships Defined in packages/cozy-client/src/associations/HasMany.js:93", "title": "count"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#data", "text": "\u2022 get data (): any Returns store documents Returns any Overrides Association.data Defined in packages/cozy-client/src/associations/HasMany.js:76", "title": "data"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#hasmore", "text": "\u2022 get hasMore (): any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:82", "title": "hasMore"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#raw", "text": "\u2022 get raw (): any Returns any Overrides Association.raw Defined in packages/cozy-client/src/associations/HasMany.js:69", "title": "raw"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#add", "text": "\u25b8 add ( docsArg ): CozyClientDocument Add the relationships to the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to add as relationships Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasMany.js:124", "title": "add"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#addbyid", "text": "\u25b8 addById ( idsArg ): any Add a referenced document by id. You need to call save() in order to synchronize your document with the store. todo We shouldn\u2019t create the array of relationship manually since it\u2019ll not be present in the store as well. We certainly should use something like updateRelationship Parameters Name Type idsArg any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:174", "title": "addById"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#addtargetrelationships", "text": "\u25b8 addTargetRelationships ( idsArg ): void Update target document with relationships Parameters Name Type Description idsArg string [] The ids to add as a relationship Returns void Defined in packages/cozy-client/src/associations/HasMany.js:147", "title": "addTargetRelationships"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#containsbyid", "text": "\u25b8 containsById ( id ): boolean Parameters Name Type id any Returns boolean Defined in packages/cozy-client/src/associations/HasMany.js:108", "title": "containsById"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#dehydrate", "text": "\u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:256", "title": "dehydrate"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#exists", "text": "\u25b8 exists ( document ): boolean Parameters Name Type document any Returns boolean Defined in packages/cozy-client/src/associations/HasMany.js:104", "title": "exists"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#existsbyid", "text": "\u25b8 existsById ( id ): boolean Parameters Name Type id any Returns boolean Defined in packages/cozy-client/src/associations/HasMany.js:114", "title": "existsById"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#fetchmore", "text": "\u25b8 fetchMore (): void Returns void Defined in packages/cozy-client/src/associations/HasMany.js:100", "title": "fetchMore"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#getrelationship", "text": "\u25b8 getRelationship (): any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:207", "title": "getRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#remove", "text": "\u25b8 remove ( docsArg ): CozyClientDocument Remove the relationships from the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to remove as relationships Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasMany.js:136", "title": "remove"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#removebyid", "text": "\u25b8 removeById ( idsArg ): any Parameters Name Type idsArg any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:193", "title": "removeById"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#removetargetrelationships", "text": "\u25b8 removeTargetRelationships ( idsArg ): void Remove relationships from target document Parameters Name Type Description idsArg string [] The ids to remove from the target relationships Returns void Defined in packages/cozy-client/src/associations/HasMany.js:184", "title": "removeTargetRelationships"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#updatemetacount", "text": "\u25b8 updateMetaCount (): void Returns void Defined in packages/cozy-client/src/associations/HasMany.js:198", "title": "updateMetaCount"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#updaterelationship", "text": "\u25b8 updateRelationship ( target , updateFn ): any Parameters Name Type target any updateFn any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:228", "title": "updateRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#updaterelationshipdata", "text": "\u25b8 updateRelationshipData ( getUpdatedRelationshipData ): ( dispatch : any , getState : any ) => void Parameters Name Type getUpdatedRelationshipData any Returns fn \u25b8 ( dispatch , getState ): void Parameters Name Type dispatch any getState any Returns void Defined in packages/cozy-client/src/associations/HasMany.js:232", "title": "updateRelationshipData"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#updatetargetrelationship", "text": "\u25b8 updateTargetRelationship ( store , updateFn ): void Parameters Name Type store any updateFn any Returns void Defined in packages/cozy-client/src/associations/HasMany.js:221", "title": "updateTargetRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#gethasmanyitem", "text": "\u25b8 Static getHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Defined in packages/cozy-client/src/associations/HasMany.js:289", "title": "getHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#gethasmanyitems", "text": "\u25b8 Static getHasManyItems ( doc , relName ): any Parameters Name Type doc any relName any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:298", "title": "getHasManyItems"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#query_1", "text": "\u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasMany.js:275", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#removehasmanyitem", "text": "\u25b8 Static removeHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Defined in packages/cozy-client/src/associations/HasMany.js:336", "title": "removeHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#sethasmanyitem", "text": "\u25b8 Static setHasManyItem ( doc , relName , relItemId , relItemAttrs ): any Parameters Name Type doc any relName string relItemId string relItemAttrs any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:310", "title": "setHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#updatehasmanyitem", "text": "\u25b8 Static updateHasManyItem ( doc , relName , relItemId , updater ): any Parameters Name Type doc any relName string relItemId string updater Function Returns any Defined in packages/cozy-client/src/associations/HasMany.js:360", "title": "updateHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasMany/#updaterelationship_1", "text": "\u25b8 Static updateRelationship ( doc , relName , updateFn ): any Parameters Name Type doc any relName any updateFn any Returns any Defined in packages/cozy-client/src/associations/HasMany.js:371", "title": "updateRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/", "text": "cozy-client / HasManyInPlace Class: HasManyInPlace \u00b6 Used when related documents are stored directly under the attribute with only the ids. property {Function} get description An example document representing a TODO. See as the related tasks are represented via ids. const todo = { label : \"Protect people's privacy\" , tasks : [ 1 , 2 ] } Here is the Schema that would represent this kind of document. Components receiving todos via Query s would have an instance of HasManyInPlace as their tasks attribute. const schema = { todos : { doctype : 'io.cozy.todos' , relationships : { tasks : { doctype : 'io.cozy.tasks' , type : 'has-many-in-place' } } } } const todo = { label : \"Get rich\" , tasks : [ 1 , 2 ] } Hierarchy \u00b6 Association \u21b3 HasManyInPlace Constructors \u00b6 constructor \u00b6 \u2022 new HasManyInPlace ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87 Properties \u00b6 dispatch \u00b6 \u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144 doctype \u00b6 \u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109 get \u00b6 \u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116 mutate \u00b6 \u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131 name \u00b6 \u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101 query \u00b6 \u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124 save \u00b6 \u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138 target \u00b6 \u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94 Accessors \u00b6 data \u00b6 \u2022 get data (): any [] Returns any [] Overrides Association.data Defined in packages/cozy-client/src/associations/HasManyInPlace.js:87 raw \u00b6 \u2022 get raw (): string [] Raw property Returns string [] Overrides Association.raw Defined in packages/cozy-client/src/associations/HasManyInPlace.js:53 Methods \u00b6 addById \u00b6 \u25b8 addById ( id ): void Parameters Name Type id any Returns void Defined in packages/cozy-client/src/associations/HasManyInPlace.js:57 dehydrate \u00b6 \u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasManyInPlace.js:80 existsById \u00b6 \u25b8 existsById ( id ): boolean Parameters Name Type id any Returns boolean Defined in packages/cozy-client/src/associations/HasManyInPlace.js:70 getRelationship \u00b6 \u25b8 getRelationship (): any Returns any Defined in packages/cozy-client/src/associations/HasManyInPlace.js:75 removeById \u00b6 \u25b8 removeById ( id ): void Parameters Name Type id any Returns void Defined in packages/cozy-client/src/associations/HasManyInPlace.js:62 query \u00b6 \u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasManyInPlace.js:99", "title": "HasManyInPlace"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#class-hasmanyinplace", "text": "Used when related documents are stored directly under the attribute with only the ids. property {Function} get description An example document representing a TODO. See as the related tasks are represented via ids. const todo = { label : \"Protect people's privacy\" , tasks : [ 1 , 2 ] } Here is the Schema that would represent this kind of document. Components receiving todos via Query s would have an instance of HasManyInPlace as their tasks attribute. const schema = { todos : { doctype : 'io.cozy.todos' , relationships : { tasks : { doctype : 'io.cozy.tasks' , type : 'has-many-in-place' } } } } const todo = { label : \"Get rich\" , tasks : [ 1 , 2 ] }", "title": "Class: HasManyInPlace"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#hierarchy", "text": "Association \u21b3 HasManyInPlace", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#constructor", "text": "\u2022 new HasManyInPlace ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#dispatch", "text": "\u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144", "title": "dispatch"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#doctype", "text": "\u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109", "title": "doctype"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#get", "text": "\u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116", "title": "get"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#mutate", "text": "\u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131", "title": "mutate"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#name", "text": "\u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101", "title": "name"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#query", "text": "\u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#save", "text": "\u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138", "title": "save"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#target", "text": "\u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94", "title": "target"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#accessors", "text": "", "title": "Accessors"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#data", "text": "\u2022 get data (): any [] Returns any [] Overrides Association.data Defined in packages/cozy-client/src/associations/HasManyInPlace.js:87", "title": "data"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#raw", "text": "\u2022 get raw (): string [] Raw property Returns string [] Overrides Association.raw Defined in packages/cozy-client/src/associations/HasManyInPlace.js:53", "title": "raw"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#addbyid", "text": "\u25b8 addById ( id ): void Parameters Name Type id any Returns void Defined in packages/cozy-client/src/associations/HasManyInPlace.js:57", "title": "addById"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#dehydrate", "text": "\u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasManyInPlace.js:80", "title": "dehydrate"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#existsbyid", "text": "\u25b8 existsById ( id ): boolean Parameters Name Type id any Returns boolean Defined in packages/cozy-client/src/associations/HasManyInPlace.js:70", "title": "existsById"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#getrelationship", "text": "\u25b8 getRelationship (): any Returns any Defined in packages/cozy-client/src/associations/HasManyInPlace.js:75", "title": "getRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#removebyid", "text": "\u25b8 removeById ( id ): void Parameters Name Type id any Returns void Defined in packages/cozy-client/src/associations/HasManyInPlace.js:62", "title": "removeById"}, {"location": "cozy-client/api/cozy-client/classes/HasManyInPlace/#query_1", "text": "\u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasManyInPlace.js:99", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/", "text": "cozy-client / HasManyTriggers Class: HasManyTriggers \u00b6 Association used for konnectors to retrieve all their related triggers. Hierarchy \u00b6 HasMany \u21b3 HasManyTriggers Constructors \u00b6 constructor \u00b6 \u2022 new HasManyTriggers ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from HasMany . constructor Defined in packages/cozy-client/src/associations/Association.js:87 Properties \u00b6 dispatch \u00b6 \u2022 dispatch : Function Dispatch an action on the store. Inherited from HasMany . dispatch Defined in packages/cozy-client/src/associations/Association.js:144 doctype \u00b6 \u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from HasMany . doctype Defined in packages/cozy-client/src/associations/Association.js:109 get \u00b6 \u2022 get : Function Returns the document from the store Inherited from HasMany . get Defined in packages/cozy-client/src/associations/Association.js:116 mutate \u00b6 \u2022 mutate : Function Performs a mutation on the relationship. function Inherited from HasMany . mutate Defined in packages/cozy-client/src/associations/Association.js:131 name \u00b6 \u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from HasMany . name Defined in packages/cozy-client/src/associations/Association.js:101 query \u00b6 \u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from HasMany . query Defined in packages/cozy-client/src/associations/Association.js:124 save \u00b6 \u2022 save : Function Saves the relationship in store. Inherited from HasMany . save Defined in packages/cozy-client/src/associations/Association.js:138 target \u00b6 \u2022 target : any The original document declaring the relationship Inherited from HasMany . target Defined in packages/cozy-client/src/associations/Association.js:94 Accessors \u00b6 count \u00b6 \u2022 get count (): number Returns the total number of documents in the relationship. Does not handle documents absent from the store. If you want to do that, you can use .data.length. Returns number Total number of documents in the relationships Inherited from HasMany.count Defined in packages/cozy-client/src/associations/HasMany.js:93 data \u00b6 \u2022 get data (): any Returns any Overrides HasMany.data Defined in packages/cozy-client/src/associations/HasManyTriggers.js:12 hasMore \u00b6 \u2022 get hasMore (): any Returns any Inherited from HasMany.hasMore Defined in packages/cozy-client/src/associations/HasMany.js:82 raw \u00b6 \u2022 get raw (): any Returns any Inherited from HasMany.raw Defined in packages/cozy-client/src/associations/HasMany.js:69 Methods \u00b6 add \u00b6 \u25b8 add ( docsArg ): CozyClientDocument Add the relationships to the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to add as relationships Returns CozyClientDocument The saved target document Inherited from HasMany . add Defined in packages/cozy-client/src/associations/HasMany.js:124 addById \u00b6 \u25b8 addById ( idsArg ): any Add a referenced document by id. You need to call save() in order to synchronize your document with the store. todo We shouldn\u2019t create the array of relationship manually since it\u2019ll not be present in the store as well. We certainly should use something like updateRelationship Parameters Name Type idsArg any Returns any Inherited from HasMany . addById Defined in packages/cozy-client/src/associations/HasMany.js:174 addTargetRelationships \u00b6 \u25b8 addTargetRelationships ( idsArg ): void Update target document with relationships Parameters Name Type Description idsArg string [] The ids to add as a relationship Returns void Inherited from HasMany . addTargetRelationships Defined in packages/cozy-client/src/associations/HasMany.js:147 containsById \u00b6 \u25b8 containsById ( id ): boolean Parameters Name Type id any Returns boolean Inherited from HasMany . containsById Defined in packages/cozy-client/src/associations/HasMany.js:108 dehydrate \u00b6 \u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Inherited from HasMany . dehydrate Defined in packages/cozy-client/src/associations/HasMany.js:256 exists \u00b6 \u25b8 exists ( document ): boolean Parameters Name Type document any Returns boolean Inherited from HasMany . exists Defined in packages/cozy-client/src/associations/HasMany.js:104 existsById \u00b6 \u25b8 existsById ( id ): boolean Parameters Name Type id any Returns boolean Inherited from HasMany . existsById Defined in packages/cozy-client/src/associations/HasMany.js:114 fetchMore \u00b6 \u25b8 fetchMore (): void Returns void Inherited from HasMany . fetchMore Defined in packages/cozy-client/src/associations/HasMany.js:100 getRelationship \u00b6 \u25b8 getRelationship (): any Returns any Inherited from HasMany . getRelationship Defined in packages/cozy-client/src/associations/HasMany.js:207 remove \u00b6 \u25b8 remove ( docsArg ): CozyClientDocument Remove the relationships from the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to remove as relationships Returns CozyClientDocument The saved target document Inherited from HasMany . remove Defined in packages/cozy-client/src/associations/HasMany.js:136 removeById \u00b6 \u25b8 removeById ( idsArg ): any Parameters Name Type idsArg any Returns any Inherited from HasMany . removeById Defined in packages/cozy-client/src/associations/HasMany.js:193 removeTargetRelationships \u00b6 \u25b8 removeTargetRelationships ( idsArg ): void Remove relationships from target document Parameters Name Type Description idsArg string [] The ids to remove from the target relationships Returns void Inherited from HasMany . removeTargetRelationships Defined in packages/cozy-client/src/associations/HasMany.js:184 updateMetaCount \u00b6 \u25b8 updateMetaCount (): void Returns void Inherited from HasMany . updateMetaCount Defined in packages/cozy-client/src/associations/HasMany.js:198 updateRelationship \u00b6 \u25b8 updateRelationship ( target , updateFn ): any Parameters Name Type target any updateFn any Returns any Inherited from HasMany . updateRelationship Defined in packages/cozy-client/src/associations/HasMany.js:228 updateRelationshipData \u00b6 \u25b8 updateRelationshipData ( getUpdatedRelationshipData ): ( dispatch : any , getState : any ) => void Parameters Name Type getUpdatedRelationshipData any Returns fn \u25b8 ( dispatch , getState ): void Parameters Name Type dispatch any getState any Returns void Inherited from HasMany . updateRelationshipData Defined in packages/cozy-client/src/associations/HasMany.js:232 updateTargetRelationship \u00b6 \u25b8 updateTargetRelationship ( store , updateFn ): void Parameters Name Type store any updateFn any Returns void Inherited from HasMany . updateTargetRelationship Defined in packages/cozy-client/src/associations/HasMany.js:221 getHasManyItem \u00b6 \u25b8 Static getHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Inherited from HasMany . getHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:289 getHasManyItems \u00b6 \u25b8 Static getHasManyItems ( doc , relName ): any Parameters Name Type doc any relName any Returns any Inherited from HasMany . getHasManyItems Defined in packages/cozy-client/src/associations/HasMany.js:298 query \u00b6 \u25b8 Static query ( doc , client ): QueryDefinition In this association the query is special, we need to fetch all the triggers having for the \u2018konnector\u2019 worker, and then filter them based on their message.konnector attribute Parameters Name Type doc any client any Returns QueryDefinition Overrides HasMany . query Defined in packages/cozy-client/src/associations/HasManyTriggers.js:21 removeHasManyItem \u00b6 \u25b8 Static removeHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Inherited from HasMany . removeHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:336 setHasManyItem \u00b6 \u25b8 Static setHasManyItem ( doc , relName , relItemId , relItemAttrs ): any Parameters Name Type doc any relName string relItemId string relItemAttrs any Returns any Inherited from HasMany . setHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:310 updateHasManyItem \u00b6 \u25b8 Static updateHasManyItem ( doc , relName , relItemId , updater ): any Parameters Name Type doc any relName string relItemId string updater Function Returns any Inherited from HasMany . updateHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:360 updateRelationship \u00b6 \u25b8 Static updateRelationship ( doc , relName , updateFn ): any Parameters Name Type doc any relName any updateFn any Returns any Inherited from HasMany . updateRelationship Defined in packages/cozy-client/src/associations/HasMany.js:371", "title": "HasManyTriggers"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#class-hasmanytriggers", "text": "Association used for konnectors to retrieve all their related triggers.", "title": "Class: HasManyTriggers"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#hierarchy", "text": "HasMany \u21b3 HasManyTriggers", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#constructor", "text": "\u2022 new HasManyTriggers ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from HasMany . constructor Defined in packages/cozy-client/src/associations/Association.js:87", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#dispatch", "text": "\u2022 dispatch : Function Dispatch an action on the store. Inherited from HasMany . dispatch Defined in packages/cozy-client/src/associations/Association.js:144", "title": "dispatch"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#doctype", "text": "\u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from HasMany . doctype Defined in packages/cozy-client/src/associations/Association.js:109", "title": "doctype"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#get", "text": "\u2022 get : Function Returns the document from the store Inherited from HasMany . get Defined in packages/cozy-client/src/associations/Association.js:116", "title": "get"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#mutate", "text": "\u2022 mutate : Function Performs a mutation on the relationship. function Inherited from HasMany . mutate Defined in packages/cozy-client/src/associations/Association.js:131", "title": "mutate"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#name", "text": "\u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from HasMany . name Defined in packages/cozy-client/src/associations/Association.js:101", "title": "name"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#query", "text": "\u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from HasMany . query Defined in packages/cozy-client/src/associations/Association.js:124", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#save", "text": "\u2022 save : Function Saves the relationship in store. Inherited from HasMany . save Defined in packages/cozy-client/src/associations/Association.js:138", "title": "save"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#target", "text": "\u2022 target : any The original document declaring the relationship Inherited from HasMany . target Defined in packages/cozy-client/src/associations/Association.js:94", "title": "target"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#accessors", "text": "", "title": "Accessors"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#count", "text": "\u2022 get count (): number Returns the total number of documents in the relationship. Does not handle documents absent from the store. If you want to do that, you can use .data.length. Returns number Total number of documents in the relationships Inherited from HasMany.count Defined in packages/cozy-client/src/associations/HasMany.js:93", "title": "count"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#data", "text": "\u2022 get data (): any Returns any Overrides HasMany.data Defined in packages/cozy-client/src/associations/HasManyTriggers.js:12", "title": "data"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#hasmore", "text": "\u2022 get hasMore (): any Returns any Inherited from HasMany.hasMore Defined in packages/cozy-client/src/associations/HasMany.js:82", "title": "hasMore"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#raw", "text": "\u2022 get raw (): any Returns any Inherited from HasMany.raw Defined in packages/cozy-client/src/associations/HasMany.js:69", "title": "raw"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#add", "text": "\u25b8 add ( docsArg ): CozyClientDocument Add the relationships to the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to add as relationships Returns CozyClientDocument The saved target document Inherited from HasMany . add Defined in packages/cozy-client/src/associations/HasMany.js:124", "title": "add"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#addbyid", "text": "\u25b8 addById ( idsArg ): any Add a referenced document by id. You need to call save() in order to synchronize your document with the store. todo We shouldn\u2019t create the array of relationship manually since it\u2019ll not be present in the store as well. We certainly should use something like updateRelationship Parameters Name Type idsArg any Returns any Inherited from HasMany . addById Defined in packages/cozy-client/src/associations/HasMany.js:174", "title": "addById"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#addtargetrelationships", "text": "\u25b8 addTargetRelationships ( idsArg ): void Update target document with relationships Parameters Name Type Description idsArg string [] The ids to add as a relationship Returns void Inherited from HasMany . addTargetRelationships Defined in packages/cozy-client/src/associations/HasMany.js:147", "title": "addTargetRelationships"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#containsbyid", "text": "\u25b8 containsById ( id ): boolean Parameters Name Type id any Returns boolean Inherited from HasMany . containsById Defined in packages/cozy-client/src/associations/HasMany.js:108", "title": "containsById"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#dehydrate", "text": "\u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Inherited from HasMany . dehydrate Defined in packages/cozy-client/src/associations/HasMany.js:256", "title": "dehydrate"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#exists", "text": "\u25b8 exists ( document ): boolean Parameters Name Type document any Returns boolean Inherited from HasMany . exists Defined in packages/cozy-client/src/associations/HasMany.js:104", "title": "exists"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#existsbyid", "text": "\u25b8 existsById ( id ): boolean Parameters Name Type id any Returns boolean Inherited from HasMany . existsById Defined in packages/cozy-client/src/associations/HasMany.js:114", "title": "existsById"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#fetchmore", "text": "\u25b8 fetchMore (): void Returns void Inherited from HasMany . fetchMore Defined in packages/cozy-client/src/associations/HasMany.js:100", "title": "fetchMore"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#getrelationship", "text": "\u25b8 getRelationship (): any Returns any Inherited from HasMany . getRelationship Defined in packages/cozy-client/src/associations/HasMany.js:207", "title": "getRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#remove", "text": "\u25b8 remove ( docsArg ): CozyClientDocument Remove the relationships from the target document Parameters Name Type Description docsArg CozyClientDocument [] Documents to remove as relationships Returns CozyClientDocument The saved target document Inherited from HasMany . remove Defined in packages/cozy-client/src/associations/HasMany.js:136", "title": "remove"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#removebyid", "text": "\u25b8 removeById ( idsArg ): any Parameters Name Type idsArg any Returns any Inherited from HasMany . removeById Defined in packages/cozy-client/src/associations/HasMany.js:193", "title": "removeById"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#removetargetrelationships", "text": "\u25b8 removeTargetRelationships ( idsArg ): void Remove relationships from target document Parameters Name Type Description idsArg string [] The ids to remove from the target relationships Returns void Inherited from HasMany . removeTargetRelationships Defined in packages/cozy-client/src/associations/HasMany.js:184", "title": "removeTargetRelationships"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#updatemetacount", "text": "\u25b8 updateMetaCount (): void Returns void Inherited from HasMany . updateMetaCount Defined in packages/cozy-client/src/associations/HasMany.js:198", "title": "updateMetaCount"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#updaterelationship", "text": "\u25b8 updateRelationship ( target , updateFn ): any Parameters Name Type target any updateFn any Returns any Inherited from HasMany . updateRelationship Defined in packages/cozy-client/src/associations/HasMany.js:228", "title": "updateRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#updaterelationshipdata", "text": "\u25b8 updateRelationshipData ( getUpdatedRelationshipData ): ( dispatch : any , getState : any ) => void Parameters Name Type getUpdatedRelationshipData any Returns fn \u25b8 ( dispatch , getState ): void Parameters Name Type dispatch any getState any Returns void Inherited from HasMany . updateRelationshipData Defined in packages/cozy-client/src/associations/HasMany.js:232", "title": "updateRelationshipData"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#updatetargetrelationship", "text": "\u25b8 updateTargetRelationship ( store , updateFn ): void Parameters Name Type store any updateFn any Returns void Inherited from HasMany . updateTargetRelationship Defined in packages/cozy-client/src/associations/HasMany.js:221", "title": "updateTargetRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#gethasmanyitem", "text": "\u25b8 Static getHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Inherited from HasMany . getHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:289", "title": "getHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#gethasmanyitems", "text": "\u25b8 Static getHasManyItems ( doc , relName ): any Parameters Name Type doc any relName any Returns any Inherited from HasMany . getHasManyItems Defined in packages/cozy-client/src/associations/HasMany.js:298", "title": "getHasManyItems"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#query_1", "text": "\u25b8 Static query ( doc , client ): QueryDefinition In this association the query is special, we need to fetch all the triggers having for the \u2018konnector\u2019 worker, and then filter them based on their message.konnector attribute Parameters Name Type doc any client any Returns QueryDefinition Overrides HasMany . query Defined in packages/cozy-client/src/associations/HasManyTriggers.js:21", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#removehasmanyitem", "text": "\u25b8 Static removeHasManyItem ( doc , relName , relItemId ): any Parameters Name Type doc any relName string relItemId string Returns any Inherited from HasMany . removeHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:336", "title": "removeHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#sethasmanyitem", "text": "\u25b8 Static setHasManyItem ( doc , relName , relItemId , relItemAttrs ): any Parameters Name Type doc any relName string relItemId string relItemAttrs any Returns any Inherited from HasMany . setHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:310", "title": "setHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#updatehasmanyitem", "text": "\u25b8 Static updateHasManyItem ( doc , relName , relItemId , updater ): any Parameters Name Type doc any relName string relItemId string updater Function Returns any Inherited from HasMany . updateHasManyItem Defined in packages/cozy-client/src/associations/HasMany.js:360", "title": "updateHasManyItem"}, {"location": "cozy-client/api/cozy-client/classes/HasManyTriggers/#updaterelationship_1", "text": "\u25b8 Static updateRelationship ( doc , relName , updateFn ): any Parameters Name Type doc any relName any updateFn any Returns any Inherited from HasMany . updateRelationship Defined in packages/cozy-client/src/associations/HasMany.js:371", "title": "updateRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/", "text": "cozy-client / HasOne Class: HasOne \u00b6 Hierarchy \u00b6 Association \u21b3 HasOne Constructors \u00b6 constructor \u00b6 \u2022 new HasOne ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87 Properties \u00b6 dispatch \u00b6 \u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144 doctype \u00b6 \u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109 get \u00b6 \u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116 mutate \u00b6 \u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131 name \u00b6 \u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101 query \u00b6 \u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124 save \u00b6 \u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138 target \u00b6 \u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94 Accessors \u00b6 data \u00b6 \u2022 get data (): any Returns any Overrides Association.data Defined in packages/cozy-client/src/associations/HasOne.js:12 raw \u00b6 \u2022 get raw (): any Returns any Overrides Association.raw Defined in packages/cozy-client/src/associations/HasOne.js:8 Methods \u00b6 add \u00b6 \u25b8 add ( doc ): CozyClientDocument Add the relationship to the target document Parameters Name Type Description doc CozyClientDocument Document to add as a relationship Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasOne.js:41 dehydrate \u00b6 \u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasOne.js:89 remove \u00b6 \u25b8 remove (): CozyClientDocument Remove the relationship from the target document Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasOne.js:51 set \u00b6 \u25b8 set ( doc ): void Parameters Name Type doc any Returns void Defined in packages/cozy-client/src/associations/HasOne.js:75 setRelationship \u00b6 \u25b8 setRelationship ( doc ): void Parameters Name Type doc any Returns void Defined in packages/cozy-client/src/associations/HasOne.js:56 unset \u00b6 \u25b8 unset (): void Returns void Defined in packages/cozy-client/src/associations/HasOne.js:82 query \u00b6 \u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasOne.js:27", "title": "HasOne"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#class-hasone", "text": "", "title": "Class: HasOne"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#hierarchy", "text": "Association \u21b3 HasOne", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#constructor", "text": "\u2022 new HasOne ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#dispatch", "text": "\u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144", "title": "dispatch"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#doctype", "text": "\u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109", "title": "doctype"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#get", "text": "\u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116", "title": "get"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#mutate", "text": "\u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131", "title": "mutate"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#name", "text": "\u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101", "title": "name"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#query", "text": "\u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#save", "text": "\u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138", "title": "save"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#target", "text": "\u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94", "title": "target"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#accessors", "text": "", "title": "Accessors"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#data", "text": "\u2022 get data (): any Returns any Overrides Association.data Defined in packages/cozy-client/src/associations/HasOne.js:12", "title": "data"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#raw", "text": "\u2022 get raw (): any Returns any Overrides Association.raw Defined in packages/cozy-client/src/associations/HasOne.js:8", "title": "raw"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#add", "text": "\u25b8 add ( doc ): CozyClientDocument Add the relationship to the target document Parameters Name Type Description doc CozyClientDocument Document to add as a relationship Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasOne.js:41", "title": "add"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#dehydrate", "text": "\u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasOne.js:89", "title": "dehydrate"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#remove", "text": "\u25b8 remove (): CozyClientDocument Remove the relationship from the target document Returns CozyClientDocument The saved target document Defined in packages/cozy-client/src/associations/HasOne.js:51", "title": "remove"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#set", "text": "\u25b8 set ( doc ): void Parameters Name Type doc any Returns void Defined in packages/cozy-client/src/associations/HasOne.js:75", "title": "set"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#setrelationship", "text": "\u25b8 setRelationship ( doc ): void Parameters Name Type doc any Returns void Defined in packages/cozy-client/src/associations/HasOne.js:56", "title": "setRelationship"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#unset", "text": "\u25b8 unset (): void Returns void Defined in packages/cozy-client/src/associations/HasOne.js:82", "title": "unset"}, {"location": "cozy-client/api/cozy-client/classes/HasOne/#query_1", "text": "\u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasOne.js:27", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/", "text": "cozy-client / HasOneInPlace Class: HasOneInPlace \u00b6 Here the id of the document is directly set in the attribute of the document, not in the relationships attribute Hierarchy \u00b6 Association \u21b3 HasOneInPlace Constructors \u00b6 constructor \u00b6 \u2022 new HasOneInPlace ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87 Properties \u00b6 dispatch \u00b6 \u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144 doctype \u00b6 \u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109 get \u00b6 \u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116 mutate \u00b6 \u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131 name \u00b6 \u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101 query \u00b6 \u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124 save \u00b6 \u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138 target \u00b6 \u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94 Accessors \u00b6 data \u00b6 \u2022 get data (): any Returns any Overrides Association.data Defined in packages/cozy-client/src/associations/HasOneInPlace.js:13 raw \u00b6 \u2022 get raw (): any Returns any Overrides Association.raw Defined in packages/cozy-client/src/associations/HasOneInPlace.js:9 Methods \u00b6 dehydrate \u00b6 \u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasOneInPlace.js:32 query \u00b6 \u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasOneInPlace.js:24", "title": "HasOneInPlace"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#class-hasoneinplace", "text": "Here the id of the document is directly set in the attribute of the document, not in the relationships attribute", "title": "Class: HasOneInPlace"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#hierarchy", "text": "Association \u21b3 HasOneInPlace", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#constructor", "text": "\u2022 new HasOneInPlace ( target , name , doctype , options ) Parameters Name Type Description target any Original object containing raw data name string Attribute under which the association is stored doctype string Doctype of the documents managed by the association options Object Options passed from the client options.dispatch Function Store\u2019s dispatch, comes from the client options.get Function Get a document from the store options.mutate Function Execute client mutate options.query Function Execute client query options.save Function Execute client save Inherited from Association . constructor Defined in packages/cozy-client/src/associations/Association.js:87", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#dispatch", "text": "\u2022 dispatch : Function Dispatch an action on the store. Inherited from Association . dispatch Defined in packages/cozy-client/src/associations/Association.js:144", "title": "dispatch"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#doctype", "text": "\u2022 doctype : string Doctype of the relationship example \u2018io.cozy.authors\u2019 Inherited from Association . doctype Defined in packages/cozy-client/src/associations/Association.js:109", "title": "doctype"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#get", "text": "\u2022 get : Function Returns the document from the store Inherited from Association . get Defined in packages/cozy-client/src/associations/Association.js:116", "title": "get"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#mutate", "text": "\u2022 mutate : Function Performs a mutation on the relationship. function Inherited from Association . mutate Defined in packages/cozy-client/src/associations/Association.js:131", "title": "mutate"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#name", "text": "\u2022 name : string The name of the relationship. example \u2018author\u2019 Inherited from Association . name Defined in packages/cozy-client/src/associations/Association.js:101", "title": "name"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#query", "text": "\u2022 query : Function Performs a query to retrieve relationship documents. param function Inherited from Association . query Defined in packages/cozy-client/src/associations/Association.js:124", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#save", "text": "\u2022 save : Function Saves the relationship in store. Inherited from Association . save Defined in packages/cozy-client/src/associations/Association.js:138", "title": "save"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#target", "text": "\u2022 target : any The original document declaring the relationship Inherited from Association . target Defined in packages/cozy-client/src/associations/Association.js:94", "title": "target"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#accessors", "text": "", "title": "Accessors"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#data", "text": "\u2022 get data (): any Returns any Overrides Association.data Defined in packages/cozy-client/src/associations/HasOneInPlace.js:13", "title": "data"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#raw", "text": "\u2022 get raw (): any Returns any Overrides Association.raw Defined in packages/cozy-client/src/associations/HasOneInPlace.js:9", "title": "raw"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#dehydrate", "text": "\u25b8 dehydrate ( doc ): any Parameters Name Type doc any Returns any Defined in packages/cozy-client/src/associations/HasOneInPlace.js:32", "title": "dehydrate"}, {"location": "cozy-client/api/cozy-client/classes/HasOneInPlace/#query_1", "text": "\u25b8 Static query ( document , client , assoc ): CozyClientDocument | QueryDefinition Parameters Name Type Description document CozyClientDocument Document to query client any The CozyClient instance assoc Association The query params Returns CozyClientDocument | QueryDefinition Overrides Association . query Defined in packages/cozy-client/src/associations/HasOneInPlace.js:24", "title": "query"}, {"location": "cozy-client/api/cozy-client/classes/InvalidCozyUrlError/", "text": "cozy-client / InvalidCozyUrlError Class: InvalidCozyUrlError \u00b6 Hierarchy \u00b6 Error \u21b3 InvalidCozyUrlError Constructors \u00b6 constructor \u00b6 \u2022 new InvalidCozyUrlError ( url ) Parameters Name Type url any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:146 Properties \u00b6 url \u00b6 \u2022 url : any Defined in packages/cozy-client/src/helpers/urlHelper.js:149", "title": "InvalidCozyUrlError"}, {"location": "cozy-client/api/cozy-client/classes/InvalidCozyUrlError/#class-invalidcozyurlerror", "text": "", "title": "Class: InvalidCozyUrlError"}, {"location": "cozy-client/api/cozy-client/classes/InvalidCozyUrlError/#hierarchy", "text": "Error \u21b3 InvalidCozyUrlError", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/InvalidCozyUrlError/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/InvalidCozyUrlError/#constructor", "text": "\u2022 new InvalidCozyUrlError ( url ) Parameters Name Type url any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:146", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/InvalidCozyUrlError/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/InvalidCozyUrlError/#url", "text": "\u2022 url : any Defined in packages/cozy-client/src/helpers/urlHelper.js:149", "title": "url"}, {"location": "cozy-client/api/cozy-client/classes/InvalidProtocolError/", "text": "cozy-client / InvalidProtocolError Class: InvalidProtocolError \u00b6 Hierarchy \u00b6 Error \u21b3 InvalidProtocolError Constructors \u00b6 constructor \u00b6 \u2022 new InvalidProtocolError ( url ) Parameters Name Type url any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:130 Properties \u00b6 url \u00b6 \u2022 url : any Defined in packages/cozy-client/src/helpers/urlHelper.js:133", "title": "InvalidProtocolError"}, {"location": "cozy-client/api/cozy-client/classes/InvalidProtocolError/#class-invalidprotocolerror", "text": "", "title": "Class: InvalidProtocolError"}, {"location": "cozy-client/api/cozy-client/classes/InvalidProtocolError/#hierarchy", "text": "Error \u21b3 InvalidProtocolError", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/InvalidProtocolError/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/InvalidProtocolError/#constructor", "text": "\u2022 new InvalidProtocolError ( url ) Parameters Name Type url any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:130", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/InvalidProtocolError/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/InvalidProtocolError/#url", "text": "\u2022 url : any Defined in packages/cozy-client/src/helpers/urlHelper.js:133", "title": "url"}, {"location": "cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/", "text": "cozy-client / InvalidRedirectLinkError Class: InvalidRedirectLinkError \u00b6 Hierarchy \u00b6 Error \u21b3 InvalidRedirectLinkError Constructors \u00b6 constructor \u00b6 \u2022 new InvalidRedirectLinkError ( redirectLink ) Parameters Name Type redirectLink any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:122 Properties \u00b6 redirectLink \u00b6 \u2022 redirectLink : any Defined in packages/cozy-client/src/helpers/urlHelper.js:125", "title": "InvalidRedirectLinkError"}, {"location": "cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/#class-invalidredirectlinkerror", "text": "", "title": "Class: InvalidRedirectLinkError"}, {"location": "cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/#hierarchy", "text": "Error \u21b3 InvalidRedirectLinkError", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/#constructor", "text": "\u2022 new InvalidRedirectLinkError ( redirectLink ) Parameters Name Type redirectLink any Overrides Error.constructor Defined in packages/cozy-client/src/helpers/urlHelper.js:122", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/#redirectlink", "text": "\u2022 redirectLink : any Defined in packages/cozy-client/src/helpers/urlHelper.js:125", "title": "redirectLink"}, {"location": "cozy-client/api/cozy-client/classes/Query/", "text": "cozy-client / Query Class: Query \u00b6 Hierarchy \u00b6 Component \u21b3 Query Constructors \u00b6 constructor \u00b6 \u2022 new Query ( props , context ) Parameters Name Type props any context any Overrides Component.constructor Defined in packages/cozy-client/src/Query.jsx:92 Properties \u00b6 childrenArgs \u00b6 \u2022 childrenArgs : any [] Defined in packages/cozy-client/src/Query.jsx:164 client \u00b6 \u2022 client : CozyClient Current client Defined in packages/cozy-client/src/Query.jsx:106 observableQuery \u00b6 \u2022 observableQuery : default Observable query to connect store to query Defined in packages/cozy-client/src/Query.jsx:112 queryUnsubscribe \u00b6 \u2022 queryUnsubscribe : Function Callback to unsubscribe from observable query Defined in packages/cozy-client/src/Query.jsx:118 contextTypes \u00b6 \u25aa Static contextTypes : Object Type declaration Name Type client Requireable < object > store Requireable < object > defaultProps \u00b6 \u25aa Static defaultProps : Object Type declaration Name Type enabled boolean propTypes \u00b6 \u25aa Static propTypes : Object Type declaration Name Type as Requireable < string > children Validator <(\u2026 args : any []) => any > enabled Requireable < boolean > fetchPolicy Requireable <(\u2026 args : any []) => any > query Validator < object > Methods \u00b6 componentDidMount \u00b6 \u25b8 componentDidMount (): void Returns void Overrides Component.componentDidMount Defined in packages/cozy-client/src/Query.jsx:124 componentDidUpdate \u00b6 \u25b8 componentDidUpdate ( prevProps ): void Parameters Name Type prevProps any Returns void Overrides Component.componentDidUpdate Defined in packages/cozy-client/src/Query.jsx:146 componentWillUnmount \u00b6 \u25b8 componentWillUnmount (): void Returns void Overrides Component.componentWillUnmount Defined in packages/cozy-client/src/Query.jsx:152 executeQueryRespectingFetchPolicy \u00b6 \u25b8 executeQueryRespectingFetchPolicy (): void Returns void Defined in packages/cozy-client/src/Query.jsx:131 onQueryChange \u00b6 \u25b8 onQueryChange (): void Returns void Defined in packages/cozy-client/src/Query.jsx:158 recomputeChildrenArgs \u00b6 \u25b8 recomputeChildrenArgs (): void Returns void Defined in packages/cozy-client/src/Query.jsx:163 render \u00b6 \u25b8 render (): any Returns any Overrides Component.render Defined in packages/cozy-client/src/Query.jsx:167", "title": "Query"}, {"location": "cozy-client/api/cozy-client/classes/Query/#class-query", "text": "", "title": "Class: Query"}, {"location": "cozy-client/api/cozy-client/classes/Query/#hierarchy", "text": "Component \u21b3 Query", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/Query/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/Query/#constructor", "text": "\u2022 new Query ( props , context ) Parameters Name Type props any context any Overrides Component.constructor Defined in packages/cozy-client/src/Query.jsx:92", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/Query/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/Query/#childrenargs", "text": "\u2022 childrenArgs : any [] Defined in packages/cozy-client/src/Query.jsx:164", "title": "childrenArgs"}, {"location": "cozy-client/api/cozy-client/classes/Query/#client", "text": "\u2022 client : CozyClient Current client Defined in packages/cozy-client/src/Query.jsx:106", "title": "client"}, {"location": "cozy-client/api/cozy-client/classes/Query/#observablequery", "text": "\u2022 observableQuery : default Observable query to connect store to query Defined in packages/cozy-client/src/Query.jsx:112", "title": "observableQuery"}, {"location": "cozy-client/api/cozy-client/classes/Query/#queryunsubscribe", "text": "\u2022 queryUnsubscribe : Function Callback to unsubscribe from observable query Defined in packages/cozy-client/src/Query.jsx:118", "title": "queryUnsubscribe"}, {"location": "cozy-client/api/cozy-client/classes/Query/#contexttypes", "text": "\u25aa Static contextTypes : Object Type declaration Name Type client Requireable < object > store Requireable < object >", "title": "contextTypes"}, {"location": "cozy-client/api/cozy-client/classes/Query/#defaultprops", "text": "\u25aa Static defaultProps : Object Type declaration Name Type enabled boolean", "title": "defaultProps"}, {"location": "cozy-client/api/cozy-client/classes/Query/#proptypes", "text": "\u25aa Static propTypes : Object Type declaration Name Type as Requireable < string > children Validator <(\u2026 args : any []) => any > enabled Requireable < boolean > fetchPolicy Requireable <(\u2026 args : any []) => any > query Validator < object >", "title": "propTypes"}, {"location": "cozy-client/api/cozy-client/classes/Query/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/Query/#componentdidmount", "text": "\u25b8 componentDidMount (): void Returns void Overrides Component.componentDidMount Defined in packages/cozy-client/src/Query.jsx:124", "title": "componentDidMount"}, {"location": "cozy-client/api/cozy-client/classes/Query/#componentdidupdate", "text": "\u25b8 componentDidUpdate ( prevProps ): void Parameters Name Type prevProps any Returns void Overrides Component.componentDidUpdate Defined in packages/cozy-client/src/Query.jsx:146", "title": "componentDidUpdate"}, {"location": "cozy-client/api/cozy-client/classes/Query/#componentwillunmount", "text": "\u25b8 componentWillUnmount (): void Returns void Overrides Component.componentWillUnmount Defined in packages/cozy-client/src/Query.jsx:152", "title": "componentWillUnmount"}, {"location": "cozy-client/api/cozy-client/classes/Query/#executequeryrespectingfetchpolicy", "text": "\u25b8 executeQueryRespectingFetchPolicy (): void Returns void Defined in packages/cozy-client/src/Query.jsx:131", "title": "executeQueryRespectingFetchPolicy"}, {"location": "cozy-client/api/cozy-client/classes/Query/#onquerychange", "text": "\u25b8 onQueryChange (): void Returns void Defined in packages/cozy-client/src/Query.jsx:158", "title": "onQueryChange"}, {"location": "cozy-client/api/cozy-client/classes/Query/#recomputechildrenargs", "text": "\u25b8 recomputeChildrenArgs (): void Returns void Defined in packages/cozy-client/src/Query.jsx:163", "title": "recomputeChildrenArgs"}, {"location": "cozy-client/api/cozy-client/classes/Query/#render", "text": "\u25b8 render (): any Returns any Overrides Component.render Defined in packages/cozy-client/src/Query.jsx:167", "title": "render"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/", "text": "cozy-client / QueryDefinition Class: QueryDefinition \u00b6 Chainable API to create query definitions to retrieve documents from a Cozy. QueryDefinition s are sent to links. Constructors \u00b6 constructor \u00b6 \u2022 new QueryDefinition ( options? ) Parameters Name Type Description options Object Initial options for the query definition options.bookmark string - options.cursor CouchDBViewCursor - options.doctype string - options.fields string [] - options.id string - options.ids string [] - options.includes string [] - options.indexedFields string [] - options.limit number - options.partialFilter any - options.referenced string - options.selector any - options.skip number - options.sort any [] - Defined in packages/cozy-client/src/queries/dsl.js:50 Properties \u00b6 bookmark \u00b6 \u2022 bookmark : string Defined in packages/cozy-client/src/queries/dsl.js:64 cursor \u00b6 \u2022 cursor : CouchDBViewCursor Defined in packages/cozy-client/src/queries/dsl.js:63 doctype \u00b6 \u2022 doctype : string Defined in packages/cozy-client/src/queries/dsl.js:51 fields \u00b6 \u2022 fields : string [] Defined in packages/cozy-client/src/queries/dsl.js:55 id \u00b6 \u2022 id : string Defined in packages/cozy-client/src/queries/dsl.js:52 ids \u00b6 \u2022 ids : string [] Defined in packages/cozy-client/src/queries/dsl.js:53 includes \u00b6 \u2022 includes : string [] Defined in packages/cozy-client/src/queries/dsl.js:59 indexedFields \u00b6 \u2022 indexedFields : string [] Defined in packages/cozy-client/src/queries/dsl.js:56 limit \u00b6 \u2022 limit : number Defined in packages/cozy-client/src/queries/dsl.js:61 partialFilter \u00b6 \u2022 partialFilter : any Defined in packages/cozy-client/src/queries/dsl.js:57 referenced \u00b6 \u2022 referenced : string Defined in packages/cozy-client/src/queries/dsl.js:60 selector \u00b6 \u2022 selector : any Defined in packages/cozy-client/src/queries/dsl.js:54 skip \u00b6 \u2022 skip : number Defined in packages/cozy-client/src/queries/dsl.js:62 sort \u00b6 \u2022 sort : any [] Defined in packages/cozy-client/src/queries/dsl.js:58 Methods \u00b6 UNSAFE_noLimit \u00b6 \u25b8 UNSAFE_noLimit (): QueryDefinition Returns QueryDefinition Defined in packages/cozy-client/src/queries/dsl.js:291 checkSelectFields \u00b6 \u25b8 checkSelectFields ( obj ): void Check if the selected fields are all included in the selectors Parameters Name Type Description obj PartialQueryDefinition A partial QueryDefinition to check Returns void Defined in packages/cozy-client/src/queries/dsl.js:154 checkSelector \u00b6 \u25b8 checkSelector ( selector ): void Checks the selector predicates. It is useful to warn the developer when a partial index might be used. Parameters Name Type Description selector any The selector definition Returns void Defined in packages/cozy-client/src/queries/dsl.js:117 checkSortOrder \u00b6 \u25b8 checkSortOrder ( obj ): void Checks if the sort order matches the index\u2019 fields order. When sorting with CouchDB, it is required to: use indexed fields keep the same order than the indexed fields. See https://docs.cozy.io/en/tutorials/data/queries/#sort-data-with-mango Parameters Name Type Description obj PartialQueryDefinition A partial QueryDefinition to check Returns void Defined in packages/cozy-client/src/queries/dsl.js:78 getById \u00b6 \u25b8 getById ( id ): QueryDefinition Query a single document on its id. Parameters Name Type Description id string The document id. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:181 getByIds \u00b6 \u25b8 getByIds ( ids ): QueryDefinition Query several documents on their ids. Parameters Name Type Description ids any [] The documents ids. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:194 include \u00b6 \u25b8 include ( includes ): QueryDefinition Includes documents having a relationships with the ones queried. For example, query albums including the photos. Parameters Name Type Description includes any [] The documents to include. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:274 indexFields \u00b6 \u25b8 indexFields ( indexedFields ): QueryDefinition Specify which fields should be indexed. This prevent the automatic indexing of the mango fields. Parameters Name Type Description indexedFields any [] The fields to index. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:230 limitBy \u00b6 \u25b8 limitBy ( limit ): QueryDefinition Maximum number of documents returned, useful for pagination. Default is 100. Parameters Name Type Description limit number The document\u2019s limit. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:287 offset \u00b6 \u25b8 offset ( skip ): QueryDefinition Skip the first \u2018n\u2019 documents, where \u2018n\u2019 is the value specified. Beware, this performs badly on view\u2019s index. Prefer cursor-based pagination in such situation. Parameters Name Type Description skip number The number of documents to skip. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:304 offsetBookmark \u00b6 \u25b8 offsetBookmark ( bookmark ): QueryDefinition Use bookmark pagination. Note this only applies for mango-queries (not views) and is way more efficient than skip pagination. The bookmark is a string returned by the _find response and can be seen as a pointer in the index for the next query. Parameters Name Type Description bookmark string The bookmark to continue a previous paginated query. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:342 offsetCursor \u00b6 \u25b8 offsetCursor ( cursor ): QueryDefinition Use cursor-based pagination. Warning : this is only useful for views. The cursor is a [startkey, startkey_docid] array, where startkey is the view\u2019s key, e.g. [\u201cio.cozy.photos.albums\u201d, \u201calbum-id\u201d] and startkey_docid is the id of the starting document of the query, e.g. \u201cfile-id\u201d. Use the last docid of each query as startkey_docid to paginate or leave blank for the first query. Parameters Name Type Description cursor CouchDBViewCursor The cursor for pagination. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:324 partialIndex \u00b6 \u25b8 partialIndex ( partialFilter ): QueryDefinition Specify a partial index . The filter must follow the same syntax than the selector. A partial index includes a filter, used to select documents before the indexing. You can find more information about partial indexes here Parameters Name Type Description partialFilter any The filter definition. Returns QueryDefinition Defined in packages/cozy-client/src/queries/dsl.js:244 referencedBy \u00b6 \u25b8 referencedBy ( document ): QueryDefinition Use the file reference system Parameters Name Type Description document any The reference document Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:357 select \u00b6 \u25b8 select ( fields ): QueryDefinition Specify which fields of each object should be returned. If it is omitted, the entire object is returned. Parameters Name Type Description fields any [] The fields to return. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:218 sortBy \u00b6 \u25b8 sortBy ( sort ): QueryDefinition Specify how to sort documents, following the sort syntax Parameters Name Type Description sort any [] The list of field name and direction pairs. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:255 toDefinition \u00b6 \u25b8 toDefinition (): Object Returns Object Name Type bookmark string cursor CouchDBViewCursor doctype string fields string [] id string ids string [] includes string [] indexedFields string [] limit number partialFilter any referenced string selector any skip number sort any [] Defined in packages/cozy-client/src/queries/dsl.js:361 where \u00b6 \u25b8 where ( selector ): QueryDefinition Query documents with a mango selector . Each field passed in the selector will be indexed, except if the indexField option is used. Parameters Name Type Description selector any The Mango selector. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:205", "title": "QueryDefinition"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#class-querydefinition", "text": "Chainable API to create query definitions to retrieve documents from a Cozy. QueryDefinition s are sent to links.", "title": "Class: QueryDefinition"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#constructor", "text": "\u2022 new QueryDefinition ( options? ) Parameters Name Type Description options Object Initial options for the query definition options.bookmark string - options.cursor CouchDBViewCursor - options.doctype string - options.fields string [] - options.id string - options.ids string [] - options.includes string [] - options.indexedFields string [] - options.limit number - options.partialFilter any - options.referenced string - options.selector any - options.skip number - options.sort any [] - Defined in packages/cozy-client/src/queries/dsl.js:50", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#bookmark", "text": "\u2022 bookmark : string Defined in packages/cozy-client/src/queries/dsl.js:64", "title": "bookmark"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#cursor", "text": "\u2022 cursor : CouchDBViewCursor Defined in packages/cozy-client/src/queries/dsl.js:63", "title": "cursor"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#doctype", "text": "\u2022 doctype : string Defined in packages/cozy-client/src/queries/dsl.js:51", "title": "doctype"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#fields", "text": "\u2022 fields : string [] Defined in packages/cozy-client/src/queries/dsl.js:55", "title": "fields"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#id", "text": "\u2022 id : string Defined in packages/cozy-client/src/queries/dsl.js:52", "title": "id"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#ids", "text": "\u2022 ids : string [] Defined in packages/cozy-client/src/queries/dsl.js:53", "title": "ids"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#includes", "text": "\u2022 includes : string [] Defined in packages/cozy-client/src/queries/dsl.js:59", "title": "includes"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#indexedfields", "text": "\u2022 indexedFields : string [] Defined in packages/cozy-client/src/queries/dsl.js:56", "title": "indexedFields"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#limit", "text": "\u2022 limit : number Defined in packages/cozy-client/src/queries/dsl.js:61", "title": "limit"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#partialfilter", "text": "\u2022 partialFilter : any Defined in packages/cozy-client/src/queries/dsl.js:57", "title": "partialFilter"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#referenced", "text": "\u2022 referenced : string Defined in packages/cozy-client/src/queries/dsl.js:60", "title": "referenced"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#selector", "text": "\u2022 selector : any Defined in packages/cozy-client/src/queries/dsl.js:54", "title": "selector"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#skip", "text": "\u2022 skip : number Defined in packages/cozy-client/src/queries/dsl.js:62", "title": "skip"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#sort", "text": "\u2022 sort : any [] Defined in packages/cozy-client/src/queries/dsl.js:58", "title": "sort"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#unsafe_nolimit", "text": "\u25b8 UNSAFE_noLimit (): QueryDefinition Returns QueryDefinition Defined in packages/cozy-client/src/queries/dsl.js:291", "title": "UNSAFE_noLimit"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#checkselectfields", "text": "\u25b8 checkSelectFields ( obj ): void Check if the selected fields are all included in the selectors Parameters Name Type Description obj PartialQueryDefinition A partial QueryDefinition to check Returns void Defined in packages/cozy-client/src/queries/dsl.js:154", "title": "checkSelectFields"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#checkselector", "text": "\u25b8 checkSelector ( selector ): void Checks the selector predicates. It is useful to warn the developer when a partial index might be used. Parameters Name Type Description selector any The selector definition Returns void Defined in packages/cozy-client/src/queries/dsl.js:117", "title": "checkSelector"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#checksortorder", "text": "\u25b8 checkSortOrder ( obj ): void Checks if the sort order matches the index\u2019 fields order. When sorting with CouchDB, it is required to: use indexed fields keep the same order than the indexed fields. See https://docs.cozy.io/en/tutorials/data/queries/#sort-data-with-mango Parameters Name Type Description obj PartialQueryDefinition A partial QueryDefinition to check Returns void Defined in packages/cozy-client/src/queries/dsl.js:78", "title": "checkSortOrder"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#getbyid", "text": "\u25b8 getById ( id ): QueryDefinition Query a single document on its id. Parameters Name Type Description id string The document id. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:181", "title": "getById"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#getbyids", "text": "\u25b8 getByIds ( ids ): QueryDefinition Query several documents on their ids. Parameters Name Type Description ids any [] The documents ids. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:194", "title": "getByIds"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#include", "text": "\u25b8 include ( includes ): QueryDefinition Includes documents having a relationships with the ones queried. For example, query albums including the photos. Parameters Name Type Description includes any [] The documents to include. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:274", "title": "include"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#indexfields", "text": "\u25b8 indexFields ( indexedFields ): QueryDefinition Specify which fields should be indexed. This prevent the automatic indexing of the mango fields. Parameters Name Type Description indexedFields any [] The fields to index. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:230", "title": "indexFields"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#limitby", "text": "\u25b8 limitBy ( limit ): QueryDefinition Maximum number of documents returned, useful for pagination. Default is 100. Parameters Name Type Description limit number The document\u2019s limit. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:287", "title": "limitBy"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#offset", "text": "\u25b8 offset ( skip ): QueryDefinition Skip the first \u2018n\u2019 documents, where \u2018n\u2019 is the value specified. Beware, this performs badly on view\u2019s index. Prefer cursor-based pagination in such situation. Parameters Name Type Description skip number The number of documents to skip. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:304", "title": "offset"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#offsetbookmark", "text": "\u25b8 offsetBookmark ( bookmark ): QueryDefinition Use bookmark pagination. Note this only applies for mango-queries (not views) and is way more efficient than skip pagination. The bookmark is a string returned by the _find response and can be seen as a pointer in the index for the next query. Parameters Name Type Description bookmark string The bookmark to continue a previous paginated query. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:342", "title": "offsetBookmark"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#offsetcursor", "text": "\u25b8 offsetCursor ( cursor ): QueryDefinition Use cursor-based pagination. Warning : this is only useful for views. The cursor is a [startkey, startkey_docid] array, where startkey is the view\u2019s key, e.g. [\u201cio.cozy.photos.albums\u201d, \u201calbum-id\u201d] and startkey_docid is the id of the starting document of the query, e.g. \u201cfile-id\u201d. Use the last docid of each query as startkey_docid to paginate or leave blank for the first query. Parameters Name Type Description cursor CouchDBViewCursor The cursor for pagination. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:324", "title": "offsetCursor"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#partialindex", "text": "\u25b8 partialIndex ( partialFilter ): QueryDefinition Specify a partial index . The filter must follow the same syntax than the selector. A partial index includes a filter, used to select documents before the indexing. You can find more information about partial indexes here Parameters Name Type Description partialFilter any The filter definition. Returns QueryDefinition Defined in packages/cozy-client/src/queries/dsl.js:244", "title": "partialIndex"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#referencedby", "text": "\u25b8 referencedBy ( document ): QueryDefinition Use the file reference system Parameters Name Type Description document any The reference document Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:357", "title": "referencedBy"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#select", "text": "\u25b8 select ( fields ): QueryDefinition Specify which fields of each object should be returned. If it is omitted, the entire object is returned. Parameters Name Type Description fields any [] The fields to return. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:218", "title": "select"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#sortby", "text": "\u25b8 sortBy ( sort ): QueryDefinition Specify how to sort documents, following the sort syntax Parameters Name Type Description sort any [] The list of field name and direction pairs. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:255", "title": "sortBy"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#todefinition", "text": "\u25b8 toDefinition (): Object Returns Object Name Type bookmark string cursor CouchDBViewCursor doctype string fields string [] id string ids string [] includes string [] indexedFields string [] limit number partialFilter any referenced string selector any skip number sort any [] Defined in packages/cozy-client/src/queries/dsl.js:361", "title": "toDefinition"}, {"location": "cozy-client/api/cozy-client/classes/QueryDefinition/#where", "text": "\u25b8 where ( selector ): QueryDefinition Query documents with a mango selector . Each field passed in the selector will be indexed, except if the indexField option is used. Parameters Name Type Description selector any The Mango selector. Returns QueryDefinition The QueryDefinition object. Defined in packages/cozy-client/src/queries/dsl.js:205", "title": "where"}, {"location": "cozy-client/api/cozy-client/classes/Registry/", "text": "cozy-client / Registry Class: Registry \u00b6 Constructors \u00b6 constructor \u00b6 \u2022 new Registry ( options ) Parameters Name Type options any Defined in packages/cozy-client/src/registry.js:40 Properties \u00b6 client \u00b6 \u2022 client : any Defined in packages/cozy-client/src/registry.js:44 Methods \u00b6 fetchApp \u00b6 \u25b8 fetchApp ( slug ): Promise < RegistryApp > Fetch the status of a single app on the registry Parameters Name Type Description slug string The slug of the app to fetch Returns Promise < RegistryApp > Defined in packages/cozy-client/src/registry.js:132 fetchAppVersion \u00b6 \u25b8 fetchAppVersion ( params ): Promise < RegistryApp > Fetch the latest version of an app for the given channel and slug Parameters Name Type Description params Object Fetching parameters params.channel RegistryAppChannel The channel of the app to fetch params.slug string The slug of the app to fetch params.version string The version of the app to fetch. Can also be \u201clatest\u201d Returns Promise < RegistryApp > Defined in packages/cozy-client/src/registry.js:146 fetchApps \u00b6 \u25b8 fetchApps ( params ): Promise < RegistryApp []> Fetch at most 200 apps from the channel Parameters Name Type Description params Object Fetching parameters params.channel RegistryAppChannel The channel of the apps to fetch params.limit string maximum number of fetched apps - defaults to 200 params.type string \u201cwebapp\u201d or \u201ckonnector\u201d Returns Promise < RegistryApp []> Defined in packages/cozy-client/src/registry.js:96 fetchAppsInMaintenance \u00b6 \u25b8 fetchAppsInMaintenance (): Promise < RegistryApp []> Fetch the list of apps that are in maintenance mode Returns Promise < RegistryApp []> Defined in packages/cozy-client/src/registry.js:121 installApp \u00b6 \u25b8 installApp ( app , source ): Promise < any > Installs or updates an app from a source. Accepts the terms if the app has them. Parameters Name Type Description app RegistryApp App to be installed source string String (ex: registry://drive/stable) Returns Promise < any > Defined in packages/cozy-client/src/registry.js:56 uninstallApp \u00b6 \u25b8 uninstallApp ( app ): Promise < any > Uninstalls an app. Parameters Name Type Description app RegistryApp App to be installed Returns Promise < any > Defined in packages/cozy-client/src/registry.js:80", "title": "Registry"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#class-registry", "text": "", "title": "Class: Registry"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#constructor", "text": "\u2022 new Registry ( options ) Parameters Name Type options any Defined in packages/cozy-client/src/registry.js:40", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#client", "text": "\u2022 client : any Defined in packages/cozy-client/src/registry.js:44", "title": "client"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#fetchapp", "text": "\u25b8 fetchApp ( slug ): Promise < RegistryApp > Fetch the status of a single app on the registry Parameters Name Type Description slug string The slug of the app to fetch Returns Promise < RegistryApp > Defined in packages/cozy-client/src/registry.js:132", "title": "fetchApp"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#fetchappversion", "text": "\u25b8 fetchAppVersion ( params ): Promise < RegistryApp > Fetch the latest version of an app for the given channel and slug Parameters Name Type Description params Object Fetching parameters params.channel RegistryAppChannel The channel of the app to fetch params.slug string The slug of the app to fetch params.version string The version of the app to fetch. Can also be \u201clatest\u201d Returns Promise < RegistryApp > Defined in packages/cozy-client/src/registry.js:146", "title": "fetchAppVersion"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#fetchapps", "text": "\u25b8 fetchApps ( params ): Promise < RegistryApp []> Fetch at most 200 apps from the channel Parameters Name Type Description params Object Fetching parameters params.channel RegistryAppChannel The channel of the apps to fetch params.limit string maximum number of fetched apps - defaults to 200 params.type string \u201cwebapp\u201d or \u201ckonnector\u201d Returns Promise < RegistryApp []> Defined in packages/cozy-client/src/registry.js:96", "title": "fetchApps"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#fetchappsinmaintenance", "text": "\u25b8 fetchAppsInMaintenance (): Promise < RegistryApp []> Fetch the list of apps that are in maintenance mode Returns Promise < RegistryApp []> Defined in packages/cozy-client/src/registry.js:121", "title": "fetchAppsInMaintenance"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#installapp", "text": "\u25b8 installApp ( app , source ): Promise < any > Installs or updates an app from a source. Accepts the terms if the app has them. Parameters Name Type Description app RegistryApp App to be installed source string String (ex: registry://drive/stable) Returns Promise < any > Defined in packages/cozy-client/src/registry.js:56", "title": "installApp"}, {"location": "cozy-client/api/cozy-client/classes/Registry/#uninstallapp", "text": "\u25b8 uninstallApp ( app ): Promise < any > Uninstalls an app. Parameters Name Type Description app RegistryApp App to be installed Returns Promise < any > Defined in packages/cozy-client/src/registry.js:80", "title": "uninstallApp"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/", "text": "cozy-client / StackLink Class: StackLink \u00b6 Transfers queries and mutations to a remote stack Hierarchy \u00b6 CozyLink \u21b3 StackLink Constructors \u00b6 constructor \u00b6 \u2022 new StackLink ( [options]? ) Parameters Name Type Description [options] Object Options [options].client any - [options].stackClient any - Overrides CozyLink . constructor Defined in packages/cozy-client/src/StackLink.js:62 Properties \u00b6 stackClient \u00b6 \u2022 stackClient : any Defined in packages/cozy-client/src/StackLink.js:69 Methods \u00b6 executeMutation \u00b6 \u25b8 executeMutation ( mutation , result , forward ): Promise < any > Parameters Name Type mutation any result any forward any Returns Promise < any > Defined in packages/cozy-client/src/StackLink.js:114 executeQuery \u00b6 \u25b8 executeQuery ( query ): Promise < any > Parameters Name Type Description query QueryDefinition Query to execute Returns Promise < any > Defined in packages/cozy-client/src/StackLink.js:91 registerClient \u00b6 \u25b8 registerClient ( client ): void Parameters Name Type client any Returns void Defined in packages/cozy-client/src/StackLink.js:72 request \u00b6 \u25b8 request ( operation , result , forward ): Promise < any > Parameters Name Type operation any result any forward any Returns Promise < any > Overrides CozyLink . request Defined in packages/cozy-client/src/StackLink.js:80 reset \u00b6 \u25b8 reset (): void Returns void Defined in packages/cozy-client/src/StackLink.js:76", "title": "StackLink"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#class-stacklink", "text": "Transfers queries and mutations to a remote stack", "title": "Class: StackLink"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#hierarchy", "text": "CozyLink \u21b3 StackLink", "title": "Hierarchy"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#constructor", "text": "\u2022 new StackLink ( [options]? ) Parameters Name Type Description [options] Object Options [options].client any - [options].stackClient any - Overrides CozyLink . constructor Defined in packages/cozy-client/src/StackLink.js:62", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#stackclient", "text": "\u2022 stackClient : any Defined in packages/cozy-client/src/StackLink.js:69", "title": "stackClient"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#executemutation", "text": "\u25b8 executeMutation ( mutation , result , forward ): Promise < any > Parameters Name Type mutation any result any forward any Returns Promise < any > Defined in packages/cozy-client/src/StackLink.js:114", "title": "executeMutation"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#executequery", "text": "\u25b8 executeQuery ( query ): Promise < any > Parameters Name Type Description query QueryDefinition Query to execute Returns Promise < any > Defined in packages/cozy-client/src/StackLink.js:91", "title": "executeQuery"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#registerclient", "text": "\u25b8 registerClient ( client ): void Parameters Name Type client any Returns void Defined in packages/cozy-client/src/StackLink.js:72", "title": "registerClient"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#request", "text": "\u25b8 request ( operation , result , forward ): Promise < any > Parameters Name Type operation any result any forward any Returns Promise < any > Overrides CozyLink . request Defined in packages/cozy-client/src/StackLink.js:80", "title": "request"}, {"location": "cozy-client/api/cozy-client/classes/StackLink/#reset", "text": "\u25b8 reset (): void Returns void Defined in packages/cozy-client/src/StackLink.js:76", "title": "reset"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/", "text": "cozy-client / models / document / Qualification Class: Qualification \u00b6 models . document .Qualification This class is used to create document Qualification, i.e. metadata attributes used to describe the document. The qualifications model is stored in the assets, associating labels to attributes, namely: purpose, sourceCategory, sourceSubCategory and subjects. A qualification can be customized accordingly to rules detailed in the checkValueAttributes method. Constructors \u00b6 constructor \u00b6 \u2022 new Qualification ( label , attributes? ) Parameters Name Type Description label string The qualification label attributes QualificationAttributes Qualification\u2019s attributes Defined in packages/cozy-client/src/models/document/qualification.js:30 Properties \u00b6 icon \u00b6 \u2022 icon : string Defined in packages/cozy-client/src/models/document/qualification.js:38 label \u00b6 \u2022 label : string Defined in packages/cozy-client/src/models/document/qualification.js:42 purpose \u00b6 \u2022 purpose : string Defined in packages/cozy-client/src/models/document/qualification.js:48 sourceCategory \u00b6 \u2022 sourceCategory : string Defined in packages/cozy-client/src/models/document/qualification.js:56 sourceSubCategory \u00b6 \u2022 sourceSubCategory : string Defined in packages/cozy-client/src/models/document/qualification.js:64 subjects \u00b6 \u2022 subjects : string [] Defined in packages/cozy-client/src/models/document/qualification.js:71 Methods \u00b6 checkAttributes \u00b6 \u25b8 checkAttributes ( attributes ): void Check the given qualification attributes respects the following rules: For the given label, if a purpose, sourceCategory or sourceSubCategory attribute is defined in the model, it must match the given qualification. If not defined in the model for the label, a custom purpose, sourceCategory or sourceSubCategory value can be defined, if it exist in their respective known values list. For the given label, if subjects are defined in the model, they must be included in the given qualification. If extra subjects are set, they should exist in the known values. Parameters Name Type Description attributes any The qualification attributes to check Returns void Defined in packages/cozy-client/src/models/document/qualification.js:91 setIcon \u00b6 \u25b8 setIcon ( icon ): Qualification Set icon to the qualification. Parameters Name Type Description icon string The icon to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:223 setPurpose \u00b6 \u25b8 setPurpose ( purpose ): Qualification Set purpose to the qualification. Parameters Name Type Description purpose any [] The purpose to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:174 setSourceCategory \u00b6 \u25b8 setSourceCategory ( sourceCategory ): Qualification Set sourceCategory to the qualification. Parameters Name Type Description sourceCategory any [] The sourceCategory to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:184 setSourceSubCategory \u00b6 \u25b8 setSourceSubCategory ( sourceSubCategory ): Qualification Set sourceSubCategory to the qualification. Parameters Name Type Description sourceSubCategory any [] The sourceSubCategory to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:197 setSubjects \u00b6 \u25b8 setSubjects ( subjects ): Qualification Set subjects to the qualification. Parameters Name Type Description subjects any [] The subjects to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:210 toQualification \u00b6 \u25b8 toQualification (): any Returns the qualification attributes Returns any The qualification attributes Defined in packages/cozy-client/src/models/document/qualification.js:235 getByLabel \u00b6 \u25b8 Static getByLabel ( label ): Qualification Returns the qualification associated to a label. Parameters Name Type Description label string The label to qualify Returns Qualification The qualification Defined in packages/cozy-client/src/models/document/qualification.js:253", "title": "models.document.Qualification"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#class-qualification", "text": "models . document .Qualification This class is used to create document Qualification, i.e. metadata attributes used to describe the document. The qualifications model is stored in the assets, associating labels to attributes, namely: purpose, sourceCategory, sourceSubCategory and subjects. A qualification can be customized accordingly to rules detailed in the checkValueAttributes method.", "title": "Class: Qualification"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#constructors", "text": "", "title": "Constructors"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#constructor", "text": "\u2022 new Qualification ( label , attributes? ) Parameters Name Type Description label string The qualification label attributes QualificationAttributes Qualification\u2019s attributes Defined in packages/cozy-client/src/models/document/qualification.js:30", "title": "constructor"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#icon", "text": "\u2022 icon : string Defined in packages/cozy-client/src/models/document/qualification.js:38", "title": "icon"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#label", "text": "\u2022 label : string Defined in packages/cozy-client/src/models/document/qualification.js:42", "title": "label"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#purpose", "text": "\u2022 purpose : string Defined in packages/cozy-client/src/models/document/qualification.js:48", "title": "purpose"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#sourcecategory", "text": "\u2022 sourceCategory : string Defined in packages/cozy-client/src/models/document/qualification.js:56", "title": "sourceCategory"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#sourcesubcategory", "text": "\u2022 sourceSubCategory : string Defined in packages/cozy-client/src/models/document/qualification.js:64", "title": "sourceSubCategory"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#subjects", "text": "\u2022 subjects : string [] Defined in packages/cozy-client/src/models/document/qualification.js:71", "title": "subjects"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#methods", "text": "", "title": "Methods"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#checkattributes", "text": "\u25b8 checkAttributes ( attributes ): void Check the given qualification attributes respects the following rules: For the given label, if a purpose, sourceCategory or sourceSubCategory attribute is defined in the model, it must match the given qualification. If not defined in the model for the label, a custom purpose, sourceCategory or sourceSubCategory value can be defined, if it exist in their respective known values list. For the given label, if subjects are defined in the model, they must be included in the given qualification. If extra subjects are set, they should exist in the known values. Parameters Name Type Description attributes any The qualification attributes to check Returns void Defined in packages/cozy-client/src/models/document/qualification.js:91", "title": "checkAttributes"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#seticon", "text": "\u25b8 setIcon ( icon ): Qualification Set icon to the qualification. Parameters Name Type Description icon string The icon to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:223", "title": "setIcon"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#setpurpose", "text": "\u25b8 setPurpose ( purpose ): Qualification Set purpose to the qualification. Parameters Name Type Description purpose any [] The purpose to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:174", "title": "setPurpose"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#setsourcecategory", "text": "\u25b8 setSourceCategory ( sourceCategory ): Qualification Set sourceCategory to the qualification. Parameters Name Type Description sourceCategory any [] The sourceCategory to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:184", "title": "setSourceCategory"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#setsourcesubcategory", "text": "\u25b8 setSourceSubCategory ( sourceSubCategory ): Qualification Set sourceSubCategory to the qualification. Parameters Name Type Description sourceSubCategory any [] The sourceSubCategory to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:197", "title": "setSourceSubCategory"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#setsubjects", "text": "\u25b8 setSubjects ( subjects ): Qualification Set subjects to the qualification. Parameters Name Type Description subjects any [] The subjects to set. Returns Qualification The Qualification object. Defined in packages/cozy-client/src/models/document/qualification.js:210", "title": "setSubjects"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#toqualification", "text": "\u25b8 toQualification (): any Returns the qualification attributes Returns any The qualification attributes Defined in packages/cozy-client/src/models/document/qualification.js:235", "title": "toQualification"}, {"location": "cozy-client/api/cozy-client/classes/models.document.Qualification/#getbylabel", "text": "\u25b8 Static getByLabel ( label ): Qualification Returns the qualification associated to a label. Parameters Name Type Description label string The label to qualify Returns Qualification The qualification Defined in packages/cozy-client/src/models/document/qualification.js:253", "title": "getByLabel"}, {"location": "cozy-client/api/cozy-client/interfaces/models.dacc.Params/", "text": "cozy-client / models / dacc / Params Interface: Params<> \u00b6 models . dacc .Params The unformatted DACC aggregate params Properties \u00b6 endDate \u00b6 \u2022 endDate : string The measure end date Defined in packages/cozy-client/src/models/dacc.js:97 measureName \u00b6 \u2022 measureName : string The measure name Defined in packages/cozy-client/src/models/dacc.js:95 startDate \u00b6 \u2022 startDate : string The measure start date Defined in packages/cozy-client/src/models/dacc.js:96", "title": "models.dacc.Params"}, {"location": "cozy-client/api/cozy-client/interfaces/models.dacc.Params/#interface-params", "text": "models . dacc .Params The unformatted DACC aggregate params", "title": "Interface: Params<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.dacc.Params/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.dacc.Params/#enddate", "text": "\u2022 endDate : string The measure end date Defined in packages/cozy-client/src/models/dacc.js:97", "title": "endDate"}, {"location": "cozy-client/api/cozy-client/interfaces/models.dacc.Params/#measurename", "text": "\u2022 measureName : string The measure name Defined in packages/cozy-client/src/models/dacc.js:95", "title": "measureName"}, {"location": "cozy-client/api/cozy-client/interfaces/models.dacc.Params/#startdate", "text": "\u2022 startDate : string The measure start date Defined in packages/cozy-client/src/models/dacc.js:96", "title": "startDate"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/", "text": "cozy-client / models / file / FileUploadOptions Interface: FileUploadOptions<> \u00b6 models . file .FileUploadOptions Properties \u00b6 conflictOptions \u00b6 \u2022 conflictOptions : ConflictOptions Conflict options Defined in packages/cozy-client/src/models/file.js:499 conflictStrategy \u00b6 \u2022 conflictStrategy : string Erase / rename Defined in packages/cozy-client/src/models/file.js:498 contentType \u00b6 \u2022 contentType : string The file Content-Type Defined in packages/cozy-client/src/models/file.js:497 dirId \u00b6 \u2022 dirId : string The dirId to upload the file to Defined in packages/cozy-client/src/models/file.js:495 metadata \u00b6 \u2022 metadata : any An object containing the metadata to attach Defined in packages/cozy-client/src/models/file.js:496 name \u00b6 \u2022 name : string The file name to upload Defined in packages/cozy-client/src/models/file.js:494", "title": "models.file.FileUploadOptions"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#interface-fileuploadoptions", "text": "models . file .FileUploadOptions", "title": "Interface: FileUploadOptions<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#conflictoptions", "text": "\u2022 conflictOptions : ConflictOptions Conflict options Defined in packages/cozy-client/src/models/file.js:499", "title": "conflictOptions"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#conflictstrategy", "text": "\u2022 conflictStrategy : string Erase / rename Defined in packages/cozy-client/src/models/file.js:498", "title": "conflictStrategy"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#contenttype", "text": "\u2022 contentType : string The file Content-Type Defined in packages/cozy-client/src/models/file.js:497", "title": "contentType"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#dirid", "text": "\u2022 dirId : string The dirId to upload the file to Defined in packages/cozy-client/src/models/file.js:495", "title": "dirId"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#metadata", "text": "\u2022 metadata : any An object containing the metadata to attach Defined in packages/cozy-client/src/models/file.js:496", "title": "metadata"}, {"location": "cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/#name", "text": "\u2022 name : string The file name to upload Defined in packages/cozy-client/src/models/file.js:494", "title": "name"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfos/", "text": "cozy-client / models / instance / DiskInfos Interface: DiskInfos<> \u00b6 models . instance .DiskInfos Properties \u00b6 humanDiskQuota \u00b6 \u2022 humanDiskQuota : string Space used in GB rounded Defined in packages/cozy-client/src/models/instance.js:121 humanDiskUsage \u00b6 \u2022 humanDiskUsage : string Maximum space available in GB rounded Defined in packages/cozy-client/src/models/instance.js:122 percentUsage \u00b6 \u2022 percentUsage : string Usage percent of the disk rounded Defined in packages/cozy-client/src/models/instance.js:123", "title": "models.instance.DiskInfos"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfos/#interface-diskinfos", "text": "models . instance .DiskInfos", "title": "Interface: DiskInfos<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfos/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfos/#humandiskquota", "text": "\u2022 humanDiskQuota : string Space used in GB rounded Defined in packages/cozy-client/src/models/instance.js:121", "title": "humanDiskQuota"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfos/#humandiskusage", "text": "\u2022 humanDiskUsage : string Maximum space available in GB rounded Defined in packages/cozy-client/src/models/instance.js:122", "title": "humanDiskUsage"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfos/#percentusage", "text": "\u2022 percentUsage : string Usage percent of the disk rounded Defined in packages/cozy-client/src/models/instance.js:123", "title": "percentUsage"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfosRaw/", "text": "cozy-client / models / instance / DiskInfosRaw Interface: DiskInfosRaw<> \u00b6 models . instance .DiskInfosRaw Properties \u00b6 diskQuota \u00b6 \u2022 diskQuota : number Space used in GB Defined in packages/cozy-client/src/models/instance.js:114 diskUsage \u00b6 \u2022 diskUsage : number Maximum space available in GB Defined in packages/cozy-client/src/models/instance.js:115 percentUsage \u00b6 \u2022 percentUsage : number Usage percent of the disk Defined in packages/cozy-client/src/models/instance.js:116", "title": "models.instance.DiskInfosRaw"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfosRaw/#interface-diskinfosraw", "text": "models . instance .DiskInfosRaw", "title": "Interface: DiskInfosRaw<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfosRaw/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfosRaw/#diskquota", "text": "\u2022 diskQuota : number Space used in GB Defined in packages/cozy-client/src/models/instance.js:114", "title": "diskQuota"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfosRaw/#diskusage", "text": "\u2022 diskUsage : number Maximum space available in GB Defined in packages/cozy-client/src/models/instance.js:115", "title": "diskUsage"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.DiskInfosRaw/#percentusage", "text": "\u2022 percentUsage : number Usage percent of the disk Defined in packages/cozy-client/src/models/instance.js:116", "title": "percentUsage"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.SettingsInfo/", "text": "cozy-client / models / instance / SettingsInfo Interface: SettingsInfo<> \u00b6 models . instance .SettingsInfo Properties \u00b6 context \u00b6 \u2022 context : any Object returned by /settings/context Defined in packages/cozy-client/src/models/instance.js:16 diskUsage \u00b6 \u2022 diskUsage : any Object returned by /settings/disk-usage Defined in packages/cozy-client/src/models/instance.js:18 instance \u00b6 \u2022 instance : any Object returned by /settings/instance Defined in packages/cozy-client/src/models/instance.js:17", "title": "models.instance.SettingsInfo"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.SettingsInfo/#interface-settingsinfo", "text": "models . instance .SettingsInfo", "title": "Interface: SettingsInfo<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.SettingsInfo/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.SettingsInfo/#context", "text": "\u2022 context : any Object returned by /settings/context Defined in packages/cozy-client/src/models/instance.js:16", "title": "context"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.SettingsInfo/#diskusage", "text": "\u2022 diskUsage : any Object returned by /settings/disk-usage Defined in packages/cozy-client/src/models/instance.js:18", "title": "diskUsage"}, {"location": "cozy-client/api/cozy-client/interfaces/models.instance.SettingsInfo/#instance", "text": "\u2022 instance : any Object returned by /settings/instance Defined in packages/cozy-client/src/models/instance.js:17", "title": "instance"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Document/", "text": "cozy-client / models / permission / Document Interface: Document<> \u00b6 models . permission .Document Couchdb document like an io.cozy.files Properties \u00b6 _id \u00b6 \u2022 _id : string Defined in packages/cozy-client/src/models/permission.js:11 _type \u00b6 \u2022 _type : string Defined in packages/cozy-client/src/models/permission.js:13 id \u00b6 \u2022 id : string Defined in packages/cozy-client/src/models/permission.js:12 type \u00b6 \u2022 type : string Defined in packages/cozy-client/src/models/permission.js:14", "title": "models.permission.Document"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Document/#interface-document", "text": "models . permission .Document Couchdb document like an io.cozy.files", "title": "Interface: Document<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Document/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Document/#_id", "text": "\u2022 _id : string Defined in packages/cozy-client/src/models/permission.js:11", "title": "_id"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Document/#_type", "text": "\u2022 _type : string Defined in packages/cozy-client/src/models/permission.js:13", "title": "_type"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Document/#id", "text": "\u2022 id : string Defined in packages/cozy-client/src/models/permission.js:12", "title": "id"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Document/#type", "text": "\u2022 type : string Defined in packages/cozy-client/src/models/permission.js:14", "title": "type"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Permission/", "text": "cozy-client / models / permission / Permission Interface: Permission<> \u00b6 models . permission .Permission Properties \u00b6 data \u00b6 \u2022 data : any Permission document Defined in packages/cozy-client/src/models/permission.js:162 included \u00b6 \u2022 included : any [] Member information from the sharing Defined in packages/cozy-client/src/models/permission.js:163", "title": "models.permission.Permission"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Permission/#interface-permission", "text": "models . permission .Permission", "title": "Interface: Permission<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Permission/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Permission/#data", "text": "\u2022 data : any Permission document Defined in packages/cozy-client/src/models/permission.js:162", "title": "data"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.Permission/#included", "text": "\u2022 included : any [] Member information from the sharing Defined in packages/cozy-client/src/models/permission.js:163", "title": "included"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/", "text": "cozy-client / models / permission / PermissionItem Interface: PermissionItem<> \u00b6 models . permission .PermissionItem Properties \u00b6 selector \u00b6 \u2022 selector : string defaults to id Defined in packages/cozy-client/src/models/permission.js:24 type \u00b6 \u2022 type : string a couch db database like \u2018io.cozy.files\u2019 Defined in packages/cozy-client/src/models/permission.js:26 values \u00b6 \u2022 values : string [] Defined in packages/cozy-client/src/models/permission.js:25 verbs \u00b6 \u2022 verbs : PermissionVerb [] ALL, GET, PUT, PATCH, DELETE, POST\u2026 Defined in packages/cozy-client/src/models/permission.js:23", "title": "models.permission.PermissionItem"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/#interface-permissionitem", "text": "models . permission .PermissionItem", "title": "Interface: PermissionItem<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/#selector", "text": "\u2022 selector : string defaults to id Defined in packages/cozy-client/src/models/permission.js:24", "title": "selector"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/#type", "text": "\u2022 type : string a couch db database like \u2018io.cozy.files\u2019 Defined in packages/cozy-client/src/models/permission.js:26", "title": "type"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/#values", "text": "\u2022 values : string [] Defined in packages/cozy-client/src/models/permission.js:25", "title": "values"}, {"location": "cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/#verbs", "text": "\u2022 verbs : PermissionVerb [] ALL, GET, PUT, PATCH, DELETE, POST\u2026 Defined in packages/cozy-client/src/models/permission.js:23", "title": "verbs"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/", "text": "cozy-client / models / timeseries / TimeSeries Interface: TimeSeries<> \u00b6 models . timeseries .TimeSeries Properties \u00b6 dataType \u00b6 \u2022 dataType : string The type of time series, e.g. \u2018electricity\u2019 Defined in packages/cozy-client/src/models/timeseries.js:22 endDate \u00b6 \u2022 endDate : Date The end date of the series Defined in packages/cozy-client/src/models/timeseries.js:24 endType \u00b6 \u2022 endType : Date The starting date of the series Defined in packages/cozy-client/src/models/timeseries.js:25 series \u00b6 \u2022 series : any [] An array of objects representing the time series Defined in packages/cozy-client/src/models/timeseries.js:28 source \u00b6 \u2022 source : string The data source, e.g. \u2018enedis.fr\u2019 Defined in packages/cozy-client/src/models/timeseries.js:26 startDate \u00b6 \u2022 startDate : Date The starting date of the series Defined in packages/cozy-client/src/models/timeseries.js:23 theme \u00b6 \u2022 theme : string The theme used to group time series, e.g. \u2018energy\u2019 Defined in packages/cozy-client/src/models/timeseries.js:27", "title": "models.timeseries.TimeSeries"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#interface-timeseries", "text": "models . timeseries .TimeSeries", "title": "Interface: TimeSeries<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#datatype", "text": "\u2022 dataType : string The type of time series, e.g. \u2018electricity\u2019 Defined in packages/cozy-client/src/models/timeseries.js:22", "title": "dataType"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#enddate", "text": "\u2022 endDate : Date The end date of the series Defined in packages/cozy-client/src/models/timeseries.js:24", "title": "endDate"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#endtype", "text": "\u2022 endType : Date The starting date of the series Defined in packages/cozy-client/src/models/timeseries.js:25", "title": "endType"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#series", "text": "\u2022 series : any [] An array of objects representing the time series Defined in packages/cozy-client/src/models/timeseries.js:28", "title": "series"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#source", "text": "\u2022 source : string The data source, e.g. \u2018enedis.fr\u2019 Defined in packages/cozy-client/src/models/timeseries.js:26", "title": "source"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#startdate", "text": "\u2022 startDate : Date The starting date of the series Defined in packages/cozy-client/src/models/timeseries.js:23", "title": "startDate"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/#theme", "text": "\u2022 theme : string The theme used to group time series, e.g. \u2018energy\u2019 Defined in packages/cozy-client/src/models/timeseries.js:27", "title": "theme"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeriesJSONAPI/", "text": "cozy-client / models / timeseries / TimeSeriesJSONAPI Interface: TimeSeriesJSONAPI<> \u00b6 models . timeseries .TimeSeriesJSONAPI Properties \u00b6 data \u00b6 \u2022 data : TimeSeries [] The JSON-API data response Defined in packages/cozy-client/src/models/timeseries.js:74", "title": "models.timeseries.TimeSeriesJSONAPI"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeriesJSONAPI/#interface-timeseriesjsonapi", "text": "models . timeseries .TimeSeriesJSONAPI", "title": "Interface: TimeSeriesJSONAPI<>"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeriesJSONAPI/#properties", "text": "", "title": "Properties"}, {"location": "cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeriesJSONAPI/#data", "text": "\u2022 data : TimeSeries [] The JSON-API data response Defined in packages/cozy-client/src/models/timeseries.js:74", "title": "data"}, {"location": "cozy-client/api/cozy-client/modules/manifest/", "text": "cozy-client / manifest Namespace: manifest \u00b6 Variables \u00b6 ROLE_IDENTIFIER \u00b6 \u2022 Const ROLE_IDENTIFIER : \"identifier\" Defined in packages/cozy-client/src/models/manifest.js:6 legacyLoginFields \u00b6 \u2022 Const legacyLoginFields : string [] Legacy login fields declared by some konnectors Defined in packages/cozy-client/src/models/manifest.js:11 Functions \u00b6 areTermsValid \u00b6 \u25b8 areTermsValid ( terms ): boolean Parameters Name Type terms any Returns boolean Defined in packages/cozy-client/src/models/manifest.js:63 getIdentifier \u00b6 \u25b8 getIdentifier ( fields? ): string Returns the key for the field having the role=identifier attribute Parameters Name Type Description fields ManifestFields Konnector fields Returns string The key for the identifier field, example \u2018login\u2019 Defined in packages/cozy-client/src/models/manifest.js:161 isPartnershipValid \u00b6 \u25b8 isPartnershipValid ( partnership ): boolean Parameters Name Type partnership any Returns boolean Defined in packages/cozy-client/src/models/manifest.js:67 sanitize \u00b6 \u25b8 sanitize ( manifest ): any Normalize app manifest, retro-compatibility for old manifests Parameters Name Type Description manifest any app manifest to normalize Returns any Defined in packages/cozy-client/src/models/manifest.js:77 sanitizeCategories \u00b6 \u25b8 sanitizeCategories ( categories ): any [] Filters unauthorized categories. Defaults to [\u2018others\u2019] if no suitable category. Parameters Name Type Description categories any [] Array of categories Returns any [] sanitized categories Defined in packages/cozy-client/src/models/manifest.js:56 sanitizeIdentifier \u00b6 \u25b8 sanitizeIdentifier ( fields ): ManifestFields Ensures that fields has at least one field with the role \u2018identifier\u2019 Parameters Name Type Description fields ManifestFields Manifest fields Returns ManifestFields Sanitized manifest fields Defined in packages/cozy-client/src/models/manifest.js:130", "title": "Manifest"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#namespace-manifest", "text": "", "title": "Namespace: manifest"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#role_identifier", "text": "\u2022 Const ROLE_IDENTIFIER : \"identifier\" Defined in packages/cozy-client/src/models/manifest.js:6", "title": "ROLE_IDENTIFIER"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#legacyloginfields", "text": "\u2022 Const legacyLoginFields : string [] Legacy login fields declared by some konnectors Defined in packages/cozy-client/src/models/manifest.js:11", "title": "legacyLoginFields"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#aretermsvalid", "text": "\u25b8 areTermsValid ( terms ): boolean Parameters Name Type terms any Returns boolean Defined in packages/cozy-client/src/models/manifest.js:63", "title": "areTermsValid"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#getidentifier", "text": "\u25b8 getIdentifier ( fields? ): string Returns the key for the field having the role=identifier attribute Parameters Name Type Description fields ManifestFields Konnector fields Returns string The key for the identifier field, example \u2018login\u2019 Defined in packages/cozy-client/src/models/manifest.js:161", "title": "getIdentifier"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#ispartnershipvalid", "text": "\u25b8 isPartnershipValid ( partnership ): boolean Parameters Name Type partnership any Returns boolean Defined in packages/cozy-client/src/models/manifest.js:67", "title": "isPartnershipValid"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#sanitize", "text": "\u25b8 sanitize ( manifest ): any Normalize app manifest, retro-compatibility for old manifests Parameters Name Type Description manifest any app manifest to normalize Returns any Defined in packages/cozy-client/src/models/manifest.js:77", "title": "sanitize"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#sanitizecategories", "text": "\u25b8 sanitizeCategories ( categories ): any [] Filters unauthorized categories. Defaults to [\u2018others\u2019] if no suitable category. Parameters Name Type Description categories any [] Array of categories Returns any [] sanitized categories Defined in packages/cozy-client/src/models/manifest.js:56", "title": "sanitizeCategories"}, {"location": "cozy-client/api/cozy-client/modules/manifest/#sanitizeidentifier", "text": "\u25b8 sanitizeIdentifier ( fields ): ManifestFields Ensures that fields has at least one field with the role \u2018identifier\u2019 Parameters Name Type Description fields ManifestFields Manifest fields Returns ManifestFields Sanitized manifest fields Defined in packages/cozy-client/src/models/manifest.js:130", "title": "sanitizeIdentifier"}, {"location": "cozy-client/api/cozy-client/modules/models.account/", "text": "cozy-client / models / account Namespace: account \u00b6 models .account Functions \u00b6 buildAccount \u00b6 \u25b8 buildAccount ( konnector , authData ): IOCozyAccount Transforms account auth data to io.cozy.accounts document Parameters Name Type Description konnector IOCozyKonnector Konnector related to account authData any Authentication data Returns IOCozyAccount io.cozy.accounts attributes Defined in packages/cozy-client/src/models/account.js:113 getAccountLogin \u00b6 \u25b8 getAccountLogin ( account ): string Get the account login field value from a given account Parameters Name Type Description account IOCozyAccount the given cozy account Returns string Account login Defined in packages/cozy-client/src/models/account.js:79 getAccountName \u00b6 \u25b8 getAccountName ( account ): string Get the account name from a given account Parameters Name Type Description account IOCozyAccount the given cozy account Returns string Account name Defined in packages/cozy-client/src/models/account.js:97 getContractSyncStatusFromAccount \u00b6 \u25b8 getContractSyncStatusFromAccount ( account , contractId ): boolean Returns whether a contract is synced from account relationship Parameters Name Type Description account IOCozyAccount Cozy account contractId string contract identifier Returns boolean synchronisation status Defined in packages/cozy-client/src/models/account.js:44 getMutedErrors \u00b6 \u25b8 getMutedErrors ( account ): any [] getMutedErrors - Returns the list of errors that have been muted for the given account Parameters Name Type Description account IOCozyAccount io.cozy.accounts Returns any [] An array of errors with a type and mutedAt field Defined in packages/cozy-client/src/models/account.js:15 isAccountWithTrigger \u00b6 \u25b8 isAccountWithTrigger ( client , account ): Promise < boolean > Look if the given account has an associated trigger or not. Parameters Name Type Description client CozyClient CozyClient instance account IOCozyAccount account document Returns Promise < boolean > Defined in packages/cozy-client/src/models/account.js:129 muteError \u00b6 \u25b8 muteError ( account , errorType ): IOCozyAccount muteError - Adds an error to the list of muted errors for the given account Parameters Name Type Description account IOCozyAccount io.cozy.accounts errorType string The type of the error to mute Returns IOCozyAccount An updated io.cozy.accounts Defined in packages/cozy-client/src/models/account.js:25 setContractSyncStatusInAccount \u00b6 \u25b8 setContractSyncStatusInAccount ( account , contractId , syncStatus ): IOCozyAccount Sets contract sync status into account relationship Parameters Name Type Description account IOCozyAccount Cozy account contractId string contract identifier syncStatus string synchronisation status Returns IOCozyAccount Defined in packages/cozy-client/src/models/account.js:60", "title": "Models.account"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#namespace-account", "text": "models .account", "title": "Namespace: account"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#buildaccount", "text": "\u25b8 buildAccount ( konnector , authData ): IOCozyAccount Transforms account auth data to io.cozy.accounts document Parameters Name Type Description konnector IOCozyKonnector Konnector related to account authData any Authentication data Returns IOCozyAccount io.cozy.accounts attributes Defined in packages/cozy-client/src/models/account.js:113", "title": "buildAccount"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#getaccountlogin", "text": "\u25b8 getAccountLogin ( account ): string Get the account login field value from a given account Parameters Name Type Description account IOCozyAccount the given cozy account Returns string Account login Defined in packages/cozy-client/src/models/account.js:79", "title": "getAccountLogin"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#getaccountname", "text": "\u25b8 getAccountName ( account ): string Get the account name from a given account Parameters Name Type Description account IOCozyAccount the given cozy account Returns string Account name Defined in packages/cozy-client/src/models/account.js:97", "title": "getAccountName"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#getcontractsyncstatusfromaccount", "text": "\u25b8 getContractSyncStatusFromAccount ( account , contractId ): boolean Returns whether a contract is synced from account relationship Parameters Name Type Description account IOCozyAccount Cozy account contractId string contract identifier Returns boolean synchronisation status Defined in packages/cozy-client/src/models/account.js:44", "title": "getContractSyncStatusFromAccount"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#getmutederrors", "text": "\u25b8 getMutedErrors ( account ): any [] getMutedErrors - Returns the list of errors that have been muted for the given account Parameters Name Type Description account IOCozyAccount io.cozy.accounts Returns any [] An array of errors with a type and mutedAt field Defined in packages/cozy-client/src/models/account.js:15", "title": "getMutedErrors"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#isaccountwithtrigger", "text": "\u25b8 isAccountWithTrigger ( client , account ): Promise < boolean > Look if the given account has an associated trigger or not. Parameters Name Type Description client CozyClient CozyClient instance account IOCozyAccount account document Returns Promise < boolean > Defined in packages/cozy-client/src/models/account.js:129", "title": "isAccountWithTrigger"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#muteerror", "text": "\u25b8 muteError ( account , errorType ): IOCozyAccount muteError - Adds an error to the list of muted errors for the given account Parameters Name Type Description account IOCozyAccount io.cozy.accounts errorType string The type of the error to mute Returns IOCozyAccount An updated io.cozy.accounts Defined in packages/cozy-client/src/models/account.js:25", "title": "muteError"}, {"location": "cozy-client/api/cozy-client/modules/models.account/#setcontractsyncstatusinaccount", "text": "\u25b8 setContractSyncStatusInAccount ( account , contractId , syncStatus ): IOCozyAccount Sets contract sync status into account relationship Parameters Name Type Description account IOCozyAccount Cozy account contractId string contract identifier syncStatus string synchronisation status Returns IOCozyAccount Defined in packages/cozy-client/src/models/account.js:60", "title": "setContractSyncStatusInAccount"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/", "text": "cozy-client / models / applications Namespace: applications \u00b6 models .applications Functions \u00b6 getAppDisplayName \u00b6 \u25b8 getAppDisplayName ( app , lang ): string getAppDisplayName - Combines the translated prefix and name of the app into a single string. Parameters Name Type Description app any io.cozy.apps or io.cozy.konnectors document lang string Locale to use Returns string Name of the app suitable for display Defined in packages/cozy-client/src/models/applications.js:73 getStoreInstallationURL \u00b6 \u25b8 getStoreInstallationURL ( appData? , app? ): string Returns the store URL to install/update an app/konnector Parameters Name Type Default value appData any [] [] app any {} Returns string URL as string Defined in packages/cozy-client/src/models/applications.js:34 getStoreURL \u00b6 \u25b8 getStoreURL ( appData? , app? ): string Returns the store URL of an app/konnector Parameters Name Type Default value appData any [] [] app any {} Returns string URL as string Defined in packages/cozy-client/src/models/applications.js:11 getUrl \u00b6 \u25b8 getUrl ( app ): string Parameters Name Type Description app any io.cozy.apps document Returns string url to the app Defined in packages/cozy-client/src/models/applications.js:61 isInstalled \u00b6 \u25b8 isInstalled ( apps? , wantedApp? ): any Parameters Name Type Default value Description apps any [] [] Array of apps returned by /apps /konnectors wantedApp any {} io.cozy.app with at least a slug Returns any The io.cozy.app is installed or undefined if not Defined in packages/cozy-client/src/models/applications.js:50", "title": "Models.applications"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/#namespace-applications", "text": "models .applications", "title": "Namespace: applications"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/#getappdisplayname", "text": "\u25b8 getAppDisplayName ( app , lang ): string getAppDisplayName - Combines the translated prefix and name of the app into a single string. Parameters Name Type Description app any io.cozy.apps or io.cozy.konnectors document lang string Locale to use Returns string Name of the app suitable for display Defined in packages/cozy-client/src/models/applications.js:73", "title": "getAppDisplayName"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/#getstoreinstallationurl", "text": "\u25b8 getStoreInstallationURL ( appData? , app? ): string Returns the store URL to install/update an app/konnector Parameters Name Type Default value appData any [] [] app any {} Returns string URL as string Defined in packages/cozy-client/src/models/applications.js:34", "title": "getStoreInstallationURL"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/#getstoreurl", "text": "\u25b8 getStoreURL ( appData? , app? ): string Returns the store URL of an app/konnector Parameters Name Type Default value appData any [] [] app any {} Returns string URL as string Defined in packages/cozy-client/src/models/applications.js:11", "title": "getStoreURL"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/#geturl", "text": "\u25b8 getUrl ( app ): string Parameters Name Type Description app any io.cozy.apps document Returns string url to the app Defined in packages/cozy-client/src/models/applications.js:61", "title": "getUrl"}, {"location": "cozy-client/api/cozy-client/modules/models.applications/#isinstalled", "text": "\u25b8 isInstalled ( apps? , wantedApp? ): any Parameters Name Type Default value Description apps any [] [] Array of apps returned by /apps /konnectors wantedApp any {} io.cozy.app with at least a slug Returns any The io.cozy.app is installed or undefined if not Defined in packages/cozy-client/src/models/applications.js:50", "title": "isInstalled"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/", "text": "cozy-client / models / contact Namespace: contact \u00b6 models .contact Type aliases \u00b6 FullnameAttributes \u00b6 \u01ac FullnameAttributes <>: \"namePrefix\" | \"givenName\" | \"additionalName\" | \"familyName\" | \"nameSuffix\" Defined in packages/cozy-client/src/models/contact.js:9 Variables \u00b6 CONTACTS_DOCTYPE \u00b6 \u2022 Const CONTACTS_DOCTYPE : \"io.cozy.contacts\" Defined in packages/cozy-client/src/models/contact.js:6 Functions \u00b6 getDefaultSortIndexValue \u00b6 \u25b8 getDefaultSortIndexValue ( contact ): string Returns \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index of a contact Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index Defined in packages/cozy-client/src/models/contact.js:214 getDisplayName \u00b6 \u25b8 getDisplayName ( contact ): string Returns a display name for the contact Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s display name Defined in packages/cozy-client/src/models/contact.js:176 getFullname \u00b6 \u25b8 getFullname ( contact ): string Returns the contact\u2019s fullname Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s fullname Defined in packages/cozy-client/src/models/contact.js:137 getIndexByFamilyNameGivenNameEmailCozyUrl \u00b6 \u25b8 getIndexByFamilyNameGivenNameEmailCozyUrl ( contact ): string Returns \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index of a contact deprecated Prefer to use getDefaultSortIndexValue. Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index Defined in packages/cozy-client/src/models/contact.js:235 getInitials \u00b6 \u25b8 getInitials ( contact ): string Returns the initials of the contact. Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s initials Defined in packages/cozy-client/src/models/contact.js:23 getPrimaryAddress \u00b6 \u25b8 getPrimaryAddress ( contact ): string Returns the contact\u2019s main address Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main address Defined in packages/cozy-client/src/models/contact.js:96 getPrimaryCozy \u00b6 \u25b8 getPrimaryCozy ( contact ): string Returns the contact\u2019s main cozy Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main cozy Defined in packages/cozy-client/src/models/contact.js:61 getPrimaryCozyDomain \u00b6 \u25b8 getPrimaryCozyDomain ( contact ): string Returns the contact\u2019s main cozy url without protocol Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main cozy url Defined in packages/cozy-client/src/models/contact.js:72 getPrimaryEmail \u00b6 \u25b8 getPrimaryEmail ( contact ): string Returns the contact\u2019s main email Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main email Defined in packages/cozy-client/src/models/contact.js:50 getPrimaryOrFirst \u00b6 \u25b8 getPrimaryOrFirst ( property ): ( obj : any ) => any Parameters Name Type property any Returns fn \u25b8 ( obj ): any Parameters Name Type obj any Returns any Defined in packages/cozy-client/src/models/contact.js:12 getPrimaryPhone \u00b6 \u25b8 getPrimaryPhone ( contact ): string Returns the contact\u2019s main phone number Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main phone number Defined in packages/cozy-client/src/models/contact.js:87 isContact \u00b6 \u25b8 isContact ( doc ): boolean Whether the document is a contact Parameters Name Type Description doc any A document (from io.cozy.something, or com.bitwarden or anything else) Returns boolean Defined in packages/cozy-client/src/models/contact.js:249 makeDefaultSortIndexValue \u00b6 \u25b8 makeDefaultSortIndexValue ( contact ): string Makes \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index of a contact Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index Defined in packages/cozy-client/src/models/contact.js:190 makeDisplayName \u00b6 \u25b8 makeDisplayName ( contact , opts ): string Makes displayName from contact data Parameters Name Type Description contact IOCozyContact A contact opts Object - opts.attributesFullname FullnameAttributes [] - Returns string The contact\u2019s displayName Defined in packages/cozy-client/src/models/contact.js:152 makeFullname \u00b6 \u25b8 makeFullname ( contact , opts ): string Makes fullname from contact name Parameters Name Type Description contact IOCozyContact A contact opts Object - opts.attributesFullname FullnameAttributes [] - Returns string The contact\u2019s fullname Defined in packages/cozy-client/src/models/contact.js:117", "title": "Models.contact"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#namespace-contact", "text": "models .contact", "title": "Namespace: contact"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#type-aliases", "text": "", "title": "Type aliases"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#fullnameattributes", "text": "\u01ac FullnameAttributes <>: \"namePrefix\" | \"givenName\" | \"additionalName\" | \"familyName\" | \"nameSuffix\" Defined in packages/cozy-client/src/models/contact.js:9", "title": "FullnameAttributes"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#contacts_doctype", "text": "\u2022 Const CONTACTS_DOCTYPE : \"io.cozy.contacts\" Defined in packages/cozy-client/src/models/contact.js:6", "title": "CONTACTS_DOCTYPE"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getdefaultsortindexvalue", "text": "\u25b8 getDefaultSortIndexValue ( contact ): string Returns \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index of a contact Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index Defined in packages/cozy-client/src/models/contact.js:214", "title": "getDefaultSortIndexValue"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getdisplayname", "text": "\u25b8 getDisplayName ( contact ): string Returns a display name for the contact Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s display name Defined in packages/cozy-client/src/models/contact.js:176", "title": "getDisplayName"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getfullname", "text": "\u25b8 getFullname ( contact ): string Returns the contact\u2019s fullname Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s fullname Defined in packages/cozy-client/src/models/contact.js:137", "title": "getFullname"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getindexbyfamilynamegivennameemailcozyurl", "text": "\u25b8 getIndexByFamilyNameGivenNameEmailCozyUrl ( contact ): string Returns \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index of a contact deprecated Prefer to use getDefaultSortIndexValue. Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index Defined in packages/cozy-client/src/models/contact.js:235", "title": "getIndexByFamilyNameGivenNameEmailCozyUrl"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getinitials", "text": "\u25b8 getInitials ( contact ): string Returns the initials of the contact. Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s initials Defined in packages/cozy-client/src/models/contact.js:23", "title": "getInitials"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getprimaryaddress", "text": "\u25b8 getPrimaryAddress ( contact ): string Returns the contact\u2019s main address Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main address Defined in packages/cozy-client/src/models/contact.js:96", "title": "getPrimaryAddress"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getprimarycozy", "text": "\u25b8 getPrimaryCozy ( contact ): string Returns the contact\u2019s main cozy Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main cozy Defined in packages/cozy-client/src/models/contact.js:61", "title": "getPrimaryCozy"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getprimarycozydomain", "text": "\u25b8 getPrimaryCozyDomain ( contact ): string Returns the contact\u2019s main cozy url without protocol Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main cozy url Defined in packages/cozy-client/src/models/contact.js:72", "title": "getPrimaryCozyDomain"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getprimaryemail", "text": "\u25b8 getPrimaryEmail ( contact ): string Returns the contact\u2019s main email Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main email Defined in packages/cozy-client/src/models/contact.js:50", "title": "getPrimaryEmail"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getprimaryorfirst", "text": "\u25b8 getPrimaryOrFirst ( property ): ( obj : any ) => any Parameters Name Type property any Returns fn \u25b8 ( obj ): any Parameters Name Type obj any Returns any Defined in packages/cozy-client/src/models/contact.js:12", "title": "getPrimaryOrFirst"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#getprimaryphone", "text": "\u25b8 getPrimaryPhone ( contact ): string Returns the contact\u2019s main phone number Parameters Name Type Description contact IOCozyContact A contact Returns string The contact\u2019s main phone number Defined in packages/cozy-client/src/models/contact.js:87", "title": "getPrimaryPhone"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#iscontact", "text": "\u25b8 isContact ( doc ): boolean Whether the document is a contact Parameters Name Type Description doc any A document (from io.cozy.something, or com.bitwarden or anything else) Returns boolean Defined in packages/cozy-client/src/models/contact.js:249", "title": "isContact"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#makedefaultsortindexvalue", "text": "\u25b8 makeDefaultSortIndexValue ( contact ): string Makes \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index of a contact Parameters Name Type Description contact IOCozyContact A contact Returns string the contact\u2019s \u2018byFamilyNameGivenNameEmailCozyUrl\u2019 index Defined in packages/cozy-client/src/models/contact.js:190", "title": "makeDefaultSortIndexValue"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#makedisplayname", "text": "\u25b8 makeDisplayName ( contact , opts ): string Makes displayName from contact data Parameters Name Type Description contact IOCozyContact A contact opts Object - opts.attributesFullname FullnameAttributes [] - Returns string The contact\u2019s displayName Defined in packages/cozy-client/src/models/contact.js:152", "title": "makeDisplayName"}, {"location": "cozy-client/api/cozy-client/modules/models.contact/#makefullname", "text": "\u25b8 makeFullname ( contact , opts ): string Makes fullname from contact name Parameters Name Type Description contact IOCozyContact A contact opts Object - opts.attributesFullname FullnameAttributes [] - Returns string The contact\u2019s fullname Defined in packages/cozy-client/src/models/contact.js:117", "title": "makeFullname"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/", "text": "cozy-client / models / dacc Namespace: dacc \u00b6 models .dacc Interfaces \u00b6 Params Functions \u00b6 buildAggregateParams \u00b6 \u25b8 buildAggregateParams ( params ): DACCAggregatesParams Build parameters to request DACC aggregate property {string} [measureName] - The measure name property {string} [startDate] - The measure start date property {string} [endDate] - The measure end date Parameters Name Type Description params Params The unformatted DACC aggregate params Returns DACCAggregatesParams Defined in packages/cozy-client/src/models/dacc.js:102 checkMeasureParams \u00b6 \u25b8 checkMeasureParams ( measure ): void Throw an errror if a DACC parameter is incorrect. Parameters Name Type Description measure DACCMeasure The DACC measure Returns void Defined in packages/cozy-client/src/models/dacc.js:24 fetchAggregatesFromDACC \u00b6 \u25b8 fetchAggregatesFromDACC ( client , remoteDoctype , params ): Promise < DACCAggregatesResponse > Send measures to a DACC through a remote doctype Parameters Name Type Description client CozyClient The CozyClient instance remoteDoctype string The remote doctype to use params DACCAggregatesParams The request params Returns Promise < DACCAggregatesResponse > Defined in packages/cozy-client/src/models/dacc.js:127 isCorrectDateFormat \u00b6 \u25b8 isCorrectDateFormat ( date ): boolean Check whether or not the given date is in YYYY-MM-DD format Parameters Name Type Description date string The date to check Returns boolean Defined in packages/cozy-client/src/models/dacc.js:10 sendMeasureToDACC \u00b6 \u25b8 sendMeasureToDACC ( client , remoteDoctype , measure ): Promise < void > Send measures to a DACC through a remote doctype Parameters Name Type Description client CozyClient The CozyClient instance remoteDoctype string The remote doctype to use measure DACCMeasure The DACC measure Returns Promise < void > Defined in packages/cozy-client/src/models/dacc.js:71", "title": "Models.dacc"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#namespace-dacc", "text": "models .dacc", "title": "Namespace: dacc"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#interfaces", "text": "Params", "title": "Interfaces"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#buildaggregateparams", "text": "\u25b8 buildAggregateParams ( params ): DACCAggregatesParams Build parameters to request DACC aggregate property {string} [measureName] - The measure name property {string} [startDate] - The measure start date property {string} [endDate] - The measure end date Parameters Name Type Description params Params The unformatted DACC aggregate params Returns DACCAggregatesParams Defined in packages/cozy-client/src/models/dacc.js:102", "title": "buildAggregateParams"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#checkmeasureparams", "text": "\u25b8 checkMeasureParams ( measure ): void Throw an errror if a DACC parameter is incorrect. Parameters Name Type Description measure DACCMeasure The DACC measure Returns void Defined in packages/cozy-client/src/models/dacc.js:24", "title": "checkMeasureParams"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#fetchaggregatesfromdacc", "text": "\u25b8 fetchAggregatesFromDACC ( client , remoteDoctype , params ): Promise < DACCAggregatesResponse > Send measures to a DACC through a remote doctype Parameters Name Type Description client CozyClient The CozyClient instance remoteDoctype string The remote doctype to use params DACCAggregatesParams The request params Returns Promise < DACCAggregatesResponse > Defined in packages/cozy-client/src/models/dacc.js:127", "title": "fetchAggregatesFromDACC"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#iscorrectdateformat", "text": "\u25b8 isCorrectDateFormat ( date ): boolean Check whether or not the given date is in YYYY-MM-DD format Parameters Name Type Description date string The date to check Returns boolean Defined in packages/cozy-client/src/models/dacc.js:10", "title": "isCorrectDateFormat"}, {"location": "cozy-client/api/cozy-client/modules/models.dacc/#sendmeasuretodacc", "text": "\u25b8 sendMeasureToDACC ( client , remoteDoctype , measure ): Promise < void > Send measures to a DACC through a remote doctype Parameters Name Type Description client CozyClient The CozyClient instance remoteDoctype string The remote doctype to use measure DACCMeasure The DACC measure Returns Promise < void > Defined in packages/cozy-client/src/models/dacc.js:71", "title": "sendMeasureToDACC"}, {"location": "cozy-client/api/cozy-client/modules/models.document.helpers/", "text": "cozy-client / models / document / helpers Namespace: helpers \u00b6 models . document .helpers Functions \u00b6 getThemeByItem \u00b6 \u25b8 getThemeByItem ( item ): Theme Parameters Name Type Description item QualificationAttributes Qualification item Returns Theme Defined in packages/cozy-client/src/models/document/documentTypeDataHelpers.js:17 isQualificationNote \u00b6 \u25b8 isQualificationNote ( item ): boolean Check if a qualification is a note Parameters Name Type Description item QualificationAttributes Qualification item Returns boolean Defined in packages/cozy-client/src/models/document/documentTypeDataHelpers.js:33", "title": "Models.document.helpers"}, {"location": "cozy-client/api/cozy-client/modules/models.document.helpers/#namespace-helpers", "text": "models . document .helpers", "title": "Namespace: helpers"}, {"location": "cozy-client/api/cozy-client/modules/models.document.helpers/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.document.helpers/#getthemebyitem", "text": "\u25b8 getThemeByItem ( item ): Theme Parameters Name Type Description item QualificationAttributes Qualification item Returns Theme Defined in packages/cozy-client/src/models/document/documentTypeDataHelpers.js:17", "title": "getThemeByItem"}, {"location": "cozy-client/api/cozy-client/modules/models.document.helpers/#isqualificationnote", "text": "\u25b8 isQualificationNote ( item ): boolean Check if a qualification is a note Parameters Name Type Description item QualificationAttributes Qualification item Returns boolean Defined in packages/cozy-client/src/models/document/documentTypeDataHelpers.js:33", "title": "isQualificationNote"}, {"location": "cozy-client/api/cozy-client/modules/models.document.locales/", "text": "cozy-client / models / document / locales Namespace: locales \u00b6 models . document .locales Functions \u00b6 getBoundT \u00b6 \u25b8 getBoundT ( lang ): ( label : string , opts? : { country? : string ; smart_count? : number }) => string Parameters Name Type Description lang string fr, en, etc Returns fn ) => string} \u25b8 ( label , opts? ): string Parameters Name Type label string opts? Object opts.country? string opts.smart_count? number Returns string Defined in packages/cozy-client/src/models/document/locales/index.js:21 getLocalizer \u00b6 \u25b8 getLocalizer ( lang ): Function Parameters Name Type Description lang string fr, en, etc Returns Function localization function Defined in packages/cozy-client/src/models/document/locales/index.js:45", "title": "Models.document.locales"}, {"location": "cozy-client/api/cozy-client/modules/models.document.locales/#namespace-locales", "text": "models . document .locales", "title": "Namespace: locales"}, {"location": "cozy-client/api/cozy-client/modules/models.document.locales/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.document.locales/#getboundt", "text": "\u25b8 getBoundT ( lang ): ( label : string , opts? : { country? : string ; smart_count? : number }) => string Parameters Name Type Description lang string fr, en, etc Returns fn ) => string} \u25b8 ( label , opts? ): string Parameters Name Type label string opts? Object opts.country? string opts.smart_count? number Returns string Defined in packages/cozy-client/src/models/document/locales/index.js:21", "title": "getBoundT"}, {"location": "cozy-client/api/cozy-client/modules/models.document.locales/#getlocalizer", "text": "\u25b8 getLocalizer ( lang ): Function Parameters Name Type Description lang string fr, en, etc Returns Function localization function Defined in packages/cozy-client/src/models/document/locales/index.js:45", "title": "getLocalizer"}, {"location": "cozy-client/api/cozy-client/modules/models.document/", "text": "cozy-client / models / document Namespace: document \u00b6 models .document Namespaces \u00b6 helpers locales themes Classes \u00b6 Qualification Functions \u00b6 getQualification \u00b6 \u25b8 getQualification ( document ): Qualification Helper to get the qualification from a document Parameters Name Type Description document any The document Returns Qualification The document qualification Defined in packages/cozy-client/src/models/document/qualification.js:288 setQualification \u00b6 \u25b8 setQualification ( document , qualification ): any Set the qualification to the document metadata Parameters Name Type Description document any The document to set the qualification qualification Qualification The qualification to set Returns any The qualified document Defined in packages/cozy-client/src/models/document/qualification.js:264", "title": "Models.document"}, {"location": "cozy-client/api/cozy-client/modules/models.document/#namespace-document", "text": "models .document", "title": "Namespace: document"}, {"location": "cozy-client/api/cozy-client/modules/models.document/#namespaces", "text": "helpers locales themes", "title": "Namespaces"}, {"location": "cozy-client/api/cozy-client/modules/models.document/#classes", "text": "Qualification", "title": "Classes"}, {"location": "cozy-client/api/cozy-client/modules/models.document/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.document/#getqualification", "text": "\u25b8 getQualification ( document ): Qualification Helper to get the qualification from a document Parameters Name Type Description document any The document Returns Qualification The document qualification Defined in packages/cozy-client/src/models/document/qualification.js:288", "title": "getQualification"}, {"location": "cozy-client/api/cozy-client/modules/models.document/#setqualification", "text": "\u25b8 setQualification ( document , qualification ): any Set the qualification to the document metadata Parameters Name Type Description document any The document to set the qualification qualification Qualification The qualification to set Returns any The qualified document Defined in packages/cozy-client/src/models/document/qualification.js:264", "title": "setQualification"}, {"location": "cozy-client/api/cozy-client/modules/models.document.themes/", "text": "cozy-client / models / document / themes Namespace: themes \u00b6 models . document .themes Variables \u00b6 themesList \u00b6 \u2022 Const themesList : ThemesList Defined in packages/cozy-client/src/models/document/documentTypeData.js:36", "title": "Models.document.themes"}, {"location": "cozy-client/api/cozy-client/modules/models.document.themes/#namespace-themes", "text": "models . document .themes", "title": "Namespace: themes"}, {"location": "cozy-client/api/cozy-client/modules/models.document.themes/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/models.document.themes/#themeslist", "text": "\u2022 Const themesList : ThemesList Defined in packages/cozy-client/src/models/document/documentTypeData.js:36", "title": "themesList"}, {"location": "cozy-client/api/cozy-client/modules/models.file/", "text": "cozy-client / models / file Namespace: file \u00b6 models .file Interfaces \u00b6 FileUploadOptions Variables \u00b6 ALBUMS_DOCTYPE \u00b6 \u2022 Const ALBUMS_DOCTYPE : \"io.cozy.photos.albums\" Defined in packages/cozy-client/src/models/file.js:14 Functions \u00b6 doMobileUpload \u00b6 \u25b8 doMobileUpload ( client , fileURL , options ): Promise < any > Upload a file on a mobile Parameters Name Type Description client CozyClient The CozyClient instance fileURL string The local file path (file://) options FileUploadOptions The upload options Returns Promise < any > Defined in packages/cozy-client/src/models/file.js:604 ensureFilePath \u00b6 \u25b8 ensureFilePath ( file , parent ): any Ensure the file has a path attribute, or build it Parameters Name Type Description file any object representing the file parent any parent directory for the file Returns any file object with path attribute Defined in packages/cozy-client/src/models/file.js:136 fetchBlobFileById \u00b6 \u25b8 fetchBlobFileById ( client , fileId ): Promise < Blob > Parameters Name Type Description client CozyClient Instance of CozyClient fileId string Id of io.cozy.files document Returns Promise < Blob > Defined in packages/cozy-client/src/models/file.js:650 fetchFilesByQualificationRules \u00b6 \u25b8 fetchFilesByQualificationRules ( client , docRules ): Promise < any > Helper to query files based on qualification rules Parameters Name Type Description client any The CozyClient instance docRules any the rules containing the searched qualification and the count Returns Promise < any > The files found by the rules Defined in packages/cozy-client/src/models/file.js:256 generateFileNameForRevision \u00b6 \u25b8 generateFileNameForRevision ( file , revision , f ): string Generate a file name for a revision Parameters Name Type Description file IOCozyFile io.cozy.files document revision any The revision containing the updated_at f Function A function taking a a date and a format as arguments to generate the name. Returns string Defined in packages/cozy-client/src/models/file.js:484 generateNewFileNameOnConflict \u00b6 \u25b8 generateNewFileNameOnConflict ( filenameWithoutExtension , conflictOptions ): string Method to generate a new filename if there is a conflict Parameters Name Type Description filenameWithoutExtension string A filename without the extension conflictOptions ConflictOptions - Returns string A filename with the right suffix Defined in packages/cozy-client/src/models/file.js:454 getFullpath \u00b6 \u25b8 getFullpath ( client , dirId , name ): Promise < string > async getFullpath - Gets a file\u2019s path Parameters Name Type Description client CozyClient The CozyClient instance dirId string The id of the parent directory name string The file\u2019s name Returns Promise < string > The full path of the file in the cozy Defined in packages/cozy-client/src/models/file.js:291 getParentFolderId \u00b6 \u25b8 getParentFolderId ( file ): string Get the id of the parent folder ( null for the root folder) Parameters Name Type Description file any io.cozy.files document Returns string id of the parent folder, if any Defined in packages/cozy-client/src/models/file.js:150 getSharingShortcutStatus \u00b6 \u25b8 getSharingShortcutStatus ( file ): string Returns the status of a sharing shortcut. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string A description of the status Defined in packages/cozy-client/src/models/file.js:162 getSharingShortcutTargetDoctype \u00b6 \u25b8 getSharingShortcutTargetDoctype ( file ): string Returns the doctype of the target of the sharing shortcut. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string A doctype Defined in packages/cozy-client/src/models/file.js:182 getSharingShortcutTargetMime \u00b6 \u25b8 getSharingShortcutTargetMime ( file ): string Returns the mime type of the target of the sharing shortcut, if it is a file. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string The mime-type of the target file, or an empty string is the target is not a file. Defined in packages/cozy-client/src/models/file.js:172 hasCertifications \u00b6 \u25b8 hasCertifications ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:630 hasMetadataAttribute \u00b6 \u25b8 hasMetadataAttribute ( params ): boolean Whether the file\u2019s metadata attribute exists Parameters Name Type Description params Object Param params.attribute string Metadata attribute to check params.file IOCozyFile An io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:280 hasQualifications \u00b6 \u25b8 hasQualifications ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:622 isDirectory \u00b6 \u25b8 isDirectory ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files Returns boolean Defined in packages/cozy-client/src/models/file.js:46 isEncrypted \u00b6 \u25b8 isEncrypted ( file ): boolean Whether the file is client-side encrypted Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:74 isFile \u00b6 \u25b8 isFile ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files Returns boolean Defined in packages/cozy-client/src/models/file.js:40 isFromKonnector \u00b6 \u25b8 isFromKonnector ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:641 isNote \u00b6 \u25b8 isNote ( file ): boolean Is file param a correct note Parameters Name Type Description file IOCozyFile io.cozy.files Returns boolean Defined in packages/cozy-client/src/models/file.js:54 isOnlyOfficeFile \u00b6 \u25b8 isOnlyOfficeFile ( file ): boolean Whether the file is supported by Only Office Parameters Name Type Description file IOCozyFile io.cozy.file document Returns boolean Defined in packages/cozy-client/src/models/file.js:84 isPlainText \u00b6 \u25b8 isPlainText ( mimeType? , fileName? ): boolean Parameters Name Type Default value mimeType string '' fileName string '' Returns boolean Defined in packages/cozy-client/src/models/file.js:614 isSharingShorcut \u00b6 \u25b8 isSharingShorcut ( file ): boolean Returns whether the file is a shortcut to a sharing deprecated Prefer to use isSharingShortcut. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:202 isSharingShorcutNew \u00b6 \u25b8 isSharingShorcutNew ( file ): boolean Returns whether the sharing shortcut is new deprecated Prefer to use isSharingShortcutNew. Parameters Name Type Description file any io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:227 isSharingShortcut \u00b6 \u25b8 isSharingShortcut ( file ): boolean Returns whether the file is a shortcut to a sharing Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:192 isSharingShortcutNew \u00b6 \u25b8 isSharingShortcutNew ( file ): boolean Returns whether the sharing shortcut is new Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:216 isShortcut \u00b6 \u25b8 isShortcut ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean true if the file is a shortcut Defined in packages/cozy-client/src/models/file.js:109 move \u00b6 \u25b8 move ( client , file , destination , options? ): Promise <{ deleted : string [] ; moved : IOCozyFile }> Move file to destination. Manage 4 cases : Move inside a Cozy server Move inside a Nextcloud server Move from a Nextcloud server to Cozy Move from Cozy to a Nextcloud server Parameters Name Type Description client CozyClient The CozyClient instance file IOCozyFile NextcloudFile destination NextcloudFile IOCozyFolder options Object The options options.force boolean Whether we should overwrite, i.e. put to trash, the destination in case of conflict (defaults to false). Returns Promise <{ deleted : string [] ; moved : IOCozyFile }> } - A promise that returns the move action response (if any) and the deleted file id (if any) if resolved or an Error if rejected Defined in packages/cozy-client/src/models/file.js:320 normalize \u00b6 \u25b8 normalize ( file ): any Normalizes an object representing a io.cozy.files object Ensures existence of _id and _type Parameters Name Type Description file any object representing the file Returns any full normalized object Defined in packages/cozy-client/src/models/file.js:122 overrideFileForPath \u00b6 \u25b8 overrideFileForPath ( client , dirPath , file , metadata ): Promise < IOCozyFile > Method to upload a file even if a file with the same name already exists. Parameters Name Type Description client CozyClient The CozyClient instance dirPath string Fullpath of directory to upload to ex: path/to/ file any HTML Object file metadata any An object containing the wanted metadata to attach Returns Promise < IOCozyFile > The overrided file Defined in packages/cozy-client/src/models/file.js:420 readMobileFile \u00b6 \u25b8 readMobileFile ( fileURL ): Promise < any > Read a file on a mobile Parameters Name Type Description fileURL string The local file path (file://) Returns Promise < any > Defined in packages/cozy-client/src/models/file.js:557 saveFileQualification \u00b6 \u25b8 saveFileQualification ( client , file , qualification ): Promise < IOCozyFile > Save the file with the given qualification Parameters Name Type Description client CozyClient The CozyClient instance file IOCozyFile The file to qualify qualification any The file qualification Returns Promise < IOCozyFile > The saved file Defined in packages/cozy-client/src/models/file.js:242 shouldBeOpenedByOnlyOffice \u00b6 \u25b8 shouldBeOpenedByOnlyOffice ( file ): boolean Whether the file should be opened by only office We want to be consistent with the stack so we check the class attributes But we want to exclude .txt and .md because the CozyUI Viewer can already show them Parameters Name Type Description file IOCozyFile io.cozy.file document Returns boolean Defined in packages/cozy-client/src/models/file.js:99 splitFilename \u00b6 \u25b8 splitFilename ( file ): Object Returns base filename and extension Parameters Name Type Description file IOCozyFile An io.cozy.files Returns Object Name Type extension string filename string Defined in packages/cozy-client/src/models/file.js:24 uploadFileWithConflictStrategy \u00b6 \u25b8 uploadFileWithConflictStrategy ( client , file , options ): any The goal of this method is to upload a file based on a conflict strategy. Be careful: We need to check if the file exists by doing a statByPath query before trying to upload the file since if we post and the stack return a 409 conflict, we will get a SPDY_ERROR_PROTOCOL on Chrome. This is the only viable workaround If there is no conflict, then we upload the file. If there is a conflict, then we apply the conflict strategy : erase or rename : The erase strategy means an upload with a new version The rename strategy means a new upload with a new name Parameters Name Type Description client CozyClient The CozyClient instance file string ArrayBuffer options FileUploadOptions The upload options Returns any Defined in packages/cozy-client/src/models/file.js:517", "title": "Models.file"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#namespace-file", "text": "models .file", "title": "Namespace: file"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#interfaces", "text": "FileUploadOptions", "title": "Interfaces"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#albums_doctype", "text": "\u2022 Const ALBUMS_DOCTYPE : \"io.cozy.photos.albums\" Defined in packages/cozy-client/src/models/file.js:14", "title": "ALBUMS_DOCTYPE"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#domobileupload", "text": "\u25b8 doMobileUpload ( client , fileURL , options ): Promise < any > Upload a file on a mobile Parameters Name Type Description client CozyClient The CozyClient instance fileURL string The local file path (file://) options FileUploadOptions The upload options Returns Promise < any > Defined in packages/cozy-client/src/models/file.js:604", "title": "doMobileUpload"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#ensurefilepath", "text": "\u25b8 ensureFilePath ( file , parent ): any Ensure the file has a path attribute, or build it Parameters Name Type Description file any object representing the file parent any parent directory for the file Returns any file object with path attribute Defined in packages/cozy-client/src/models/file.js:136", "title": "ensureFilePath"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#fetchblobfilebyid", "text": "\u25b8 fetchBlobFileById ( client , fileId ): Promise < Blob > Parameters Name Type Description client CozyClient Instance of CozyClient fileId string Id of io.cozy.files document Returns Promise < Blob > Defined in packages/cozy-client/src/models/file.js:650", "title": "fetchBlobFileById"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#fetchfilesbyqualificationrules", "text": "\u25b8 fetchFilesByQualificationRules ( client , docRules ): Promise < any > Helper to query files based on qualification rules Parameters Name Type Description client any The CozyClient instance docRules any the rules containing the searched qualification and the count Returns Promise < any > The files found by the rules Defined in packages/cozy-client/src/models/file.js:256", "title": "fetchFilesByQualificationRules"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#generatefilenameforrevision", "text": "\u25b8 generateFileNameForRevision ( file , revision , f ): string Generate a file name for a revision Parameters Name Type Description file IOCozyFile io.cozy.files document revision any The revision containing the updated_at f Function A function taking a a date and a format as arguments to generate the name. Returns string Defined in packages/cozy-client/src/models/file.js:484", "title": "generateFileNameForRevision"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#generatenewfilenameonconflict", "text": "\u25b8 generateNewFileNameOnConflict ( filenameWithoutExtension , conflictOptions ): string Method to generate a new filename if there is a conflict Parameters Name Type Description filenameWithoutExtension string A filename without the extension conflictOptions ConflictOptions - Returns string A filename with the right suffix Defined in packages/cozy-client/src/models/file.js:454", "title": "generateNewFileNameOnConflict"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#getfullpath", "text": "\u25b8 getFullpath ( client , dirId , name ): Promise < string > async getFullpath - Gets a file\u2019s path Parameters Name Type Description client CozyClient The CozyClient instance dirId string The id of the parent directory name string The file\u2019s name Returns Promise < string > The full path of the file in the cozy Defined in packages/cozy-client/src/models/file.js:291", "title": "getFullpath"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#getparentfolderid", "text": "\u25b8 getParentFolderId ( file ): string Get the id of the parent folder ( null for the root folder) Parameters Name Type Description file any io.cozy.files document Returns string id of the parent folder, if any Defined in packages/cozy-client/src/models/file.js:150", "title": "getParentFolderId"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#getsharingshortcutstatus", "text": "\u25b8 getSharingShortcutStatus ( file ): string Returns the status of a sharing shortcut. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string A description of the status Defined in packages/cozy-client/src/models/file.js:162", "title": "getSharingShortcutStatus"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#getsharingshortcuttargetdoctype", "text": "\u25b8 getSharingShortcutTargetDoctype ( file ): string Returns the doctype of the target of the sharing shortcut. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string A doctype Defined in packages/cozy-client/src/models/file.js:182", "title": "getSharingShortcutTargetDoctype"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#getsharingshortcuttargetmime", "text": "\u25b8 getSharingShortcutTargetMime ( file ): string Returns the mime type of the target of the sharing shortcut, if it is a file. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string The mime-type of the target file, or an empty string is the target is not a file. Defined in packages/cozy-client/src/models/file.js:172", "title": "getSharingShortcutTargetMime"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#hascertifications", "text": "\u25b8 hasCertifications ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:630", "title": "hasCertifications"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#hasmetadataattribute", "text": "\u25b8 hasMetadataAttribute ( params ): boolean Whether the file\u2019s metadata attribute exists Parameters Name Type Description params Object Param params.attribute string Metadata attribute to check params.file IOCozyFile An io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:280", "title": "hasMetadataAttribute"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#hasqualifications", "text": "\u25b8 hasQualifications ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:622", "title": "hasQualifications"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isdirectory", "text": "\u25b8 isDirectory ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files Returns boolean Defined in packages/cozy-client/src/models/file.js:46", "title": "isDirectory"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isencrypted", "text": "\u25b8 isEncrypted ( file ): boolean Whether the file is client-side encrypted Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:74", "title": "isEncrypted"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isfile", "text": "\u25b8 isFile ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files Returns boolean Defined in packages/cozy-client/src/models/file.js:40", "title": "isFile"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isfromkonnector", "text": "\u25b8 isFromKonnector ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:641", "title": "isFromKonnector"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isnote", "text": "\u25b8 isNote ( file ): boolean Is file param a correct note Parameters Name Type Description file IOCozyFile io.cozy.files Returns boolean Defined in packages/cozy-client/src/models/file.js:54", "title": "isNote"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isonlyofficefile", "text": "\u25b8 isOnlyOfficeFile ( file ): boolean Whether the file is supported by Only Office Parameters Name Type Description file IOCozyFile io.cozy.file document Returns boolean Defined in packages/cozy-client/src/models/file.js:84", "title": "isOnlyOfficeFile"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isplaintext", "text": "\u25b8 isPlainText ( mimeType? , fileName? ): boolean Parameters Name Type Default value mimeType string '' fileName string '' Returns boolean Defined in packages/cozy-client/src/models/file.js:614", "title": "isPlainText"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#issharingshorcut", "text": "\u25b8 isSharingShorcut ( file ): boolean Returns whether the file is a shortcut to a sharing deprecated Prefer to use isSharingShortcut. Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:202", "title": "isSharingShorcut"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#issharingshorcutnew", "text": "\u25b8 isSharingShorcutNew ( file ): boolean Returns whether the sharing shortcut is new deprecated Prefer to use isSharingShortcutNew. Parameters Name Type Description file any io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:227", "title": "isSharingShorcutNew"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#issharingshortcut", "text": "\u25b8 isSharingShortcut ( file ): boolean Returns whether the file is a shortcut to a sharing Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:192", "title": "isSharingShortcut"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#issharingshortcutnew", "text": "\u25b8 isSharingShortcutNew ( file ): boolean Returns whether the sharing shortcut is new Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/file.js:216", "title": "isSharingShortcutNew"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#isshortcut", "text": "\u25b8 isShortcut ( file ): boolean Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean true if the file is a shortcut Defined in packages/cozy-client/src/models/file.js:109", "title": "isShortcut"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#move", "text": "\u25b8 move ( client , file , destination , options? ): Promise <{ deleted : string [] ; moved : IOCozyFile }> Move file to destination. Manage 4 cases : Move inside a Cozy server Move inside a Nextcloud server Move from a Nextcloud server to Cozy Move from Cozy to a Nextcloud server Parameters Name Type Description client CozyClient The CozyClient instance file IOCozyFile NextcloudFile destination NextcloudFile IOCozyFolder options Object The options options.force boolean Whether we should overwrite, i.e. put to trash, the destination in case of conflict (defaults to false). Returns Promise <{ deleted : string [] ; moved : IOCozyFile }> } - A promise that returns the move action response (if any) and the deleted file id (if any) if resolved or an Error if rejected Defined in packages/cozy-client/src/models/file.js:320", "title": "move"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#normalize", "text": "\u25b8 normalize ( file ): any Normalizes an object representing a io.cozy.files object Ensures existence of _id and _type Parameters Name Type Description file any object representing the file Returns any full normalized object Defined in packages/cozy-client/src/models/file.js:122", "title": "normalize"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#overridefileforpath", "text": "\u25b8 overrideFileForPath ( client , dirPath , file , metadata ): Promise < IOCozyFile > Method to upload a file even if a file with the same name already exists. Parameters Name Type Description client CozyClient The CozyClient instance dirPath string Fullpath of directory to upload to ex: path/to/ file any HTML Object file metadata any An object containing the wanted metadata to attach Returns Promise < IOCozyFile > The overrided file Defined in packages/cozy-client/src/models/file.js:420", "title": "overrideFileForPath"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#readmobilefile", "text": "\u25b8 readMobileFile ( fileURL ): Promise < any > Read a file on a mobile Parameters Name Type Description fileURL string The local file path (file://) Returns Promise < any > Defined in packages/cozy-client/src/models/file.js:557", "title": "readMobileFile"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#savefilequalification", "text": "\u25b8 saveFileQualification ( client , file , qualification ): Promise < IOCozyFile > Save the file with the given qualification Parameters Name Type Description client CozyClient The CozyClient instance file IOCozyFile The file to qualify qualification any The file qualification Returns Promise < IOCozyFile > The saved file Defined in packages/cozy-client/src/models/file.js:242", "title": "saveFileQualification"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#shouldbeopenedbyonlyoffice", "text": "\u25b8 shouldBeOpenedByOnlyOffice ( file ): boolean Whether the file should be opened by only office We want to be consistent with the stack so we check the class attributes But we want to exclude .txt and .md because the CozyUI Viewer can already show them Parameters Name Type Description file IOCozyFile io.cozy.file document Returns boolean Defined in packages/cozy-client/src/models/file.js:99", "title": "shouldBeOpenedByOnlyOffice"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#splitfilename", "text": "\u25b8 splitFilename ( file ): Object Returns base filename and extension Parameters Name Type Description file IOCozyFile An io.cozy.files Returns Object Name Type extension string filename string Defined in packages/cozy-client/src/models/file.js:24", "title": "splitFilename"}, {"location": "cozy-client/api/cozy-client/modules/models.file/#uploadfilewithconflictstrategy", "text": "\u25b8 uploadFileWithConflictStrategy ( client , file , options ): any The goal of this method is to upload a file based on a conflict strategy. Be careful: We need to check if the file exists by doing a statByPath query before trying to upload the file since if we post and the stack return a 409 conflict, we will get a SPDY_ERROR_PROTOCOL on Chrome. This is the only viable workaround If there is no conflict, then we upload the file. If there is a conflict, then we apply the conflict strategy : erase or rename : The erase strategy means an upload with a new version The rename strategy means a new upload with a new name Parameters Name Type Description client CozyClient The CozyClient instance file string ArrayBuffer options FileUploadOptions The upload options Returns any Defined in packages/cozy-client/src/models/file.js:517", "title": "uploadFileWithConflictStrategy"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/", "text": "cozy-client / models / folder Namespace: folder \u00b6 models .folder Variables \u00b6 MAGIC_FOLDERS \u00b6 \u2022 Const MAGIC_FOLDERS : Object Type declaration Name Type ADMINISTRATIVE string COACH_CO2 string HOME string NOTES string PAPERS string PHOTOS string PHOTOS_BACKUP string PHOTOS_UPLOAD string Defined in packages/cozy-client/src/models/folder.js:11 Functions \u00b6 createFolderWithReference \u00b6 \u25b8 createFolderWithReference ( client , path , document ): Promise < IOCozyFolder > Create a folder with a reference to the given document Parameters Name Type Description client CozyClient cozy-client instance path string Folder path document CozyClientDocument Document to make reference to. Any doctype. Returns Promise < IOCozyFolder > Folder document Defined in packages/cozy-client/src/models/folder.js:71 ensureMagicFolder \u00b6 \u25b8 ensureMagicFolder ( client , id , path ): Promise < IOCozyFolder > Returns a \u201cMagic Folder\u201d, given its id. See https://docs.cozy.io/en/cozy-doctypes/docs/io.cozy.apps/#special-iocozyapps-doctypes Parameters Name Type Description client CozyClient cozy-client instance id string Magic Folder id. CozyFolder.magicFolders contains the ids of folders that can be magic folders. path string Default path to use if magic folder does not exist Returns Promise < IOCozyFolder > Folder document Defined in packages/cozy-client/src/models/folder.js:31 getReferencedFolder \u00b6 \u25b8 getReferencedFolder ( client , document ): Promise < IOCozyFolder > Returns the most recent folder referenced by the given document Parameters Name Type Description client CozyClient cozy-client instance document CozyClientDocument Document to get references from Returns Promise < IOCozyFolder > Folder referenced by the given document Defined in packages/cozy-client/src/models/folder.js:92", "title": "Models.folder"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/#namespace-folder", "text": "models .folder", "title": "Namespace: folder"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/#magic_folders", "text": "\u2022 Const MAGIC_FOLDERS : Object Type declaration Name Type ADMINISTRATIVE string COACH_CO2 string HOME string NOTES string PAPERS string PHOTOS string PHOTOS_BACKUP string PHOTOS_UPLOAD string Defined in packages/cozy-client/src/models/folder.js:11", "title": "MAGIC_FOLDERS"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/#createfolderwithreference", "text": "\u25b8 createFolderWithReference ( client , path , document ): Promise < IOCozyFolder > Create a folder with a reference to the given document Parameters Name Type Description client CozyClient cozy-client instance path string Folder path document CozyClientDocument Document to make reference to. Any doctype. Returns Promise < IOCozyFolder > Folder document Defined in packages/cozy-client/src/models/folder.js:71", "title": "createFolderWithReference"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/#ensuremagicfolder", "text": "\u25b8 ensureMagicFolder ( client , id , path ): Promise < IOCozyFolder > Returns a \u201cMagic Folder\u201d, given its id. See https://docs.cozy.io/en/cozy-doctypes/docs/io.cozy.apps/#special-iocozyapps-doctypes Parameters Name Type Description client CozyClient cozy-client instance id string Magic Folder id. CozyFolder.magicFolders contains the ids of folders that can be magic folders. path string Default path to use if magic folder does not exist Returns Promise < IOCozyFolder > Folder document Defined in packages/cozy-client/src/models/folder.js:31", "title": "ensureMagicFolder"}, {"location": "cozy-client/api/cozy-client/modules/models.folder/#getreferencedfolder", "text": "\u25b8 getReferencedFolder ( client , document ): Promise < IOCozyFolder > Returns the most recent folder referenced by the given document Parameters Name Type Description client CozyClient cozy-client instance document CozyClientDocument Document to get references from Returns Promise < IOCozyFolder > Folder referenced by the given document Defined in packages/cozy-client/src/models/folder.js:92", "title": "getReferencedFolder"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/", "text": "cozy-client / models / geo Namespace: geo \u00b6 models .geo Functions \u00b6 computeSpeed \u00b6 \u25b8 computeSpeed ( distance , duration ): number Compute the speed from distance and duration Parameters Name Type Description distance number The distance in meters duration number The duration in seconds Returns number The speed, in m/s, rounded to 2 decimals Defined in packages/cozy-client/src/models/geo.js:12 computeSphericalCenter \u00b6 \u25b8 computeSphericalCenter ( coordinates ): Coordinates Compute the geographical center of the given points This consists of finding the centroid of a set of points in a sphere. Note this assumes the Earth is a perfect sphere, which is not, but the approximation should be good enough. Parameters Name Type Description coordinates Coordinates [] The geo points Returns Coordinates The center point Defined in packages/cozy-client/src/models/geo.js:104 deltaLatitude \u00b6 \u25b8 deltaLatitude ( distance ): number Compute the latitude delta from a distance, in meters. The reasoning is rather simple: there are 360\u00b0 of latitudes of same distance. Then, it consists of computing 1 degree distance, and divide the given distance by this value. Parameters Name Type Description distance number The distance in meters Returns number The delta latitude degrees Defined in packages/cozy-client/src/models/geo.js:172 deltaLongitude \u00b6 \u25b8 deltaLongitude ( latitude , distance ): number Compute the longitude delta from a distance, in meters. This requires the latitude: we want to compute the horizontal delta on the Earth surface. As it is a sphere (kind of), this delta won\u2019t be the same depending on whether it is on the equator (min variation) or on the poles (max variation), for instance. Parameters Name Type Description latitude number The latitude distance number The distance in meters Returns number the longitude delta degrees Defined in packages/cozy-client/src/models/geo.js:155 geodesicDistance \u00b6 \u25b8 geodesicDistance ( point1 , point2 ): number Compute the distance between 2 geographic points, in meters. This is an implementation of the Haversine formula, that supposes a perfect sphere. We know this is not exactly the case for Earth, especially at the poles, but this approximation is good enough. More complex methods do exist, such as Vincenty formula, but we prefer simplicity over precision here. See https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid Parameters Name Type Description point1 Coordinates The first point coordinates, in decimal degrees point2 Coordinates The second point coordinates, in decimal degrees Returns number The distance between the points, in meters, rounded to 2 decimals Defined in packages/cozy-client/src/models/geo.js:65", "title": "Models.geo"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/#namespace-geo", "text": "models .geo", "title": "Namespace: geo"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/#computespeed", "text": "\u25b8 computeSpeed ( distance , duration ): number Compute the speed from distance and duration Parameters Name Type Description distance number The distance in meters duration number The duration in seconds Returns number The speed, in m/s, rounded to 2 decimals Defined in packages/cozy-client/src/models/geo.js:12", "title": "computeSpeed"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/#computesphericalcenter", "text": "\u25b8 computeSphericalCenter ( coordinates ): Coordinates Compute the geographical center of the given points This consists of finding the centroid of a set of points in a sphere. Note this assumes the Earth is a perfect sphere, which is not, but the approximation should be good enough. Parameters Name Type Description coordinates Coordinates [] The geo points Returns Coordinates The center point Defined in packages/cozy-client/src/models/geo.js:104", "title": "computeSphericalCenter"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/#deltalatitude", "text": "\u25b8 deltaLatitude ( distance ): number Compute the latitude delta from a distance, in meters. The reasoning is rather simple: there are 360\u00b0 of latitudes of same distance. Then, it consists of computing 1 degree distance, and divide the given distance by this value. Parameters Name Type Description distance number The distance in meters Returns number The delta latitude degrees Defined in packages/cozy-client/src/models/geo.js:172", "title": "deltaLatitude"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/#deltalongitude", "text": "\u25b8 deltaLongitude ( latitude , distance ): number Compute the longitude delta from a distance, in meters. This requires the latitude: we want to compute the horizontal delta on the Earth surface. As it is a sphere (kind of), this delta won\u2019t be the same depending on whether it is on the equator (min variation) or on the poles (max variation), for instance. Parameters Name Type Description latitude number The latitude distance number The distance in meters Returns number the longitude delta degrees Defined in packages/cozy-client/src/models/geo.js:155", "title": "deltaLongitude"}, {"location": "cozy-client/api/cozy-client/modules/models.geo/#geodesicdistance", "text": "\u25b8 geodesicDistance ( point1 , point2 ): number Compute the distance between 2 geographic points, in meters. This is an implementation of the Haversine formula, that supposes a perfect sphere. We know this is not exactly the case for Earth, especially at the poles, but this approximation is good enough. More complex methods do exist, such as Vincenty formula, but we prefer simplicity over precision here. See https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid Parameters Name Type Description point1 Coordinates The first point coordinates, in decimal degrees point2 Coordinates The second point coordinates, in decimal degrees Returns number The distance between the points, in meters, rounded to 2 decimals Defined in packages/cozy-client/src/models/geo.js:65", "title": "geodesicDistance"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/", "text": "cozy-client / models / instance Namespace: instance \u00b6 models .instance Interfaces \u00b6 DiskInfos DiskInfosRaw SettingsInfo Type aliases \u00b6 ContextInfo \u00b6 \u01ac ContextInfo <>: object Defined in packages/cozy-client/src/models/instance.js:10 DiskUsageInfo \u00b6 \u01ac DiskUsageInfo <>: object Defined in packages/cozy-client/src/models/instance.js:11 InstanceInfo \u00b6 \u01ac InstanceInfo <>: object Defined in packages/cozy-client/src/models/instance.js:9 Functions \u00b6 arePremiumLinksEnabled \u00b6 \u25b8 arePremiumLinksEnabled ( instanceInfo ): boolean Parameters Name Type instanceInfo any Returns boolean Defined in packages/cozy-client/src/models/instance.js:25 buildPremiumLink \u00b6 \u25b8 buildPremiumLink ( instanceInfo ): string Returns the link to the Premium page on the Cozy\u2019s Manager Parameters Name Type Description instanceInfo any Instance information Returns string Defined in packages/cozy-client/src/models/instance.js:72 getUuid \u00b6 \u25b8 getUuid ( instanceInfo ): any Parameters Name Type instanceInfo any Returns any Defined in packages/cozy-client/src/models/instance.js:34 hasAnOffer \u00b6 \u25b8 hasAnOffer ( data ): boolean Returns if an instance has subscribed to one of our offers Parameters Name Type Description data SettingsInfo Object containing all the results from /settings/* Returns boolean Does the cozy have offers Defined in packages/cozy-client/src/models/instance.js:58 hasPasswordDefinedAttribute \u00b6 \u25b8 hasPasswordDefinedAttribute ( client ): Promise < boolean > Checks the value of the password_defined attribute Parameters Name Type Description client CozyClient The CozyClient instance Returns Promise < boolean > Returns the value of the password_defined attribute Defined in packages/cozy-client/src/models/instance.js:92 isFreemiumUser \u00b6 \u25b8 isFreemiumUser ( instanceInfo ): boolean Parameters Name Type instanceInfo any Returns boolean Defined in packages/cozy-client/src/models/instance.js:30 isSelfHosted \u00b6 \u25b8 isSelfHosted ( instanceInfo ): boolean property {ContextInfo} context - Object returned by /settings/context property {InstanceInfo} instance - Object returned by /settings/instance property {DiskUsageInfo} diskUsage - Object returned by /settings/disk-usage Parameters Name Type instanceInfo any Returns boolean Defined in packages/cozy-client/src/models/instance.js:22 makeDiskInfos \u00b6 \u25b8 makeDiskInfos ( usage , quota ): DiskInfos Make human readable information from disk information (usage, quota) Parameters Name Type Description usage string number quota string number Returns DiskInfos Return a set of human readable information about disk Defined in packages/cozy-client/src/models/instance.js:164 shouldDisplayOffers \u00b6 \u25b8 shouldDisplayOffers ( data ): boolean Returns whether an instance is concerned by our offers Parameters Name Type Description data SettingsInfo Object containing all the results from /settings/* Returns boolean Should we display offers Defined in packages/cozy-client/src/models/instance.js:44", "title": "Models.instance"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#namespace-instance", "text": "models .instance", "title": "Namespace: instance"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#interfaces", "text": "DiskInfos DiskInfosRaw SettingsInfo", "title": "Interfaces"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#type-aliases", "text": "", "title": "Type aliases"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#contextinfo", "text": "\u01ac ContextInfo <>: object Defined in packages/cozy-client/src/models/instance.js:10", "title": "ContextInfo"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#diskusageinfo", "text": "\u01ac DiskUsageInfo <>: object Defined in packages/cozy-client/src/models/instance.js:11", "title": "DiskUsageInfo"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#instanceinfo", "text": "\u01ac InstanceInfo <>: object Defined in packages/cozy-client/src/models/instance.js:9", "title": "InstanceInfo"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#arepremiumlinksenabled", "text": "\u25b8 arePremiumLinksEnabled ( instanceInfo ): boolean Parameters Name Type instanceInfo any Returns boolean Defined in packages/cozy-client/src/models/instance.js:25", "title": "arePremiumLinksEnabled"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#buildpremiumlink", "text": "\u25b8 buildPremiumLink ( instanceInfo ): string Returns the link to the Premium page on the Cozy\u2019s Manager Parameters Name Type Description instanceInfo any Instance information Returns string Defined in packages/cozy-client/src/models/instance.js:72", "title": "buildPremiumLink"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#getuuid", "text": "\u25b8 getUuid ( instanceInfo ): any Parameters Name Type instanceInfo any Returns any Defined in packages/cozy-client/src/models/instance.js:34", "title": "getUuid"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#hasanoffer", "text": "\u25b8 hasAnOffer ( data ): boolean Returns if an instance has subscribed to one of our offers Parameters Name Type Description data SettingsInfo Object containing all the results from /settings/* Returns boolean Does the cozy have offers Defined in packages/cozy-client/src/models/instance.js:58", "title": "hasAnOffer"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#haspassworddefinedattribute", "text": "\u25b8 hasPasswordDefinedAttribute ( client ): Promise < boolean > Checks the value of the password_defined attribute Parameters Name Type Description client CozyClient The CozyClient instance Returns Promise < boolean > Returns the value of the password_defined attribute Defined in packages/cozy-client/src/models/instance.js:92", "title": "hasPasswordDefinedAttribute"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#isfreemiumuser", "text": "\u25b8 isFreemiumUser ( instanceInfo ): boolean Parameters Name Type instanceInfo any Returns boolean Defined in packages/cozy-client/src/models/instance.js:30", "title": "isFreemiumUser"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#isselfhosted", "text": "\u25b8 isSelfHosted ( instanceInfo ): boolean property {ContextInfo} context - Object returned by /settings/context property {InstanceInfo} instance - Object returned by /settings/instance property {DiskUsageInfo} diskUsage - Object returned by /settings/disk-usage Parameters Name Type instanceInfo any Returns boolean Defined in packages/cozy-client/src/models/instance.js:22", "title": "isSelfHosted"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#makediskinfos", "text": "\u25b8 makeDiskInfos ( usage , quota ): DiskInfos Make human readable information from disk information (usage, quota) Parameters Name Type Description usage string number quota string number Returns DiskInfos Return a set of human readable information about disk Defined in packages/cozy-client/src/models/instance.js:164", "title": "makeDiskInfos"}, {"location": "cozy-client/api/cozy-client/modules/models.instance/#shoulddisplayoffers", "text": "\u25b8 shouldDisplayOffers ( data ): boolean Returns whether an instance is concerned by our offers Parameters Name Type Description data SettingsInfo Object containing all the results from /settings/* Returns boolean Should we display offers Defined in packages/cozy-client/src/models/instance.js:44", "title": "shouldDisplayOffers"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/", "text": "cozy-client / models / konnectorFolder Namespace: konnectorFolder \u00b6 models .konnectorFolder Functions \u00b6 buildFolderPath \u00b6 \u25b8 buildFolderPath ( konnector , account , magicFolders? ): string Build folder path for a given konnector and a given account. If konnector.folders[0].defaultDir exists, it is used as default directory. Occurrences of following strings in base directory are replaced by: $administrative : Administrative folder $photos : Photos folder Occurrences of following strings in path are replaced by: $account: Account label (id or name) $konnector : Konnector name If no konnectors.folders[0].defaultDir is set, the default dir used is $administrative/$konnector/$account Parameters Name Type Description konnector IOCozyKonnector Konnector document account IOCozyAccount Account document magicFolders Object Object containing a mapping from folder identifiers (ex: $administrative) to their localized values (ex: Administratif). Returns string The result path Defined in packages/cozy-client/src/models/konnectorFolder.js:154 buildFolderPermission \u00b6 \u25b8 buildFolderPermission ( folder ): any Returns a permission ready to be passed to client.collection(\u2018io.cozy.permissions\u2019).add(). Parameters Name Type Description folder IOCozyFolder The folder which the konnector should have access Returns any Permission object Defined in packages/cozy-client/src/models/konnectorFolder.js:266 createDirectoryByPath \u00b6 \u25b8 createDirectoryByPath ( client , path ): Promise < IOCozyFolder > Creates a directory from a given path Parameters Name Type Description client CozyClient CozyClient path string Directory path Returns Promise < IOCozyFolder > Directory attributes Defined in packages/cozy-client/src/models/konnectorFolder.js:102 ensureKonnectorFolder \u00b6 \u25b8 ensureKonnectorFolder ( client , options ): Promise < IOCozyFolder > Ensures the destination folder of a konnector exists and is initiated with proper permissions and references Parameters Name Type Description client CozyClient CozyClient instance options Object options object options.account IOCozyAccount io.cozy.accounts document options.konnector IOCozyKonnector io.cozy.konnectors document options.lang string instance current language. ex: \u2018fr\u2019 Returns Promise < IOCozyFolder > Defined in packages/cozy-client/src/models/konnectorFolder.js:27 findKonnectorAccountFolderByReference \u00b6 \u25b8 findKonnectorAccountFolderByReference ( options ): Promise < IOCozyFolder > try to find a konnector account folder using file references Parameters Name Type Description options Object options object options.client CozyClient CozyClient instance options.slug string konnector slug options.sourceAccountIdentifier string source account identifier Returns Promise < IOCozyFolder > Defined in packages/cozy-client/src/models/konnectorFolder.js:374 statDirectoryByPath \u00b6 \u25b8 statDirectoryByPath ( client , path ): Promise < IOCozyFolder > Retrieves a directory from its path throws will throw an error on any error without status === 404 Parameters Name Type Description client CozyClient CozyClient path string Directory path Returns Promise < IOCozyFolder > Created io.cozy.files document Defined in packages/cozy-client/src/models/konnectorFolder.js:117", "title": "models.konnectorFolder"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#namespace-konnectorfolder", "text": "models .konnectorFolder", "title": "Namespace: konnectorFolder"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#buildfolderpath", "text": "\u25b8 buildFolderPath ( konnector , account , magicFolders? ): string Build folder path for a given konnector and a given account. If konnector.folders[0].defaultDir exists, it is used as default directory. Occurrences of following strings in base directory are replaced by: $administrative : Administrative folder $photos : Photos folder Occurrences of following strings in path are replaced by: $account: Account label (id or name) $konnector : Konnector name If no konnectors.folders[0].defaultDir is set, the default dir used is $administrative/$konnector/$account Parameters Name Type Description konnector IOCozyKonnector Konnector document account IOCozyAccount Account document magicFolders Object Object containing a mapping from folder identifiers (ex: $administrative) to their localized values (ex: Administratif). Returns string The result path Defined in packages/cozy-client/src/models/konnectorFolder.js:154", "title": "buildFolderPath"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#buildfolderpermission", "text": "\u25b8 buildFolderPermission ( folder ): any Returns a permission ready to be passed to client.collection(\u2018io.cozy.permissions\u2019).add(). Parameters Name Type Description folder IOCozyFolder The folder which the konnector should have access Returns any Permission object Defined in packages/cozy-client/src/models/konnectorFolder.js:266", "title": "buildFolderPermission"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#createdirectorybypath", "text": "\u25b8 createDirectoryByPath ( client , path ): Promise < IOCozyFolder > Creates a directory from a given path Parameters Name Type Description client CozyClient CozyClient path string Directory path Returns Promise < IOCozyFolder > Directory attributes Defined in packages/cozy-client/src/models/konnectorFolder.js:102", "title": "createDirectoryByPath"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#ensurekonnectorfolder", "text": "\u25b8 ensureKonnectorFolder ( client , options ): Promise < IOCozyFolder > Ensures the destination folder of a konnector exists and is initiated with proper permissions and references Parameters Name Type Description client CozyClient CozyClient instance options Object options object options.account IOCozyAccount io.cozy.accounts document options.konnector IOCozyKonnector io.cozy.konnectors document options.lang string instance current language. ex: \u2018fr\u2019 Returns Promise < IOCozyFolder > Defined in packages/cozy-client/src/models/konnectorFolder.js:27", "title": "ensureKonnectorFolder"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#findkonnectoraccountfolderbyreference", "text": "\u25b8 findKonnectorAccountFolderByReference ( options ): Promise < IOCozyFolder > try to find a konnector account folder using file references Parameters Name Type Description options Object options object options.client CozyClient CozyClient instance options.slug string konnector slug options.sourceAccountIdentifier string source account identifier Returns Promise < IOCozyFolder > Defined in packages/cozy-client/src/models/konnectorFolder.js:374", "title": "findKonnectorAccountFolderByReference"}, {"location": "cozy-client/api/cozy-client/modules/models.konnectorFolder/#statdirectorybypath", "text": "\u25b8 statDirectoryByPath ( client , path ): Promise < IOCozyFolder > Retrieves a directory from its path throws will throw an error on any error without status === 404 Parameters Name Type Description client CozyClient CozyClient path string Directory path Returns Promise < IOCozyFolder > Created io.cozy.files document Defined in packages/cozy-client/src/models/konnectorFolder.js:117", "title": "statDirectoryByPath"}, {"location": "cozy-client/api/cozy-client/modules/models/", "text": "cozy-client / models Namespace: models \u00b6 Namespaces \u00b6 account applications contact dacc document file folder geo instance konnectorFolder note paper permission sharing timeseries trigger user utils Variables \u00b6 accounts \u00b6 \u2022 Const accounts : account = account Defined in packages/cozy-client/src/models/index.js:22 triggers \u00b6 \u2022 Const triggers : trigger = trigger Defined in packages/cozy-client/src/models/index.js:21", "title": "Models"}, {"location": "cozy-client/api/cozy-client/modules/models/#namespace-models", "text": "", "title": "Namespace: models"}, {"location": "cozy-client/api/cozy-client/modules/models/#namespaces", "text": "account applications contact dacc document file folder geo instance konnectorFolder note paper permission sharing timeseries trigger user utils", "title": "Namespaces"}, {"location": "cozy-client/api/cozy-client/modules/models/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/models/#accounts", "text": "\u2022 Const accounts : account = account Defined in packages/cozy-client/src/models/index.js:22", "title": "accounts"}, {"location": "cozy-client/api/cozy-client/modules/models/#triggers", "text": "\u2022 Const triggers : trigger = trigger Defined in packages/cozy-client/src/models/index.js:21", "title": "triggers"}, {"location": "cozy-client/api/cozy-client/modules/models.note/", "text": "cozy-client / models / note Namespace: note \u00b6 models .note Functions \u00b6 fetchURL \u00b6 \u25b8 fetchURL ( client , file , options? ): Promise < string > Fetch and build an URL to open a note. Parameters Name Type Description client any CozyClient instance file any io.cozy.file object options Object Options options.pathname string - Returns Promise < string > url Defined in packages/cozy-client/src/models/note.js:33 generatePrivateUrl \u00b6 \u25b8 generatePrivateUrl ( notesAppUrl , file , options? ): string Parameters Name Type Description notesAppUrl string URL to the Notes App (https://notes.foo.mycozy.cloud) file any io.cozy.files object options Object - Returns string Defined in packages/cozy-client/src/models/note.js:9 generateUrlForNote \u00b6 \u25b8 generateUrlForNote ( notesAppUrl , file ): string Parameters Name Type notesAppUrl any file any Returns string Defined in packages/cozy-client/src/models/note.js:18", "title": "Models.note"}, {"location": "cozy-client/api/cozy-client/modules/models.note/#namespace-note", "text": "models .note", "title": "Namespace: note"}, {"location": "cozy-client/api/cozy-client/modules/models.note/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.note/#fetchurl", "text": "\u25b8 fetchURL ( client , file , options? ): Promise < string > Fetch and build an URL to open a note. Parameters Name Type Description client any CozyClient instance file any io.cozy.file object options Object Options options.pathname string - Returns Promise < string > url Defined in packages/cozy-client/src/models/note.js:33", "title": "fetchURL"}, {"location": "cozy-client/api/cozy-client/modules/models.note/#generateprivateurl", "text": "\u25b8 generatePrivateUrl ( notesAppUrl , file , options? ): string Parameters Name Type Description notesAppUrl string URL to the Notes App (https://notes.foo.mycozy.cloud) file any io.cozy.files object options Object - Returns string Defined in packages/cozy-client/src/models/note.js:9", "title": "generatePrivateUrl"}, {"location": "cozy-client/api/cozy-client/modules/models.note/#generateurlfornote", "text": "\u25b8 generateUrlForNote ( notesAppUrl , file ): string Parameters Name Type notesAppUrl any file any Returns string Defined in packages/cozy-client/src/models/note.js:18", "title": "generateUrlForNote"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/", "text": "cozy-client / models / paper Namespace: paper \u00b6 models .paper Type aliases \u00b6 IOCozyFile \u00b6 \u01ac IOCozyFile <>: IOCozyFile Defined in packages/cozy-client/src/models/paper.js:12 MetadataQualificationType \u00b6 \u01ac MetadataQualificationType <>: \"date\" | \"information\" | \"contact\" | \"other\" | \"bills\" Defined in packages/cozy-client/src/models/paper.js:276 Variables \u00b6 KNOWN_BILLS_ATTRIBUTES_NAMES \u00b6 \u2022 Const KNOWN_BILLS_ATTRIBUTES_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:51 KNOWN_DATE_METADATA_NAMES \u00b6 \u2022 Const KNOWN_DATE_METADATA_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:25 KNOWN_INFORMATION_METADATA_NAMES \u00b6 \u2022 Const KNOWN_INFORMATION_METADATA_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:38 KNOWN_OTHER_METADATA_NAMES \u00b6 \u2022 Const KNOWN_OTHER_METADATA_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:50 Functions \u00b6 computeExpirationDate \u00b6 \u25b8 computeExpirationDate ( file ): Date description Computes et returns the expiration date of the given file, or null if it is not expiring Parameters Name Type Description file IOCozyFile io.cozy.files document Returns Date Expiration date Defined in packages/cozy-client/src/models/paper.js:126 computeExpirationNoticeDate \u00b6 \u25b8 computeExpirationNoticeDate ( file ): Date description Computes et returns the expiration notice date of the given file, or null if it is not expiring Parameters Name Type Description file IOCozyFile io.cozy.files document Returns Date Expiration notice date Defined in packages/cozy-client/src/models/paper.js:162 computeExpirationNoticeLink \u00b6 \u25b8 computeExpirationNoticeLink ( file ): string description Computes and returns the expiration notice link of the given file, or null if it has none Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string Expiration notice link Defined in packages/cozy-client/src/models/paper.js:181 formatContactValue \u00b6 \u25b8 formatContactValue ( contacts ): string Parameters Name Type Description contacts any [] An array of contact Returns string Formatted and translated value of an array of contact Defined in packages/cozy-client/src/models/paper.js:448 formatDateMetadataValue \u00b6 \u25b8 formatDateMetadataValue ( value , options ): string Parameters Name Type Description value string The value of a metadata of type date options Object Options options.f Function Date formatting function options.lang string Lang requested for the translation Returns string Formatted and translated value for the metadata Defined in packages/cozy-client/src/models/paper.js:326 formatInformationMetadataValue \u00b6 \u25b8 formatInformationMetadataValue ( value , options ): string Parameters Name Type Description value string The value of a metadata of type information options Object Options options.lang string Lang requested for the translation options.name string The name of the metadata options.qualificationLabel string The qualification label of the metadata Returns string Formatted and translated value for the metadata Defined in packages/cozy-client/src/models/paper.js:369 formatMetadataQualification \u00b6 \u25b8 formatMetadataQualification ( metadata ): { name : string ; value : string }[] description Select and format displayable metadata of a paper Parameters Name Type Description metadata any An io.cozy.files metadata object Returns { name : string ; value : string }[] []} Array of displayable metadata Defined in packages/cozy-client/src/models/paper.js:245 formatOtherMetadataValue \u00b6 \u25b8 formatOtherMetadataValue ( value , options ): string Parameters Name Type Description value string The value of a metadata of type other options Object Options options.lang string Lang requested for the translation options.name string The name of the metadata Returns string Formatted and translated value for the metadata Defined in packages/cozy-client/src/models/paper.js:423 getMetadataQualificationType \u00b6 \u25b8 getMetadataQualificationType ( metadataName ): MetadataQualificationType description Returns the type of the metatada from a metadata name Parameters Name Type Description metadataName string A metadata name Returns MetadataQualificationType The type of the metadata Defined in packages/cozy-client/src/models/paper.js:284 getTranslatedNameForContact \u00b6 \u25b8 getTranslatedNameForContact ( options ): string Parameters Name Type Description options Object Options options.lang string Lang requested for the translation Returns string Translated name for contact Defined in packages/cozy-client/src/models/paper.js:438 getTranslatedNameForDateMetadata \u00b6 \u25b8 getTranslatedNameForDateMetadata ( name , options ): string Parameters Name Type Description name string The name of a metadata of type date like \u2018expirationDate\u2019 or \u2018shootingDate\u2019 options Object Options options.lang string Lang requested for the translation like \u2018fr\u2019 or \u2018en\u2019 Returns string Translated name for the metadata Defined in packages/cozy-client/src/models/paper.js:313 getTranslatedNameForInformationMetadata \u00b6 \u25b8 getTranslatedNameForInformationMetadata ( name , options ): string Parameters Name Type Description name string The name of a metadata of type information like \u2018national_id_card\u2019 or \u2018fine\u2019 options Object Options options.lang string Lang requested for the translation options.qualificationLabel string The qualification label of the metadata Returns string Translated name for the metadata Defined in packages/cozy-client/src/models/paper.js:346 getTranslatedNameForOtherMetadata \u00b6 \u25b8 getTranslatedNameForOtherMetadata ( name , options ): string Parameters Name Type Description name string The name of a metadata of type other like \u2018page\u2019 or \u2018qualification\u2019 options Object Options options.lang string Lang requested for the translation Returns string Translated name for the metadata Defined in packages/cozy-client/src/models/paper.js:410 isExpired \u00b6 \u25b8 isExpired ( file ): boolean description Tells if the given file is expiring and if today is after its expiration date Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/paper.js:193 isExpiring \u00b6 \u25b8 isExpiring ( file ): boolean description Tells if a given file matches one of the known types of expiring papers Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/paper.js:108 isExpiringSoon \u00b6 \u25b8 isExpiringSoon ( file ): boolean description Tells if the given file is expiring and if today is between its expiration notice date and its expiration date Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/paper.js:205 makeExpirationDescription \u00b6 \u25b8 makeExpirationDescription ( expirationDate , options ): string Parameters Name Type Description expirationDate string Expiration date options Object Options options.lang string Lang requested for the translation Returns string Defined in packages/cozy-client/src/models/paper.js:487 makeExpiredMessage \u00b6 \u25b8 makeExpiredMessage ( options ): string Parameters Name Type Description options Object Options options.lang string Lang requested for the translation Returns string Defined in packages/cozy-client/src/models/paper.js:459 makeExpiresInMessage \u00b6 \u25b8 makeExpiresInMessage ( expirationDate , options ): string Parameters Name Type Description expirationDate string Expiration date options Object Options options.lang string Lang requested for the translation Returns string Defined in packages/cozy-client/src/models/paper.js:471", "title": "Models.paper"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#namespace-paper", "text": "models .paper", "title": "Namespace: paper"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#type-aliases", "text": "", "title": "Type aliases"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#iocozyfile", "text": "\u01ac IOCozyFile <>: IOCozyFile Defined in packages/cozy-client/src/models/paper.js:12", "title": "IOCozyFile"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#metadataqualificationtype", "text": "\u01ac MetadataQualificationType <>: \"date\" | \"information\" | \"contact\" | \"other\" | \"bills\" Defined in packages/cozy-client/src/models/paper.js:276", "title": "MetadataQualificationType"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#known_bills_attributes_names", "text": "\u2022 Const KNOWN_BILLS_ATTRIBUTES_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:51", "title": "KNOWN_BILLS_ATTRIBUTES_NAMES"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#known_date_metadata_names", "text": "\u2022 Const KNOWN_DATE_METADATA_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:25", "title": "KNOWN_DATE_METADATA_NAMES"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#known_information_metadata_names", "text": "\u2022 Const KNOWN_INFORMATION_METADATA_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:38", "title": "KNOWN_INFORMATION_METADATA_NAMES"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#known_other_metadata_names", "text": "\u2022 Const KNOWN_OTHER_METADATA_NAMES : string [] Defined in packages/cozy-client/src/models/paper.js:50", "title": "KNOWN_OTHER_METADATA_NAMES"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#computeexpirationdate", "text": "\u25b8 computeExpirationDate ( file ): Date description Computes et returns the expiration date of the given file, or null if it is not expiring Parameters Name Type Description file IOCozyFile io.cozy.files document Returns Date Expiration date Defined in packages/cozy-client/src/models/paper.js:126", "title": "computeExpirationDate"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#computeexpirationnoticedate", "text": "\u25b8 computeExpirationNoticeDate ( file ): Date description Computes et returns the expiration notice date of the given file, or null if it is not expiring Parameters Name Type Description file IOCozyFile io.cozy.files document Returns Date Expiration notice date Defined in packages/cozy-client/src/models/paper.js:162", "title": "computeExpirationNoticeDate"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#computeexpirationnoticelink", "text": "\u25b8 computeExpirationNoticeLink ( file ): string description Computes and returns the expiration notice link of the given file, or null if it has none Parameters Name Type Description file IOCozyFile io.cozy.files document Returns string Expiration notice link Defined in packages/cozy-client/src/models/paper.js:181", "title": "computeExpirationNoticeLink"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#formatcontactvalue", "text": "\u25b8 formatContactValue ( contacts ): string Parameters Name Type Description contacts any [] An array of contact Returns string Formatted and translated value of an array of contact Defined in packages/cozy-client/src/models/paper.js:448", "title": "formatContactValue"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#formatdatemetadatavalue", "text": "\u25b8 formatDateMetadataValue ( value , options ): string Parameters Name Type Description value string The value of a metadata of type date options Object Options options.f Function Date formatting function options.lang string Lang requested for the translation Returns string Formatted and translated value for the metadata Defined in packages/cozy-client/src/models/paper.js:326", "title": "formatDateMetadataValue"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#formatinformationmetadatavalue", "text": "\u25b8 formatInformationMetadataValue ( value , options ): string Parameters Name Type Description value string The value of a metadata of type information options Object Options options.lang string Lang requested for the translation options.name string The name of the metadata options.qualificationLabel string The qualification label of the metadata Returns string Formatted and translated value for the metadata Defined in packages/cozy-client/src/models/paper.js:369", "title": "formatInformationMetadataValue"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#formatmetadataqualification", "text": "\u25b8 formatMetadataQualification ( metadata ): { name : string ; value : string }[] description Select and format displayable metadata of a paper Parameters Name Type Description metadata any An io.cozy.files metadata object Returns { name : string ; value : string }[] []} Array of displayable metadata Defined in packages/cozy-client/src/models/paper.js:245", "title": "formatMetadataQualification"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#formatothermetadatavalue", "text": "\u25b8 formatOtherMetadataValue ( value , options ): string Parameters Name Type Description value string The value of a metadata of type other options Object Options options.lang string Lang requested for the translation options.name string The name of the metadata Returns string Formatted and translated value for the metadata Defined in packages/cozy-client/src/models/paper.js:423", "title": "formatOtherMetadataValue"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#getmetadataqualificationtype", "text": "\u25b8 getMetadataQualificationType ( metadataName ): MetadataQualificationType description Returns the type of the metatada from a metadata name Parameters Name Type Description metadataName string A metadata name Returns MetadataQualificationType The type of the metadata Defined in packages/cozy-client/src/models/paper.js:284", "title": "getMetadataQualificationType"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#gettranslatednameforcontact", "text": "\u25b8 getTranslatedNameForContact ( options ): string Parameters Name Type Description options Object Options options.lang string Lang requested for the translation Returns string Translated name for contact Defined in packages/cozy-client/src/models/paper.js:438", "title": "getTranslatedNameForContact"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#gettranslatednamefordatemetadata", "text": "\u25b8 getTranslatedNameForDateMetadata ( name , options ): string Parameters Name Type Description name string The name of a metadata of type date like \u2018expirationDate\u2019 or \u2018shootingDate\u2019 options Object Options options.lang string Lang requested for the translation like \u2018fr\u2019 or \u2018en\u2019 Returns string Translated name for the metadata Defined in packages/cozy-client/src/models/paper.js:313", "title": "getTranslatedNameForDateMetadata"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#gettranslatednameforinformationmetadata", "text": "\u25b8 getTranslatedNameForInformationMetadata ( name , options ): string Parameters Name Type Description name string The name of a metadata of type information like \u2018national_id_card\u2019 or \u2018fine\u2019 options Object Options options.lang string Lang requested for the translation options.qualificationLabel string The qualification label of the metadata Returns string Translated name for the metadata Defined in packages/cozy-client/src/models/paper.js:346", "title": "getTranslatedNameForInformationMetadata"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#gettranslatednameforothermetadata", "text": "\u25b8 getTranslatedNameForOtherMetadata ( name , options ): string Parameters Name Type Description name string The name of a metadata of type other like \u2018page\u2019 or \u2018qualification\u2019 options Object Options options.lang string Lang requested for the translation Returns string Translated name for the metadata Defined in packages/cozy-client/src/models/paper.js:410", "title": "getTranslatedNameForOtherMetadata"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#isexpired", "text": "\u25b8 isExpired ( file ): boolean description Tells if the given file is expiring and if today is after its expiration date Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/paper.js:193", "title": "isExpired"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#isexpiring", "text": "\u25b8 isExpiring ( file ): boolean description Tells if a given file matches one of the known types of expiring papers Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/paper.js:108", "title": "isExpiring"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#isexpiringsoon", "text": "\u25b8 isExpiringSoon ( file ): boolean description Tells if the given file is expiring and if today is between its expiration notice date and its expiration date Parameters Name Type Description file IOCozyFile io.cozy.files document Returns boolean Defined in packages/cozy-client/src/models/paper.js:205", "title": "isExpiringSoon"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#makeexpirationdescription", "text": "\u25b8 makeExpirationDescription ( expirationDate , options ): string Parameters Name Type Description expirationDate string Expiration date options Object Options options.lang string Lang requested for the translation Returns string Defined in packages/cozy-client/src/models/paper.js:487", "title": "makeExpirationDescription"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#makeexpiredmessage", "text": "\u25b8 makeExpiredMessage ( options ): string Parameters Name Type Description options Object Options options.lang string Lang requested for the translation Returns string Defined in packages/cozy-client/src/models/paper.js:459", "title": "makeExpiredMessage"}, {"location": "cozy-client/api/cozy-client/modules/models.paper/#makeexpiresinmessage", "text": "\u25b8 makeExpiresInMessage ( expirationDate , options ): string Parameters Name Type Description expirationDate string Expiration date options Object Options options.lang string Lang requested for the translation Returns string Defined in packages/cozy-client/src/models/paper.js:471", "title": "makeExpiresInMessage"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/", "text": "cozy-client / models / permission Namespace: permission \u00b6 models .permission Interfaces \u00b6 Document Permission PermissionItem Type aliases \u00b6 PermissionVerb \u00b6 \u01ac PermissionVerb <>: \"ALL\" | \"GET\" | \"PATCH\" | \"POST\" | \"PUT\" | \"DELETE\" Defined in packages/cozy-client/src/models/permission.js:18 Functions \u00b6 fetchOwn \u00b6 \u25b8 fetchOwn ( client ): Promise < PermissionItem []> Fetches the list of permissions blocks Parameters Name Type Description client CozyClient - Returns Promise < PermissionItem []> list of permissions Defined in packages/cozy-client/src/models/permission.js:53 isDocumentReadOnly \u00b6 \u25b8 isDocumentReadOnly ( args ): Promise < boolean > Parameters Name Type args any Returns Promise < boolean > Defined in packages/cozy-client/src/models/permission.js:129 isForType \u00b6 \u25b8 isForType ( permission , type ): boolean Checks if the permission item is about a specific doctype Parameters Name Type Description permission PermissionItem - type string doctype Returns boolean Defined in packages/cozy-client/src/models/permission.js:67 isShortcutCreatedOnTheRecipientCozy \u00b6 \u25b8 isShortcutCreatedOnTheRecipientCozy ( permission ): boolean When a cozy to cozy sharing is created Cozy\u2019s stack creates a shortcut in /Inbox of sharing on the recipient\u2019s cozy to have a quick access even when the sharing is not accepted yet. However, this file is created only if the stack knows the URL of the cozy. This is not always the case. This method is here to tell us if the shortcut\u2019s file is created on the recipient\u2019s cozy. It can be used to make an UI distinction between the both situation. property {object} data Permission document property {Array} included Member information from the sharing Parameters Name Type Description permission Permission From getOwnPermissions mainly Returns boolean Defined in packages/cozy-client/src/models/permission.js:167", "title": "Models.permission"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#namespace-permission", "text": "models .permission", "title": "Namespace: permission"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#interfaces", "text": "Document Permission PermissionItem", "title": "Interfaces"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#type-aliases", "text": "", "title": "Type aliases"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#permissionverb", "text": "\u01ac PermissionVerb <>: \"ALL\" | \"GET\" | \"PATCH\" | \"POST\" | \"PUT\" | \"DELETE\" Defined in packages/cozy-client/src/models/permission.js:18", "title": "PermissionVerb"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#fetchown", "text": "\u25b8 fetchOwn ( client ): Promise < PermissionItem []> Fetches the list of permissions blocks Parameters Name Type Description client CozyClient - Returns Promise < PermissionItem []> list of permissions Defined in packages/cozy-client/src/models/permission.js:53", "title": "fetchOwn"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#isdocumentreadonly", "text": "\u25b8 isDocumentReadOnly ( args ): Promise < boolean > Parameters Name Type args any Returns Promise < boolean > Defined in packages/cozy-client/src/models/permission.js:129", "title": "isDocumentReadOnly"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#isfortype", "text": "\u25b8 isForType ( permission , type ): boolean Checks if the permission item is about a specific doctype Parameters Name Type Description permission PermissionItem - type string doctype Returns boolean Defined in packages/cozy-client/src/models/permission.js:67", "title": "isForType"}, {"location": "cozy-client/api/cozy-client/modules/models.permission/#isshortcutcreatedontherecipientcozy", "text": "\u25b8 isShortcutCreatedOnTheRecipientCozy ( permission ): boolean When a cozy to cozy sharing is created Cozy\u2019s stack creates a shortcut in /Inbox of sharing on the recipient\u2019s cozy to have a quick access even when the sharing is not accepted yet. However, this file is created only if the stack knows the URL of the cozy. This is not always the case. This method is here to tell us if the shortcut\u2019s file is created on the recipient\u2019s cozy. It can be used to make an UI distinction between the both situation. property {object} data Permission document property {Array} included Member information from the sharing Parameters Name Type Description permission Permission From getOwnPermissions mainly Returns boolean Defined in packages/cozy-client/src/models/permission.js:167", "title": "isShortcutCreatedOnTheRecipientCozy"}, {"location": "cozy-client/api/cozy-client/modules/models.sharing/", "text": "cozy-client / models / sharing Namespace: sharing \u00b6 models .sharing Functions \u00b6 getSharingLink \u00b6 \u25b8 getSharingLink ( client , filesIds , options? ): Promise < string > Generate Sharing link for one or many files Parameters Name Type Description client CozyClient Instance of CozyClient filesIds string [] Array of io.cozy.files ids options Object Options options.password string - options.ttl string - Returns Promise < string > Shared link Defined in packages/cozy-client/src/models/sharing.js:15", "title": "Models.sharing"}, {"location": "cozy-client/api/cozy-client/modules/models.sharing/#namespace-sharing", "text": "models .sharing", "title": "Namespace: sharing"}, {"location": "cozy-client/api/cozy-client/modules/models.sharing/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.sharing/#getsharinglink", "text": "\u25b8 getSharingLink ( client , filesIds , options? ): Promise < string > Generate Sharing link for one or many files Parameters Name Type Description client CozyClient Instance of CozyClient filesIds string [] Array of io.cozy.files ids options Object Options options.password string - options.ttl string - Returns Promise < string > Shared link Defined in packages/cozy-client/src/models/sharing.js:15", "title": "getSharingLink"}, {"location": "cozy-client/api/cozy-client/modules/models.timeseries/", "text": "cozy-client / models / timeseries Namespace: timeseries \u00b6 models .timeseries Interfaces \u00b6 TimeSeries TimeSeriesJSONAPI Functions \u00b6 fetchTimeSeriesByIntervalAndSource \u00b6 \u25b8 fetchTimeSeriesByIntervalAndSource ( client , params ): Promise < TimeSeriesJSONAPI > Helper to retrieve time series by their date interval and source. property data {Array } - The JSON-API data response Parameters Name Type Description client any The CozyClient instance params Object The query params params.dataType string The type of time series, e.g. \u2018electricity\u2019 params.endDate Date The end date of the series params.limit number Number of serie items to retrieve params.source string The data source, e.g. \u2018enedis.fr\u2019 params.startDate Date The starting date of the series Returns Promise < TimeSeriesJSONAPI > The TimeSeries found by the query in JSON-API format Defined in packages/cozy-client/src/models/timeseries.js:77 saveTimeSeries \u00b6 \u25b8 saveTimeSeries ( client , timeseriesOption ): Promise < any > Helper to save a time series document. Parameters Name Type Description client any The CozyClient instance timeseriesOption TimeSeries The time series to save Returns Promise < any > Defined in packages/cozy-client/src/models/timeseries.js:39", "title": "Models.timeseries"}, {"location": "cozy-client/api/cozy-client/modules/models.timeseries/#namespace-timeseries", "text": "models .timeseries", "title": "Namespace: timeseries"}, {"location": "cozy-client/api/cozy-client/modules/models.timeseries/#interfaces", "text": "TimeSeries TimeSeriesJSONAPI", "title": "Interfaces"}, {"location": "cozy-client/api/cozy-client/modules/models.timeseries/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.timeseries/#fetchtimeseriesbyintervalandsource", "text": "\u25b8 fetchTimeSeriesByIntervalAndSource ( client , params ): Promise < TimeSeriesJSONAPI > Helper to retrieve time series by their date interval and source. property data {Array } - The JSON-API data response Parameters Name Type Description client any The CozyClient instance params Object The query params params.dataType string The type of time series, e.g. \u2018electricity\u2019 params.endDate Date The end date of the series params.limit number Number of serie items to retrieve params.source string The data source, e.g. \u2018enedis.fr\u2019 params.startDate Date The starting date of the series Returns Promise < TimeSeriesJSONAPI > The TimeSeries found by the query in JSON-API format Defined in packages/cozy-client/src/models/timeseries.js:77", "title": "fetchTimeSeriesByIntervalAndSource"}, {"location": "cozy-client/api/cozy-client/modules/models.timeseries/#savetimeseries", "text": "\u25b8 saveTimeSeries ( client , timeseriesOption ): Promise < any > Helper to save a time series document. Parameters Name Type Description client any The CozyClient instance timeseriesOption TimeSeries The time series to save Returns Promise < any > Defined in packages/cozy-client/src/models/timeseries.js:39", "title": "saveTimeSeries"}, {"location": "cozy-client/api/cozy-client/modules/models.trigger/", "text": "cozy-client / models / trigger Namespace: trigger \u00b6 models .trigger Variables \u00b6 triggerStates \u00b6 \u2022 Const triggerStates : Object Trigger states come from /jobs/triggers Type declaration Name Type getLastErrorType ( trigger : IOCozyTrigger ) => string getLastExecution ( trigger : IOCozyTrigger ) => string getLastSuccess ( trigger : IOCozyTrigger ) => string getLastsuccess ( trigger : IOCozyTrigger ) => string isErrored ( trigger : IOCozyTrigger ) => boolean Defined in packages/cozy-client/src/models/trigger.js:17 triggers \u00b6 \u2022 Const triggers : Object Type declaration Name Type buildTriggerAttributes ( options : { account : IOCozyAccount ; cron : string ; folder : any ; konnector : IOCozyKonnector }) => IOCozyTrigger getAccountId ( trigger : IOCozyTrigger ) => string getKonnector ( trigger : IOCozyTrigger ) => string hasActionableError ( trigger : IOCozyTrigger ) => boolean isKonnector ( trigger : any ) => boolean isKonnectorWorker ( trigger : IOCozyTrigger ) => boolean isLatestErrorMuted ( trigger : IOCozyTrigger , account : IOCozyAccount ) => boolean Defined in packages/cozy-client/src/models/trigger.js:66", "title": "Models.trigger"}, {"location": "cozy-client/api/cozy-client/modules/models.trigger/#namespace-trigger", "text": "models .trigger", "title": "Namespace: trigger"}, {"location": "cozy-client/api/cozy-client/modules/models.trigger/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/models.trigger/#triggerstates", "text": "\u2022 Const triggerStates : Object Trigger states come from /jobs/triggers Type declaration Name Type getLastErrorType ( trigger : IOCozyTrigger ) => string getLastExecution ( trigger : IOCozyTrigger ) => string getLastSuccess ( trigger : IOCozyTrigger ) => string getLastsuccess ( trigger : IOCozyTrigger ) => string isErrored ( trigger : IOCozyTrigger ) => boolean Defined in packages/cozy-client/src/models/trigger.js:17", "title": "triggerStates"}, {"location": "cozy-client/api/cozy-client/modules/models.trigger/#triggers", "text": "\u2022 Const triggers : Object Type declaration Name Type buildTriggerAttributes ( options : { account : IOCozyAccount ; cron : string ; folder : any ; konnector : IOCozyKonnector }) => IOCozyTrigger getAccountId ( trigger : IOCozyTrigger ) => string getKonnector ( trigger : IOCozyTrigger ) => string hasActionableError ( trigger : IOCozyTrigger ) => boolean isKonnector ( trigger : any ) => boolean isKonnectorWorker ( trigger : IOCozyTrigger ) => boolean isLatestErrorMuted ( trigger : IOCozyTrigger , account : IOCozyAccount ) => boolean Defined in packages/cozy-client/src/models/trigger.js:66", "title": "triggers"}, {"location": "cozy-client/api/cozy-client/modules/models.user/", "text": "cozy-client / models / user Namespace: user \u00b6 models .user Functions \u00b6 hasPassword \u00b6 \u25b8 hasPassword ( client ): Promise < boolean > Checks whether the user has a password Parameters Name Type Description client CozyClient The CozyClient instance Returns Promise < boolean > Returns true if the user has a password Defined in packages/cozy-client/src/models/user.js:11", "title": "Models.user"}, {"location": "cozy-client/api/cozy-client/modules/models.user/#namespace-user", "text": "models .user", "title": "Namespace: user"}, {"location": "cozy-client/api/cozy-client/modules/models.user/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.user/#haspassword", "text": "\u25b8 hasPassword ( client ): Promise < boolean > Checks whether the user has a password Parameters Name Type Description client CozyClient The CozyClient instance Returns Promise < boolean > Returns true if the user has a password Defined in packages/cozy-client/src/models/user.js:11", "title": "hasPassword"}, {"location": "cozy-client/api/cozy-client/modules/models.utils/", "text": "cozy-client / models / utils Namespace: utils \u00b6 models .utils Functions \u00b6 getCreatedByApp \u00b6 \u25b8 getCreatedByApp ( doc ): string Gets the app that created a document Parameters Name Type Description doc any The document to check Returns string The slug of the app that created the document Defined in packages/cozy-client/src/models/utils.js:23 getFlagshipDownloadLink \u00b6 \u25b8 getFlagshipDownloadLink ( lang ): string Gets the download link for the Cozy Flagship app and his white-labels versions Parameters Name Type Description lang string The language code for the download page Returns string The URL of the download page Defined in packages/cozy-client/src/models/utils.js:31 hasBeenUpdatedByApp \u00b6 \u25b8 hasBeenUpdatedByApp ( doc , appSlug ): boolean Checks if a document has been updated by a specific app Parameters Name Type Description doc any The document to check appSlug string The slug of the app to check Returns boolean True if the document has been updated by the app, false otherwise Defined in packages/cozy-client/src/models/utils.js:12", "title": "Models.utils"}, {"location": "cozy-client/api/cozy-client/modules/models.utils/#namespace-utils", "text": "models .utils", "title": "Namespace: utils"}, {"location": "cozy-client/api/cozy-client/modules/models.utils/#functions", "text": "", "title": "Functions"}, {"location": "cozy-client/api/cozy-client/modules/models.utils/#getcreatedbyapp", "text": "\u25b8 getCreatedByApp ( doc ): string Gets the app that created a document Parameters Name Type Description doc any The document to check Returns string The slug of the app that created the document Defined in packages/cozy-client/src/models/utils.js:23", "title": "getCreatedByApp"}, {"location": "cozy-client/api/cozy-client/modules/models.utils/#getflagshipdownloadlink", "text": "\u25b8 getFlagshipDownloadLink ( lang ): string Gets the download link for the Cozy Flagship app and his white-labels versions Parameters Name Type Description lang string The language code for the download page Returns string The URL of the download page Defined in packages/cozy-client/src/models/utils.js:31", "title": "getFlagshipDownloadLink"}, {"location": "cozy-client/api/cozy-client/modules/models.utils/#hasbeenupdatedbyapp", "text": "\u25b8 hasBeenUpdatedByApp ( doc , appSlug ): boolean Checks if a document has been updated by a specific app Parameters Name Type Description doc any The document to check appSlug string The slug of the app to check Returns boolean True if the document has been updated by the app, false otherwise Defined in packages/cozy-client/src/models/utils.js:12", "title": "hasBeenUpdatedByApp"}, {"location": "cozy-client/api/cozy-client/modules/useMutation/", "text": "cozy-client / useMutation Namespace: useMutation \u00b6 Variables \u00b6 propTypes \u00b6 \u2022 propTypes : Object Type declaration Name Type onError Requireable <(\u2026 args : any []) => any > onSuccess Requireable <(\u2026 args : any []) => any >", "title": "useMutation"}, {"location": "cozy-client/api/cozy-client/modules/useMutation/#namespace-usemutation", "text": "", "title": "Namespace: useMutation"}, {"location": "cozy-client/api/cozy-client/modules/useMutation/#variables", "text": "", "title": "Variables"}, {"location": "cozy-client/api/cozy-client/modules/useMutation/#proptypes", "text": "\u2022 propTypes : Object Type declaration Name Type onError Requireable <(\u2026 args : any []) => any > onSuccess Requireable <(\u2026 args : any []) => any >", "title": "propTypes"}, {"location": "cozy-desktop/", "text": "Usage \u00b6 Build CLI Filesystems Ignore files\u201d inotify Limitations Linux MacOS Windows Developer \u00b6 API Documentation Cofeescript Debug Log analysis Requirements Setup Test Other \u00b6 Feddback", "title": "README"}, {"location": "cozy-desktop/#usage", "text": "Build CLI Filesystems Ignore files\u201d inotify Limitations Linux MacOS Windows", "title": "Usage"}, {"location": "cozy-desktop/#developer", "text": "API Documentation Cofeescript Debug Log analysis Requirements Setup Test", "title": "Developer"}, {"location": "cozy-desktop/#other", "text": "Feddback", "title": "Other"}, {"location": "cozy-desktop/feedback/", "text": "Feedback \u00b6 You can: \ud83d\uddea Discuss on the Forum \ud83d\udc1b Report issues and request features on the Github repository Synchronization problems are better reported by the help form included in the application (so logs are automatically attached to the request). \ud83d\uddea Chat with us on the IRC channel #cozycloud on Libera.Chat \ud83d\udc26 Mention us on Twitter The current maintainers of Cozy Drive for Desktop are @cozy-labs/cozy-drive-for-desktop, feel free to say hello!", "title": "Feddback"}, {"location": "cozy-desktop/feedback/#feedback", "text": "You can: \ud83d\uddea Discuss on the Forum \ud83d\udc1b Report issues and request features on the Github repository Synchronization problems are better reported by the help form included in the application (so logs are automatically attached to the request). \ud83d\uddea Chat with us on the IRC channel #cozycloud on Libera.Chat \ud83d\udc26 Mention us on Twitter The current maintainers of Cozy Drive for Desktop are @cozy-labs/cozy-drive-for-desktop, feel free to say hello!", "title": "Feedback"}, {"location": "cozy-desktop/developer/api_doc/", "text": "API Documentation \u00b6 Build \u00b6 To build the API documentation locally: yarn jsdoc To browse the generated documentation: xdg-open ./doc/api/index.html || open ./doc/api/index.html To rebuild automatically as you edit the source comments: yarn jsdoc:watch Publish \u00b6 To publish the API documentation at https://cozy-labs.github.io/cozy-desktop/doc/api/ : git checkout gh-pages git fetch git reset --hard origin/master yarn jsdoc git add -f doc/api/ git commit -m build git push -f", "title": "API Documentation"}, {"location": "cozy-desktop/developer/api_doc/#api-documentation", "text": "", "title": "API Documentation"}, {"location": "cozy-desktop/developer/api_doc/#build", "text": "To build the API documentation locally: yarn jsdoc To browse the generated documentation: xdg-open ./doc/api/index.html || open ./doc/api/index.html To rebuild automatically as you edit the source comments: yarn jsdoc:watch", "title": "Build"}, {"location": "cozy-desktop/developer/api_doc/#publish", "text": "To publish the API documentation at https://cozy-labs.github.io/cozy-desktop/doc/api/ : git checkout gh-pages git fetch git reset --hard origin/master yarn jsdoc git add -f doc/api/ git commit -m build git push -f", "title": "Publish"}, {"location": "cozy-desktop/developer/coffeescript/", "text": "CoffeeScript to EcmaScript Conversion \u00b6 The cozy-desktop lib and CLI were historically written in CoffeeScript , like many Cozy apps. CoffeeScript used to provide many benefits over EcmaScript, but that\u2019s not true anymore: EcmaScript has catched up regarding language features it is the standard: it won\u2019t die soon more people can read/write ES code than CoffeeScript ES provides us with more options (there are far more ES libs/tools than Coffee ones out there) ES tooling is becoming better ( Eslint spots far more issues in our codebase than Coffeelint , and tools like Flow bring static type checking to ES) As many Cozy apps were rewritten in EcmaScript, going the same way would makes the platform more consistent This is why the code was converted from CoffeeScript to EcmaScript . Part of this was done automatically using decaffeinate . But some conversion issues were also fixed afterwards. Build and tools also moved to the new language stack. The list of changes can be seen in the corresponding GitHub pull request . Because of lack of time, some minor issues still remain in the ES code, like a few useless return statements for example. Those will be adressed progressively while working on new features or enhancements. But help is still welcome", "title": "Cofeescript"}, {"location": "cozy-desktop/developer/coffeescript/#coffeescript-to-ecmascript-conversion", "text": "The cozy-desktop lib and CLI were historically written in CoffeeScript , like many Cozy apps. CoffeeScript used to provide many benefits over EcmaScript, but that\u2019s not true anymore: EcmaScript has catched up regarding language features it is the standard: it won\u2019t die soon more people can read/write ES code than CoffeeScript ES provides us with more options (there are far more ES libs/tools than Coffee ones out there) ES tooling is becoming better ( Eslint spots far more issues in our codebase than Coffeelint , and tools like Flow bring static type checking to ES) As many Cozy apps were rewritten in EcmaScript, going the same way would makes the platform more consistent This is why the code was converted from CoffeeScript to EcmaScript . Part of this was done automatically using decaffeinate . But some conversion issues were also fixed afterwards. Build and tools also moved to the new language stack. The list of changes can be seen in the corresponding GitHub pull request . Because of lack of time, some minor issues still remain in the ES code, like a few useless return statements for example. Those will be adressed progressively while working on new features or enhancements. But help is still welcome", "title": "CoffeeScript to EcmaScript Conversion"}, {"location": "cozy-desktop/developer/debug/", "text": "Tools for debugging \u00b6 Bugs can happen. Cozy-desktop has some tools to track them. Debug logs \u00b6 The first and most important one is logging. If you think you might have found a bug, the first thing to do is running cozy-desktop with debug: DEBUG = true yarn start To both keep logs on a file and display them on screen, you can use tee : DEBUG = true yarn start 2 > & 1 | tee $( date '+%Y-%m-%d.log' ) It\u2019s possible to have even more logs if you want, by enabling pouchdb debug logs and request debug logs: NODE_DEBUG = request DEBUG = pouchdb:* yarn start When cozy-desktop is running, it\u2019s possible to send it the USR1 signal to make it list the paths watched by chokidar: kill -USR1 ", "title": "Debug"}, {"location": "cozy-desktop/developer/debug/#tools-for-debugging", "text": "Bugs can happen. Cozy-desktop has some tools to track them.", "title": "Tools for debugging"}, {"location": "cozy-desktop/developer/debug/#debug-logs", "text": "The first and most important one is logging. If you think you might have found a bug, the first thing to do is running cozy-desktop with debug: DEBUG = true yarn start To both keep logs on a file and display them on screen, you can use tee : DEBUG = true yarn start 2 > & 1 | tee $( date '+%Y-%m-%d.log' ) It\u2019s possible to have even more logs if you want, by enabling pouchdb debug logs and request debug logs: NODE_DEBUG = request DEBUG = pouchdb:* yarn start When cozy-desktop is running, it\u2019s possible to send it the USR1 signal to make it list the paths watched by chokidar: kill -USR1 ", "title": "Debug logs"}, {"location": "cozy-desktop/developer/log_analysis/", "text": "Log analysis \u00b6 Debugging synchronization issues mostly means analysing logs. Logs are in JSON lines format, generated by bunyan, and can be quite huge (this is a known issue). We use jq to filter them. See jq manual to get all the basic and advanced filters. A yarn jq script is also available which automatically includes a bunch of custom ones: yarn jq 'some|filter' path/to/logs The script doesn\u2019t use --slurp so JSON lines are filtered one by one and memory usage is kept below 100MB. Which means you can filter multiple log files at once, even huge ones: yarn jq 'some|filter' path/to/logs* Start with the issues filter to find out main issues: yarn jq issues path/to/logs* Shorten the output with jq \u2018s -c option and the short filter so you get a better overview: yarn jq -c 'issues|short' path/to/logs* You can combine even more filters to focus on some kind of events: yarn jq -c 'issues|no_gui|xls|short' path/to/logs* Then you can check what happened at some file path: yarn jq -c 'path(foo/bar)|short' path/to/logs* Please note that since the path filter takes a regular expression pattern, you\u2019ll have to double-escape backslashes in Windows paths: yarn jq 'path(\"foo\\\\\\\\bar\")' path/to/logs* Then get more details (e.g. dropping -c option and short filter): yarn jq 'select(...)' path/to/logs* To get an error stack trace as you would expect, you can use jq \u2018s -r (raw) option on the .stack property: yarn jq -r 'select(.time == \"2018-06-21T13:57:40.699Z\")|.err|.stack' path/to/logs See the .jq file at the root of the repository to get the complete list of custom filters.", "title": "Log analysis"}, {"location": "cozy-desktop/developer/log_analysis/#log-analysis", "text": "Debugging synchronization issues mostly means analysing logs. Logs are in JSON lines format, generated by bunyan, and can be quite huge (this is a known issue). We use jq to filter them. See jq manual to get all the basic and advanced filters. A yarn jq script is also available which automatically includes a bunch of custom ones: yarn jq 'some|filter' path/to/logs The script doesn\u2019t use --slurp so JSON lines are filtered one by one and memory usage is kept below 100MB. Which means you can filter multiple log files at once, even huge ones: yarn jq 'some|filter' path/to/logs* Start with the issues filter to find out main issues: yarn jq issues path/to/logs* Shorten the output with jq \u2018s -c option and the short filter so you get a better overview: yarn jq -c 'issues|short' path/to/logs* You can combine even more filters to focus on some kind of events: yarn jq -c 'issues|no_gui|xls|short' path/to/logs* Then you can check what happened at some file path: yarn jq -c 'path(foo/bar)|short' path/to/logs* Please note that since the path filter takes a regular expression pattern, you\u2019ll have to double-escape backslashes in Windows paths: yarn jq 'path(\"foo\\\\\\\\bar\")' path/to/logs* Then get more details (e.g. dropping -c option and short filter): yarn jq 'select(...)' path/to/logs* To get an error stack trace as you would expect, you can use jq \u2018s -r (raw) option on the .stack property: yarn jq -r 'select(.time == \"2018-06-21T13:57:40.699Z\")|.err|.stack' path/to/logs See the .jq file at the root of the repository to get the complete list of custom filters.", "title": "Log analysis"}, {"location": "cozy-desktop/developer/requirements/", "text": "Requirements \u00b6 Build \u00b6 Git Node.js Yarn Development \u00b6 Cozy Stack in Docker Windows \u00b6 If you don\u2019t own a Windows license but you still need to build / test the app on Windows, you can use the free virtual machines provided by Microsoft, either in VirtualBox or any of the hypervisors supporting the available VM file formats. The following assumes you run commands from an administrator command prompt To get an administrator prompt, look for Command Prompt in the start menu, right-click on it and select Run as administrator . FIXME: Document scoop instead of choco (it works far better). Once you are in a running Windows session, you can eventually install Chocolatey from an administrator prompt, then use it to install the requirements above (or you can download and install each of the installers): choco install git choco install nodejs-lts choco install yarn Right now the nodejs-lts package seems to be broken, you may need to install the latest Node 6.x by hand. You may also need at some point to restart the Command Prompt , the whole system, or refresh your environment variables using the refreshenv command. Then install the Windows build tools from an admin console as documented in the Microsoft\u2019s Node.js guidelines : npm install -g windows-build-tools You may still need to manually add the python installation directory to your PATH . To do so, search for PATH from the start menu and select Edit environment variables for your account . Then edit the PATH user variable (not the system one) and append the following to the end (assuming ... is the current text): `...;%USERPROFILE%\\.windows-build-tools\\python27` To set up Docker, in case you hardware is old or you don\u2019t own a Windows Pro license, you may encounter the same issue as on old macOS hardware (see below). (please feel free to improve this section) macOS \u00b6 You need a Mac to build / test for macOS. The easiest way to set up the environment is to install and use Homebrew : brew install git brew install node @8 brew install yarn To install Docker, first check that your mac has kernel hypervisor support: sysctl -n kern.hv_support If the output is 1 , then you can install the latest Docker version: brew cask install docker Otherwise you\u2019ll have to install a Docker VM and set up your shell environment so the various docker commands know how to use it (you can omit the default parameters below): brew cask install docker-toolbox docker-machine create default eval $(docker-machine env default) Fedora 28 \u00b6 sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo sudo dnf install docker gcc-c++ git nodejs yarn transifex-client python3-pip sudo pip install docker-compose sudo groupadd docker sudo usermod -aG docker $USER # Restart your session so this takes effect Ubuntu \u00b6 curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo \"deb https://dl.yarnpkg.com/debian/ stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository \\ \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" sudo apt update sudo apt install git nodejs build-essential gcc transifex-client icnsutils graphicsmagick python3-pip docker-ce yarn sudo pip install docker-compose sudo groupadd docker sudo usermod -aG docker $USER # Restart your session so this takes effect Set up a Cozy stack \u00b6 If you don\u2019t already have a running Cozy stack , the easiest way to get started is to use Docker & docker-compose : docker-compose up yarn bootstrap Cozy Stack \u00b6 You can run any command in the cozy-stack docker container with the yarn docker:exec script, e.g.: yarn docker:exec apt-get update yarn docker:exec apt-get install git # So we can install cozy apps You can also run any cozy-stack command with the yarn cozy-stack script, e.g.: yarn cozy-stack apps install --domain cozy.localhost:8080 drive 'git://github.com/cozy/cozy-drive.git#build-drive' Complete your setup \u00b6 See ./setup.md", "title": "Requirements"}, {"location": "cozy-desktop/developer/requirements/#requirements", "text": "", "title": "Requirements"}, {"location": "cozy-desktop/developer/requirements/#build", "text": "Git Node.js Yarn", "title": "Build"}, {"location": "cozy-desktop/developer/requirements/#development", "text": "Cozy Stack in Docker", "title": "Development"}, {"location": "cozy-desktop/developer/requirements/#windows", "text": "If you don\u2019t own a Windows license but you still need to build / test the app on Windows, you can use the free virtual machines provided by Microsoft, either in VirtualBox or any of the hypervisors supporting the available VM file formats. The following assumes you run commands from an administrator command prompt To get an administrator prompt, look for Command Prompt in the start menu, right-click on it and select Run as administrator . FIXME: Document scoop instead of choco (it works far better). Once you are in a running Windows session, you can eventually install Chocolatey from an administrator prompt, then use it to install the requirements above (or you can download and install each of the installers): choco install git choco install nodejs-lts choco install yarn Right now the nodejs-lts package seems to be broken, you may need to install the latest Node 6.x by hand. You may also need at some point to restart the Command Prompt , the whole system, or refresh your environment variables using the refreshenv command. Then install the Windows build tools from an admin console as documented in the Microsoft\u2019s Node.js guidelines : npm install -g windows-build-tools You may still need to manually add the python installation directory to your PATH . To do so, search for PATH from the start menu and select Edit environment variables for your account . Then edit the PATH user variable (not the system one) and append the following to the end (assuming ... is the current text): `...;%USERPROFILE%\\.windows-build-tools\\python27` To set up Docker, in case you hardware is old or you don\u2019t own a Windows Pro license, you may encounter the same issue as on old macOS hardware (see below). (please feel free to improve this section)", "title": "Windows"}, {"location": "cozy-desktop/developer/requirements/#macos", "text": "You need a Mac to build / test for macOS. The easiest way to set up the environment is to install and use Homebrew : brew install git brew install node @8 brew install yarn To install Docker, first check that your mac has kernel hypervisor support: sysctl -n kern.hv_support If the output is 1 , then you can install the latest Docker version: brew cask install docker Otherwise you\u2019ll have to install a Docker VM and set up your shell environment so the various docker commands know how to use it (you can omit the default parameters below): brew cask install docker-toolbox docker-machine create default eval $(docker-machine env default)", "title": "macOS"}, {"location": "cozy-desktop/developer/requirements/#fedora-28", "text": "sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo sudo dnf install docker gcc-c++ git nodejs yarn transifex-client python3-pip sudo pip install docker-compose sudo groupadd docker sudo usermod -aG docker $USER # Restart your session so this takes effect", "title": "Fedora 28"}, {"location": "cozy-desktop/developer/requirements/#ubuntu", "text": "curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo \"deb https://dl.yarnpkg.com/debian/ stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository \\ \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" sudo apt update sudo apt install git nodejs build-essential gcc transifex-client icnsutils graphicsmagick python3-pip docker-ce yarn sudo pip install docker-compose sudo groupadd docker sudo usermod -aG docker $USER # Restart your session so this takes effect", "title": "Ubuntu"}, {"location": "cozy-desktop/developer/requirements/#set-up-a-cozy-stack", "text": "If you don\u2019t already have a running Cozy stack , the easiest way to get started is to use Docker & docker-compose : docker-compose up yarn bootstrap", "title": "Set up a Cozy stack"}, {"location": "cozy-desktop/developer/requirements/#cozy-stack", "text": "You can run any command in the cozy-stack docker container with the yarn docker:exec script, e.g.: yarn docker:exec apt-get update yarn docker:exec apt-get install git # So we can install cozy apps You can also run any cozy-stack command with the yarn cozy-stack script, e.g.: yarn cozy-stack apps install --domain cozy.localhost:8080 drive 'git://github.com/cozy/cozy-drive.git#build-drive'", "title": "Cozy Stack"}, {"location": "cozy-desktop/developer/requirements/#complete-your-setup", "text": "See ./setup.md", "title": "Complete your setup"}, {"location": "cozy-desktop/developer/setup/", "text": "Setting Up a Development Environment \u00b6 Cozy Desktop is based on electron and the code is mostly written in JavaScript. To start developing, check the prerequisites and follow the guide below. The following commands should work in a Unix shell (Bash or ZSH for example) and in Windows PowerShell. Install requirements \u00b6 To develop and build the source code, you will need the following: Git Node.js Yarn Docker Cozy Stack in Docker Consult ./requirements.md for help on this topic. Get the code \u00b6 git clone git@github.com:cozy-labs/cozy-desktop.git cd cozy-desktop Warning : The path to your local repository should not include any space, otherwise installing dependencies will fail . Install dependencies \u00b6 yarn install:all Build everything \u00b6 yarn build Transifex (optional) \u00b6 If you need to update translations, you\u2019ll need a Transifex API token at this step (requested automatically if transifex is in your $PATH) Create an account on http://www.transifex.com Join the Cozy team Get your API token from the account settings page Start development version \u00b6 yarn start N.B.: the address of the development cozy-stack is http://cozy.localhost:8080. Don\u2019t forget the protocol part when creating the connection in cozy-desktop for the first time or it won\u2019t find the server. Run tests \u00b6 See test . Develop Elm \u00b6 The script yarn dev:elm let you develop elm in standalone. Open the browser at http://localhost:8000/dev/elm.html#updater . See Window.elm@fromHash for different windows (updater, tray, help, \u2026).", "title": "Test"}, {"location": "cozy-desktop/developer/setup/#setting-up-a-development-environment", "text": "Cozy Desktop is based on electron and the code is mostly written in JavaScript. To start developing, check the prerequisites and follow the guide below. The following commands should work in a Unix shell (Bash or ZSH for example) and in Windows PowerShell.", "title": "Setting Up a Development Environment"}, {"location": "cozy-desktop/developer/setup/#install-requirements", "text": "To develop and build the source code, you will need the following: Git Node.js Yarn Docker Cozy Stack in Docker Consult ./requirements.md for help on this topic.", "title": "Install requirements"}, {"location": "cozy-desktop/developer/setup/#get-the-code", "text": "git clone git@github.com:cozy-labs/cozy-desktop.git cd cozy-desktop Warning : The path to your local repository should not include any space, otherwise installing dependencies will fail .", "title": "Get the code"}, {"location": "cozy-desktop/developer/setup/#install-dependencies", "text": "yarn install:all", "title": "Install dependencies"}, {"location": "cozy-desktop/developer/setup/#build-everything", "text": "yarn build", "title": "Build everything"}, {"location": "cozy-desktop/developer/setup/#transifex-optional", "text": "If you need to update translations, you\u2019ll need a Transifex API token at this step (requested automatically if transifex is in your $PATH) Create an account on http://www.transifex.com Join the Cozy team Get your API token from the account settings page", "title": "Transifex (optional)"}, {"location": "cozy-desktop/developer/setup/#start-development-version", "text": "yarn start N.B.: the address of the development cozy-stack is http://cozy.localhost:8080. Don\u2019t forget the protocol part when creating the connection in cozy-desktop for the first time or it won\u2019t find the server.", "title": "Start development version"}, {"location": "cozy-desktop/developer/setup/#run-tests", "text": "See test .", "title": "Run tests"}, {"location": "cozy-desktop/developer/setup/#develop-elm", "text": "The script yarn dev:elm let you develop elm in standalone. Open the browser at http://localhost:8000/dev/elm.html#updater . See Window.elm@fromHash for different windows (updater, tray, help, \u2026).", "title": "Develop Elm"}, {"location": "cozy-desktop/developer/test/", "text": "Tests \u00b6 Dependencies \u00b6 Dependencies are managed with Yarn , so you\u2019ll have to install it first. Then, to install dev dependencies: yarn We use electron-mocha , an electron-compatible version of mocha , for testing cozy-desktop. See options in test/mocha.opt . Unit, integration & scenario tests require that you have a Cozy stack up. It\u2019s also expected that you have an instance registered for cozy.localhost:8080 with the test passphrase . You can start a cozy-stack via the provided docker-compose file: docker-compose up See requirements for details on how to setup docker and docker-compose. Unit tests \u00b6 For testing a class in isolation, method per method: yarn test:unit Integration tests \u00b6 You can run the integration suite to test the communication between cozy-desktop and a remote cozy stack: yarn test:integration Scenarios \u00b6 Recently we have been writing more and more test scenarios as plain data in ./test/scenarios/*/scenario.js files. Those can then be used to capture local and/or remote events generated by those scenarios actions (by running the yarn capture script , see yarn capture --help for more information). The captured events are stored in the corresponding ./test/scenarios/**/{parcel|local|remote}/ subdirectory. Finally we can use those captures as fixtures in tests (see test/scenarios/**/scenario.js ). The main benefit is that both local and remote events can come in remote order, so using versioned test input makes the tests repetable/reliable and allows us to try different event sequences. TODO: Refactor dev/capture* and test/support/helpers/scenarios.js TODO: The local/remote wording is confusing. Use source/target instead? TODO: Rename local/ subdirs to chokidar/ TODO: Use captures instead of real actions when run from the remote side (so we can test different event sequences) TODO: Enable and fix the last failing scenarios TODO: Eventually stop asserting the whole chain in every scenario to make the build faster TODO: Eventually find a way to test a few loop effects Options \u00b6 It\u2019s possible to run all tests at once: yarn test To run a specific set of tests (here testing pouch) yarn mocha test/unit/pouch.js For more logs you can activate debug logs: DEBUG = 1 yarn ... Or even dump the logs of a given level directly in the console: DEBUG = 1 TESTDEBUG = info yarn ... Coverage \u00b6 FIXME: Coverage is currently unavailable. You can enable coverage metrics for any npm command with the coverage.sh script. Examples: ./scripts/coverage.sh yarn test ./scripts/coverage.sh yarn test-unit Please note that code coverage is only measured for unit tests by default. Integration tests have another purpose, so they are deliberately excluded, even when running ./scripts/coverage.sh yarn test-integration explicitely. Please also note that we don\u2019t measure coverage on the GUI for now. Implementation details: yarn mocha:coverage is the same as yarn mocha except it also loads ./test/support/coverage.js . ./test/support/coverage.js uses istanbul to instrument the code in a way compatible with electron-mocha . babel-plugin-istanbul inserts instrumentation code when compiling from EcmaScript to JavaScript The mocha tests are run and generate an lcov-style report (including HTML output) Finally, when run on the CI, we tell Travis to upload the report to the Codecov service. Property based testing \u00b6 In theory, property based testing is a way to generalize some unit tests. Here, we are using them more as fuzzing / intergration tests. The property based testing is not currently runned on CI: it would need some work to do so. Currently, it is mainly aimed at running manually by an experienced developer to find bugs that manual tests haven\u2019t found. We have two types of property based testing: local_watcher, where we simulate events of a disk, and at the end we check that PouchDB has all the information about the files and directory in the synchronized path. It\u2019s called local_watcher because it mostly tests the local watcher, but it also touches other classes like Prep and Merge. two_clients, where we start a cozy-stack, create an instance, and run 2 cozy-desktop on this instance. Then, we doing things like creating files on both clients, and at the end, we check that the two clients has the same data as the stack (in CouchDB). For both, we have separated the generation of a test case from running it, and we have no shrinking strategy (no good JS library to do that). The generated test case are in JSON format, and it\u2019s possible to write manually a test case to exibit particular behavior. You can generate a test with this command: $ ./test/generate_property_json.js local_watcher | jq . > test/property/local_watcher/generated.json And then, you can run it with: $ COZY_FS_WATCHER = channel yarn test:property --grep generated If you want to run several tests for finding new bugs, there is also the ./test/mass_property_tests.sh script.", "title": "Test"}, {"location": "cozy-desktop/developer/test/#tests", "text": "", "title": "Tests"}, {"location": "cozy-desktop/developer/test/#dependencies", "text": "Dependencies are managed with Yarn , so you\u2019ll have to install it first. Then, to install dev dependencies: yarn We use electron-mocha , an electron-compatible version of mocha , for testing cozy-desktop. See options in test/mocha.opt . Unit, integration & scenario tests require that you have a Cozy stack up. It\u2019s also expected that you have an instance registered for cozy.localhost:8080 with the test passphrase . You can start a cozy-stack via the provided docker-compose file: docker-compose up See requirements for details on how to setup docker and docker-compose.", "title": "Dependencies"}, {"location": "cozy-desktop/developer/test/#unit-tests", "text": "For testing a class in isolation, method per method: yarn test:unit", "title": "Unit tests"}, {"location": "cozy-desktop/developer/test/#integration-tests", "text": "You can run the integration suite to test the communication between cozy-desktop and a remote cozy stack: yarn test:integration", "title": "Integration tests"}, {"location": "cozy-desktop/developer/test/#scenarios", "text": "Recently we have been writing more and more test scenarios as plain data in ./test/scenarios/*/scenario.js files. Those can then be used to capture local and/or remote events generated by those scenarios actions (by running the yarn capture script , see yarn capture --help for more information). The captured events are stored in the corresponding ./test/scenarios/**/{parcel|local|remote}/ subdirectory. Finally we can use those captures as fixtures in tests (see test/scenarios/**/scenario.js ). The main benefit is that both local and remote events can come in remote order, so using versioned test input makes the tests repetable/reliable and allows us to try different event sequences. TODO: Refactor dev/capture* and test/support/helpers/scenarios.js TODO: The local/remote wording is confusing. Use source/target instead? TODO: Rename local/ subdirs to chokidar/ TODO: Use captures instead of real actions when run from the remote side (so we can test different event sequences) TODO: Enable and fix the last failing scenarios TODO: Eventually stop asserting the whole chain in every scenario to make the build faster TODO: Eventually find a way to test a few loop effects", "title": "Scenarios"}, {"location": "cozy-desktop/developer/test/#options", "text": "It\u2019s possible to run all tests at once: yarn test To run a specific set of tests (here testing pouch) yarn mocha test/unit/pouch.js For more logs you can activate debug logs: DEBUG = 1 yarn ... Or even dump the logs of a given level directly in the console: DEBUG = 1 TESTDEBUG = info yarn ...", "title": "Options"}, {"location": "cozy-desktop/developer/test/#coverage", "text": "FIXME: Coverage is currently unavailable. You can enable coverage metrics for any npm command with the coverage.sh script. Examples: ./scripts/coverage.sh yarn test ./scripts/coverage.sh yarn test-unit Please note that code coverage is only measured for unit tests by default. Integration tests have another purpose, so they are deliberately excluded, even when running ./scripts/coverage.sh yarn test-integration explicitely. Please also note that we don\u2019t measure coverage on the GUI for now. Implementation details: yarn mocha:coverage is the same as yarn mocha except it also loads ./test/support/coverage.js . ./test/support/coverage.js uses istanbul to instrument the code in a way compatible with electron-mocha . babel-plugin-istanbul inserts instrumentation code when compiling from EcmaScript to JavaScript The mocha tests are run and generate an lcov-style report (including HTML output) Finally, when run on the CI, we tell Travis to upload the report to the Codecov service.", "title": "Coverage"}, {"location": "cozy-desktop/developer/test/#property-based-testing", "text": "In theory, property based testing is a way to generalize some unit tests. Here, we are using them more as fuzzing / intergration tests. The property based testing is not currently runned on CI: it would need some work to do so. Currently, it is mainly aimed at running manually by an experienced developer to find bugs that manual tests haven\u2019t found. We have two types of property based testing: local_watcher, where we simulate events of a disk, and at the end we check that PouchDB has all the information about the files and directory in the synchronized path. It\u2019s called local_watcher because it mostly tests the local watcher, but it also touches other classes like Prep and Merge. two_clients, where we start a cozy-stack, create an instance, and run 2 cozy-desktop on this instance. Then, we doing things like creating files on both clients, and at the end, we check that the two clients has the same data as the stack (in CouchDB). For both, we have separated the generation of a test case from running it, and we have no shrinking strategy (no good JS library to do that). The generated test case are in JSON format, and it\u2019s possible to write manually a test case to exibit particular behavior. You can generate a test with this command: $ ./test/generate_property_json.js local_watcher | jq . > test/property/local_watcher/generated.json And then, you can run it with: $ COZY_FS_WATCHER = channel yarn test:property --grep generated If you want to run several tests for finding new bugs, there is also the ./test/mass_property_tests.sh script.", "title": "Property based testing"}, {"location": "cozy-desktop/usage/build/", "text": "Build Cozy Drive for the GNU/Linux \u00b6 If your distribution is supported, it is much easier to use our provided .AppImage file Install some dependencies \u00b6 Git Node.js Yarn Get the source code from github \u00b6 git clone git@github.com:cozy-labs/cozy-desktop.git cd cozy-desktop Install dependencies \u00b6 yarn install:all NB: to speed things up electron will attempt to download a compiled binary. If you are strict about compiling everything on your computer, refer to the electron build instructions Build all assets \u00b6 yarn build Package it into a binary \u00b6 yarn dist Run it \u00b6 mkdir /opt/cozydrive # you can change this path cp ./dist/CozyDrive-*.AppImage /opts/cozydrive/CozyDrive.AppImage chmod +x /opt/cozydrive/CozyDrive.AppImage /opt/cozydrive/CozyDrive.AppImage Note: When a new version gets out, the application will attempt to update itself but it will fail, simply repeat the steps above to make it works again. Contribute \u00b6 We want to support as much linux distribution as possible, but we just don\u2019t have the resource. As of this writing, the biggest limiter is a bug where the AppImage does not build unless the GLIBCXX >= 3.4.21 We did an exploration to fix this issue but do not have the time to experiment and implement any ot the potential solutions. If you have experience with compiling/packaging for linux, you can help us with a PR to setup build for your distribution\u2019s package or by implementing one of the following option to make the .AppImage works with older glibc versions. Option A: convince the whole chain electron-builder > prebuild > node-gyp to build against another libc version Prebuild has a \u2013libc options, not sure what value it takes, not sure which compilers it needs. Option B: bundling libstdc++.so - Add libstdc++.so to AppImage build : https://github.com/electron-userland/electron-builder/issues/1985 - But AppImage does not recommend it, as it might break on newer distro https://github.com/AppImage/AppImageKit/wiki/Creating-AppImages#libstdcso6 - So AppImage recommends to use https://github.com/darealshinji/AppImageKit-checkrt/ to only include the bundled .so if the distro is too old. - But we need to figure out how to include this within electron-builder - This adds a few Mo to the build, but insignificant compare to the whole bundle. Option C: Building on an older distro should give us a working binary. But we will need to duplicate the works done on https://github.com/electron-userland/electron-builder/tree/master/docker to get a working build environment. And until we try, we have no guarantee it will even works.", "title": "Build"}, {"location": "cozy-desktop/usage/build/#build-cozy-drive-for-the-gnulinux", "text": "If your distribution is supported, it is much easier to use our provided .AppImage file", "title": "Build Cozy Drive for the GNU/Linux"}, {"location": "cozy-desktop/usage/build/#install-some-dependencies", "text": "Git Node.js Yarn", "title": "Install some dependencies"}, {"location": "cozy-desktop/usage/build/#get-the-source-code-from-github", "text": "git clone git@github.com:cozy-labs/cozy-desktop.git cd cozy-desktop", "title": "Get the source code from github"}, {"location": "cozy-desktop/usage/build/#install-dependencies", "text": "yarn install:all NB: to speed things up electron will attempt to download a compiled binary. If you are strict about compiling everything on your computer, refer to the electron build instructions", "title": "Install dependencies"}, {"location": "cozy-desktop/usage/build/#build-all-assets", "text": "yarn build", "title": "Build all assets"}, {"location": "cozy-desktop/usage/build/#package-it-into-a-binary", "text": "yarn dist", "title": "Package it into a binary"}, {"location": "cozy-desktop/usage/build/#run-it", "text": "mkdir /opt/cozydrive # you can change this path cp ./dist/CozyDrive-*.AppImage /opts/cozydrive/CozyDrive.AppImage chmod +x /opt/cozydrive/CozyDrive.AppImage /opt/cozydrive/CozyDrive.AppImage Note: When a new version gets out, the application will attempt to update itself but it will fail, simply repeat the steps above to make it works again.", "title": "Run it"}, {"location": "cozy-desktop/usage/build/#contribute", "text": "We want to support as much linux distribution as possible, but we just don\u2019t have the resource. As of this writing, the biggest limiter is a bug where the AppImage does not build unless the GLIBCXX >= 3.4.21 We did an exploration to fix this issue but do not have the time to experiment and implement any ot the potential solutions. If you have experience with compiling/packaging for linux, you can help us with a PR to setup build for your distribution\u2019s package or by implementing one of the following option to make the .AppImage works with older glibc versions. Option A: convince the whole chain electron-builder > prebuild > node-gyp to build against another libc version Prebuild has a \u2013libc options, not sure what value it takes, not sure which compilers it needs. Option B: bundling libstdc++.so - Add libstdc++.so to AppImage build : https://github.com/electron-userland/electron-builder/issues/1985 - But AppImage does not recommend it, as it might break on newer distro https://github.com/AppImage/AppImageKit/wiki/Creating-AppImages#libstdcso6 - So AppImage recommends to use https://github.com/darealshinji/AppImageKit-checkrt/ to only include the bundled .so if the distro is too old. - But we need to figure out how to include this within electron-builder - This adds a few Mo to the build, but insignificant compare to the whole bundle. Option C: Building on an older distro should give us a working binary. But we will need to duplicate the works done on https://github.com/electron-userland/electron-builder/tree/master/docker to get a working build environment. And until we try, we have no guarantee it will even works.", "title": "Contribute"}, {"location": "cozy-desktop/usage/cli/", "text": "CLI Deprecated \u00b6 The CLI mode was disabled on Cozy Drive for Desktop. Let us know if you\u2019d like to have it and we will add it to our todolist.", "title": "CLI"}, {"location": "cozy-desktop/usage/cli/#cli-deprecated", "text": "The CLI mode was disabled on Cozy Drive for Desktop. Let us know if you\u2019d like to have it and we will add it to our todolist.", "title": "CLI Deprecated"}, {"location": "cozy-desktop/usage/file_systems/", "text": "File Systems \u00b6 The app currently makes the following assumptions: NTFS is used on Windows APFS or HFS+ is used on macOS EXT4 is used on GNU/Linux On those 3 platforms, using a file system with similar path restrictions, case and unicode normalization sensitivity as the assumed one(s) may work (e.g. using EXT3 on GNU/Linux should work although we don\u2019t officially support it). On other platforms, using a file system with similar path restrictions, case and unicode normalization sensitivity as EXT4 should work too (e.g. using EXT4 on BSD should work too). Please note that all FAT versions are currently unsupported. In case you\u2019re successfully using another platform (e.g. some BSD flavor), or GNU/Linux with another file system than EXT4 (e.g. BTRFS or ZFS), your feedback is welcome! File System / Platform Matrix \u00b6 File System Platform Status APFS macOS supported, actively tested EXT3/EXT2 GNU/Linux should work EXT4 GNU/Linux supported, actively tested FAT won\u2019t work HFS+ macOS supported, testing should be back soon HFS+ GNU/Linux won\u2019t work NTFS Windows supported, actively tested NTFS GNU/Linux won\u2019t work Add your file system / platform", "title": "Filesystems"}, {"location": "cozy-desktop/usage/file_systems/#file-systems", "text": "The app currently makes the following assumptions: NTFS is used on Windows APFS or HFS+ is used on macOS EXT4 is used on GNU/Linux On those 3 platforms, using a file system with similar path restrictions, case and unicode normalization sensitivity as the assumed one(s) may work (e.g. using EXT3 on GNU/Linux should work although we don\u2019t officially support it). On other platforms, using a file system with similar path restrictions, case and unicode normalization sensitivity as EXT4 should work too (e.g. using EXT4 on BSD should work too). Please note that all FAT versions are currently unsupported. In case you\u2019re successfully using another platform (e.g. some BSD flavor), or GNU/Linux with another file system than EXT4 (e.g. BTRFS or ZFS), your feedback is welcome!", "title": "File Systems"}, {"location": "cozy-desktop/usage/file_systems/#file-system-platform-matrix", "text": "File System Platform Status APFS macOS supported, actively tested EXT3/EXT2 GNU/Linux should work EXT4 GNU/Linux supported, actively tested FAT won\u2019t work HFS+ macOS supported, testing should be back soon HFS+ GNU/Linux won\u2019t work NTFS Windows supported, actively tested NTFS GNU/Linux won\u2019t work Add your file system / platform", "title": "File System / Platform Matrix"}, {"location": "cozy-desktop/usage/ignore_files/", "text": "Ignore Files or Directories \u00b6 It\u2019s possible to make cozy-desktop ignore some files and folders by using a .cozyignore file. It works pretty much like a .gitignore , ie you put patterns in this file to ignore. The rules for patterns are the same, so you can look at git documentation to see for their format. For example: *.mp4 heavy-* /tmp", "title": "Ignore files"}, {"location": "cozy-desktop/usage/ignore_files/#ignore-files-or-directories", "text": "It\u2019s possible to make cozy-desktop ignore some files and folders by using a .cozyignore file. It works pretty much like a .gitignore , ie you put patterns in this file to ignore. The rules for patterns are the same, so you can look at git documentation to see for their format. For example: *.mp4 heavy-* /tmp", "title": "Ignore Files or Directories"}, {"location": "cozy-desktop/usage/inotify/", "text": "How to increase the number of inotify watches \u00b6 What is this limit? \u00b6 Under GNU/Linux, cozy-desktop is notified of file system changes via inotify. This mechanism has a limit for the number of files and directories that it can watch, to avoid taking too much memory. On modern computers, it is recommended to use at least 524288 for this limit. How to increase it \u00b6 If you are running Ubuntu, Debian, RedHat, or another similar Linux distribution, run the following in a terminal: echo fs.inotify.max_user_watches = 524288 | sudo tee -a /etc/sysctl.conf \\ && sudo sysctl -p If you are running ArchLinux, run the following command instead: echo fs.inotify.max_user_watches = 524288 \\ | sudo tee /etc/sysctl.d/40-max-user-watches.conf \\ && sudo sysctl --system More info \u00b6 Wiki of Listen: Increasing the amount of inotify watchers Manual of inotify(7) Blog post: limit of inotify Forum: How can I tell if I am out of inotify watches?", "title": "inotify"}, {"location": "cozy-desktop/usage/inotify/#how-to-increase-the-number-of-inotify-watches", "text": "", "title": "How to increase the number of inotify watches"}, {"location": "cozy-desktop/usage/inotify/#what-is-this-limit", "text": "Under GNU/Linux, cozy-desktop is notified of file system changes via inotify. This mechanism has a limit for the number of files and directories that it can watch, to avoid taking too much memory. On modern computers, it is recommended to use at least 524288 for this limit.", "title": "What is this limit?"}, {"location": "cozy-desktop/usage/inotify/#how-to-increase-it", "text": "If you are running Ubuntu, Debian, RedHat, or another similar Linux distribution, run the following in a terminal: echo fs.inotify.max_user_watches = 524288 | sudo tee -a /etc/sysctl.conf \\ && sudo sysctl -p If you are running ArchLinux, run the following command instead: echo fs.inotify.max_user_watches = 524288 \\ | sudo tee /etc/sysctl.d/40-max-user-watches.conf \\ && sudo sysctl --system", "title": "How to increase it"}, {"location": "cozy-desktop/usage/inotify/#more-info", "text": "Wiki of Listen: Increasing the amount of inotify watchers Manual of inotify(7) Blog post: limit of inotify Forum: How can I tell if I am out of inotify watches?", "title": "More info"}, {"location": "cozy-desktop/usage/limitations/", "text": "Limitations \u00b6 Cozy-desktop is designed to synchronize files and folders between a remote cozy instance and a local hard drive, for a personal usage. We tried to make it simple and easy. So, it has some limitations: Files and folders named like this are ignored: .system-tmp-cozy-drive (they are used to keep internal state) _design (special meaning for pouchdb/couchdb) It\u2019s not a particularly good idea to share code with cozy-desktop: node_modules have tons of small files compiled code often has to be recompile to works on another environment git (and other VCS) repositories are not meant to be shared this way. You may lose your work if you make changes on two laptops synchronized by cozy-desktop (it\u2019s the same with dropbox , google-drive , syncthing , etc.) cozy-desktop keeps the time with only a precision of a second, which may trigger unexpected \u201cfile changed\u201d notifications in your editor (see emacs issue and workaround ). If the same file has been modified in parallel, cozy-desktop don\u2019t try to merge the modifications. It will just rename of one the copies with a -conflict suffix. It\u2019s the same for folders. We expect a personal usage: a reasonable number of files and folders (< 1.000.000) a reasonable number of files per folder (< 10.000) a reasonable size for files (< 1 Tb) a reasonable size for files and folders path (< 1024 bytes) not too many changes etc. For OSX, filenames with weird unicode characters may be problematic in some rare cases. Symbolic links and ACL are not yet handled. The full sync directory must be on the same partition. Large files must be uploaded/downloaded in one time (we are thinking about making it possible to split a large file in several blocks for download/upload). Due to its nature, cozy-desktop needs resources: CPU, for checksums in particular RAM, to keep all the metadata in memory, and for nodejs libraries Disk, but the overhead from cozy-desktop is low Network bandwidth obviously No advanced feature, like P2P replication between several cozy-desktop instances.", "title": "Limitations"}, {"location": "cozy-desktop/usage/limitations/#limitations", "text": "Cozy-desktop is designed to synchronize files and folders between a remote cozy instance and a local hard drive, for a personal usage. We tried to make it simple and easy. So, it has some limitations: Files and folders named like this are ignored: .system-tmp-cozy-drive (they are used to keep internal state) _design (special meaning for pouchdb/couchdb) It\u2019s not a particularly good idea to share code with cozy-desktop: node_modules have tons of small files compiled code often has to be recompile to works on another environment git (and other VCS) repositories are not meant to be shared this way. You may lose your work if you make changes on two laptops synchronized by cozy-desktop (it\u2019s the same with dropbox , google-drive , syncthing , etc.) cozy-desktop keeps the time with only a precision of a second, which may trigger unexpected \u201cfile changed\u201d notifications in your editor (see emacs issue and workaround ). If the same file has been modified in parallel, cozy-desktop don\u2019t try to merge the modifications. It will just rename of one the copies with a -conflict suffix. It\u2019s the same for folders. We expect a personal usage: a reasonable number of files and folders (< 1.000.000) a reasonable number of files per folder (< 10.000) a reasonable size for files (< 1 Tb) a reasonable size for files and folders path (< 1024 bytes) not too many changes etc. For OSX, filenames with weird unicode characters may be problematic in some rare cases. Symbolic links and ACL are not yet handled. The full sync directory must be on the same partition. Large files must be uploaded/downloaded in one time (we are thinking about making it possible to split a large file in several blocks for download/upload). Due to its nature, cozy-desktop needs resources: CPU, for checksums in particular RAM, to keep all the metadata in memory, and for nodejs libraries Disk, but the overhead from cozy-desktop is low Network bandwidth obviously No advanced feature, like P2P replication between several cozy-desktop instances.", "title": "Limitations"}, {"location": "cozy-desktop/usage/linux/", "text": "Cozy Drive on the GNU/Linux Desktop \u00b6 Introduction \u00b6 While porting the old file synchronization client to the new Cozy stack v3, we decided to focus on Windows and macOS because those were what most of our future users would be using. But lots of our early-adopters were GNU/Linux users. And we are GNU/Linux users ourselves too. So we had to bring back GNU/Linux support at some point. There are many GNU/Linux distributions out there, and even in the Cozy team people use many of them. Providing quality packages for everybody can be quite time consuming. So we decided to start with a solution that was easy for us to set up: AppImage . Easy since it\u2019s included in electron-builder, the tool we already use to generate the Windows and macOS apps. User experience definitely won\u2019t be the best (it will look a lot like good old proprietary driver install scripts). But it should at least work for most people and give us a way to quickly start getting feedback regarding other possible issues. And the app will auto-update the same way as the Windows or macOS ones. We\u2019ll provide packages for major distros as soon as possible (unofficial nightly builds for Debian and Ubuntu are already being tested internally). Supported distributions \u00b6 A few things to know: - The current AppImage needs a relatively recent versions of : - GLIBC >= 2.32 - GLIBCXX >= 3.4.21 - The application should work with most desktop manager but is actively tested on Gnome 3 - The systray icon might only show up on some desktop managers if you use a third-party software like the TopIcons-Plus Gnome extension or libappindicator; it is up to you to install the third-party software if needed We only support the latest version of each distribution although the app could work on older versions. The table below can be outdated. Distribution supported comment Fedora 38 yes Debian 12 (Bookworm) yes Ubuntu 23.04 (Lunar Lobster) yes Linux Mint 21.2 (Victoria) yes Archlinux yes if up-to-date Add your distribution (see below) \u2026 \u2014 \u2014 \u2014 Fedora 37 no should work Debian 11 (Bullseye) no should work Ubuntu 22.10 (Kinetic Kudu) no should work Ubuntu 22.04 (Jammy Jellyfish) no should work after installing FUSE ( sudo apt install libfuse2 ) Linux Mint 21.1 (Vera) no should work Mageia 8 no should work openSUSE Leap 15.4 no should work Before requesting for your distribution to be added to the list, please: Include the exact name and version of your distribution Retrieve your GLIBC and GLIBCXX versions by running the following commands in a terminal: strings $(locate -b '\\libstdc++.so.6') | grep '^GLIBCXX_[0-9.]*$' | sort -V | tail -n 1 strings $(locate -b '\\libstdc++.so.6') | grep '^GLIBC_[0-9.]*$' | sort -V | tail -n 1 (and include the output in your request) Install the app, run it and make sure it actually works If your distribution is not supported follow the manual build guide and jump to the second part of the Install section. Install \u00b6 Note for Archlinux Users You can install cozy-desktop from the [community] repo. Download the *.AppImage file for your architecture from the latest release . You probably don\u2019t want to keep the app in your /Downloads folder and run it from there. You can for example create a macOS-like Applications folder and move it there. Advanced users may prefer to move it to some special folder ( ~/.local/bin/ , ~/bin/ , /opt/ \u2026). Integration with the system \u00b6 By default, the application will only be launchable by double-clicking the AppImage file you downloaded. If you want it to be available in your applications menu, you can install the appimaged daemon, available from its github repository \u2018s releases or via your distribution package manager. If you install it from the repository, you might need to run the following commands in a terminal to make sure it is run when starting your user session: $ systemctl --user add-wants default.target appimaged $ systemctl --user start appimaged # restart your user session now After that, any AppImage file found in one of those folders will be automatically made executable and available in your applications menu: - $HOME/Downloads (or its localized equivalent, as determined by G_USER_DIRECTORY_DOWNLOAD in glib) - $HOME/.local/bin - $HOME/bin - $HOME/Applications - /Applications - [any mounted partition]/Applications - /opt - /usr/local/bin Running \u00b6 If you have decided not to integrate AppImages with your system, you\u2019ll need to make the file executable. In GNOME 3, right-click on the file, select the Properties menu entry, go to the Permissions tab and enable the Execution checkbox. Or in a terminal: cd /dir/where/you/put/the/file && chmod +x *.AppImage ` On first run, the application should have configured itself to run automatically on system start. Where are the application files? \u00b6 Almost everything is in the *.AppImage file however, if you have installed appimaged , the following additional files are created: Launcher file in ~/.local/share/applications/appimagekit_-Cozy_Drive.desktop Icons in ~/.local/share/icons/hicolor/*/apps/appimagekit-cozydrive.png Everything else works the same as Windows or macOS: your synchronized files are in ~/Cozy Drive/ or the folder you choose on first run, and the hidden ~/.cozy-desktop/ folder contains the application configuration, metadata and logs. Displaying the app window \u00b6 To show the application preferences and the recently synchronized files list, you can either launch the app again (i.e. it will simply open the app\u2019s window as only one instance can run at a time) or click on the systray icon. If libappindicator is installed on your system, left-clicks won\u2019t have any effects so you need to do a right-click on the icon then select the Show Application menu entry. Note for GNOME Users From 3.26 onwards, GNOME removed the systray which is the only interface for Cozy Drive . It should be replaced in the future by libcloudprovider , which we will implement when it spreads. In the meantime, you need to install an extension providing support for appindicator. You can find and install one from https://extensions.gnome.org/ by searching for appindicator . Note for i3wm Users You can set \"gui\": {\"visibleOnBlur\": true} in your ~/.cozy-desktop/config.json so the popover doesn\u2019t hide when focusing another window. Uninstall \u00b6 Manually remove the files listed above.", "title": "Linux"}, {"location": "cozy-desktop/usage/linux/#cozy-drive-on-the-gnulinux-desktop", "text": "", "title": "Cozy Drive on the GNU/Linux Desktop"}, {"location": "cozy-desktop/usage/linux/#introduction", "text": "While porting the old file synchronization client to the new Cozy stack v3, we decided to focus on Windows and macOS because those were what most of our future users would be using. But lots of our early-adopters were GNU/Linux users. And we are GNU/Linux users ourselves too. So we had to bring back GNU/Linux support at some point. There are many GNU/Linux distributions out there, and even in the Cozy team people use many of them. Providing quality packages for everybody can be quite time consuming. So we decided to start with a solution that was easy for us to set up: AppImage . Easy since it\u2019s included in electron-builder, the tool we already use to generate the Windows and macOS apps. User experience definitely won\u2019t be the best (it will look a lot like good old proprietary driver install scripts). But it should at least work for most people and give us a way to quickly start getting feedback regarding other possible issues. And the app will auto-update the same way as the Windows or macOS ones. We\u2019ll provide packages for major distros as soon as possible (unofficial nightly builds for Debian and Ubuntu are already being tested internally).", "title": "Introduction"}, {"location": "cozy-desktop/usage/linux/#supported-distributions", "text": "A few things to know: - The current AppImage needs a relatively recent versions of : - GLIBC >= 2.32 - GLIBCXX >= 3.4.21 - The application should work with most desktop manager but is actively tested on Gnome 3 - The systray icon might only show up on some desktop managers if you use a third-party software like the TopIcons-Plus Gnome extension or libappindicator; it is up to you to install the third-party software if needed We only support the latest version of each distribution although the app could work on older versions. The table below can be outdated. Distribution supported comment Fedora 38 yes Debian 12 (Bookworm) yes Ubuntu 23.04 (Lunar Lobster) yes Linux Mint 21.2 (Victoria) yes Archlinux yes if up-to-date Add your distribution (see below) \u2026 \u2014 \u2014 \u2014 Fedora 37 no should work Debian 11 (Bullseye) no should work Ubuntu 22.10 (Kinetic Kudu) no should work Ubuntu 22.04 (Jammy Jellyfish) no should work after installing FUSE ( sudo apt install libfuse2 ) Linux Mint 21.1 (Vera) no should work Mageia 8 no should work openSUSE Leap 15.4 no should work Before requesting for your distribution to be added to the list, please: Include the exact name and version of your distribution Retrieve your GLIBC and GLIBCXX versions by running the following commands in a terminal: strings $(locate -b '\\libstdc++.so.6') | grep '^GLIBCXX_[0-9.]*$' | sort -V | tail -n 1 strings $(locate -b '\\libstdc++.so.6') | grep '^GLIBC_[0-9.]*$' | sort -V | tail -n 1 (and include the output in your request) Install the app, run it and make sure it actually works If your distribution is not supported follow the manual build guide and jump to the second part of the Install section.", "title": "Supported distributions"}, {"location": "cozy-desktop/usage/linux/#install", "text": "Note for Archlinux Users You can install cozy-desktop from the [community] repo. Download the *.AppImage file for your architecture from the latest release . You probably don\u2019t want to keep the app in your /Downloads folder and run it from there. You can for example create a macOS-like Applications folder and move it there. Advanced users may prefer to move it to some special folder ( ~/.local/bin/ , ~/bin/ , /opt/ \u2026).", "title": "Install"}, {"location": "cozy-desktop/usage/linux/#integration-with-the-system", "text": "By default, the application will only be launchable by double-clicking the AppImage file you downloaded. If you want it to be available in your applications menu, you can install the appimaged daemon, available from its github repository \u2018s releases or via your distribution package manager. If you install it from the repository, you might need to run the following commands in a terminal to make sure it is run when starting your user session: $ systemctl --user add-wants default.target appimaged $ systemctl --user start appimaged # restart your user session now After that, any AppImage file found in one of those folders will be automatically made executable and available in your applications menu: - $HOME/Downloads (or its localized equivalent, as determined by G_USER_DIRECTORY_DOWNLOAD in glib) - $HOME/.local/bin - $HOME/bin - $HOME/Applications - /Applications - [any mounted partition]/Applications - /opt - /usr/local/bin", "title": "Integration with the system"}, {"location": "cozy-desktop/usage/linux/#running", "text": "If you have decided not to integrate AppImages with your system, you\u2019ll need to make the file executable. In GNOME 3, right-click on the file, select the Properties menu entry, go to the Permissions tab and enable the Execution checkbox. Or in a terminal: cd /dir/where/you/put/the/file && chmod +x *.AppImage ` On first run, the application should have configured itself to run automatically on system start.", "title": "Running"}, {"location": "cozy-desktop/usage/linux/#where-are-the-application-files", "text": "Almost everything is in the *.AppImage file however, if you have installed appimaged , the following additional files are created: Launcher file in ~/.local/share/applications/appimagekit_-Cozy_Drive.desktop Icons in ~/.local/share/icons/hicolor/*/apps/appimagekit-cozydrive.png Everything else works the same as Windows or macOS: your synchronized files are in ~/Cozy Drive/ or the folder you choose on first run, and the hidden ~/.cozy-desktop/ folder contains the application configuration, metadata and logs.", "title": "Where are the application files?"}, {"location": "cozy-desktop/usage/linux/#displaying-the-app-window", "text": "To show the application preferences and the recently synchronized files list, you can either launch the app again (i.e. it will simply open the app\u2019s window as only one instance can run at a time) or click on the systray icon. If libappindicator is installed on your system, left-clicks won\u2019t have any effects so you need to do a right-click on the icon then select the Show Application menu entry. Note for GNOME Users From 3.26 onwards, GNOME removed the systray which is the only interface for Cozy Drive . It should be replaced in the future by libcloudprovider , which we will implement when it spreads. In the meantime, you need to install an extension providing support for appindicator. You can find and install one from https://extensions.gnome.org/ by searching for appindicator . Note for i3wm Users You can set \"gui\": {\"visibleOnBlur\": true} in your ~/.cozy-desktop/config.json so the popover doesn\u2019t hide when focusing another window.", "title": "Displaying the app window"}, {"location": "cozy-desktop/usage/linux/#uninstall", "text": "Manually remove the files listed above.", "title": "Uninstall"}, {"location": "cozy-desktop/usage/macos/", "text": "Cozy Drive on macOS \u00b6 Supported versions \u00b6 We only support the latest 2 versions of macOS although the app could work on older versions. The table below can be outdated. We do not support M1 and M2 processors natively yet but Cozy Desktop should work fine with the emulation. macOS version supported comment 13 \u201cVentura\u201d yes 12 \u201cMonterey\u201d yes \u2014 \u2014 \u2014 11 \u201cBig Sur\u201d no should work 10.15 \u201cCatalina\u201d no end of life reached 10.14 \u201cMojave\u201d no end of life reached 10.13 \u201cHigh Sierra\u201d no end of life reached 10.12 \u201cSierra\u201d no end of life reached 10.11 \u201cEl Capitan\u201d no end of life reached 10.10 \u201cYosemite\u201d no end of life reached 10.9 \u201cMavericks\u201d no end of life reached 10.8 \u201cMountain Lion\u201d no end of life reached 10.7 \u201cLion\u201d no end of life reached 10.6 \u201cSnow Leopard\u201d no end of life reached Slash ( / ) vs colon ( : ) on macOS \u00b6 Quoting this paper from Wilfredo S\u00e1nchez, senior software engineer at Apple : Another obvious problem is the different path separators between HFS+ (colon, \u2018:\u2019) and UFS (slash, \u2018/\u2019). This also means that HFS+ file names may contain the slash character and not colons, while the opposite is true for UFS file names. This was easy to address, though it involves transforming strings back and forth. The HFS+ implementation in the kernel\u2019s VFS layer converts colon to slash and vice versa when reading from and writing to the on-disk format. So on disk the separator is a colon, but at the VFS layer (and therefore anything above it and the kernel, such as libc) it\u2019s a slash. However, the traditional Mac OS toolkits expect colons, so above the BSD layer, the core Carbon toolkit does yet another translation. The result is that Carbon applications see colons, and everyone else sees slashes. This can create a user-visible schizophrenia in the rare cases of file names containing colon characters, which appear to Carbon applications as slash characters, but to BSD programs and Cocoa applications as colons.", "title": "MacOS"}, {"location": "cozy-desktop/usage/macos/#cozy-drive-on-macos", "text": "", "title": "Cozy Drive on macOS"}, {"location": "cozy-desktop/usage/macos/#supported-versions", "text": "We only support the latest 2 versions of macOS although the app could work on older versions. The table below can be outdated. We do not support M1 and M2 processors natively yet but Cozy Desktop should work fine with the emulation. macOS version supported comment 13 \u201cVentura\u201d yes 12 \u201cMonterey\u201d yes \u2014 \u2014 \u2014 11 \u201cBig Sur\u201d no should work 10.15 \u201cCatalina\u201d no end of life reached 10.14 \u201cMojave\u201d no end of life reached 10.13 \u201cHigh Sierra\u201d no end of life reached 10.12 \u201cSierra\u201d no end of life reached 10.11 \u201cEl Capitan\u201d no end of life reached 10.10 \u201cYosemite\u201d no end of life reached 10.9 \u201cMavericks\u201d no end of life reached 10.8 \u201cMountain Lion\u201d no end of life reached 10.7 \u201cLion\u201d no end of life reached 10.6 \u201cSnow Leopard\u201d no end of life reached", "title": "Supported versions"}, {"location": "cozy-desktop/usage/macos/#slash-vs-colon-on-macos", "text": "Quoting this paper from Wilfredo S\u00e1nchez, senior software engineer at Apple : Another obvious problem is the different path separators between HFS+ (colon, \u2018:\u2019) and UFS (slash, \u2018/\u2019). This also means that HFS+ file names may contain the slash character and not colons, while the opposite is true for UFS file names. This was easy to address, though it involves transforming strings back and forth. The HFS+ implementation in the kernel\u2019s VFS layer converts colon to slash and vice versa when reading from and writing to the on-disk format. So on disk the separator is a colon, but at the VFS layer (and therefore anything above it and the kernel, such as libc) it\u2019s a slash. However, the traditional Mac OS toolkits expect colons, so above the BSD layer, the core Carbon toolkit does yet another translation. The result is that Carbon applications see colons, and everyone else sees slashes. This can create a user-visible schizophrenia in the rare cases of file names containing colon characters, which appear to Carbon applications as slash characters, but to BSD programs and Cocoa applications as colons.", "title": "Slash (/) vs colon (:) on macOS"}, {"location": "cozy-desktop/usage/windows/", "text": "Cozy Drive on Windows \u00b6 Supported versions \u00b6 We only support the latest 2 versions of Windows although the app could work on older versions. The table below can be outdated. Windows version supported comment Windows 11 (64 bits) yes should work Windows 10 (64 bits) yes actively tested \u2014 \u2014 \u2014 Windows 10 (32 bits) no \u2014 \u2014 \u2014 Windows 8.1 no end of life reached Windows 8 no end of life reached Windows 7 no end of life reached Windows Vista no end of life reached Windows XP no end of life reached", "title": "Windows"}, {"location": "cozy-desktop/usage/windows/#cozy-drive-on-windows", "text": "", "title": "Cozy Drive on Windows"}, {"location": "cozy-desktop/usage/windows/#supported-versions", "text": "We only support the latest 2 versions of Windows although the app could work on older versions. The table below can be outdated. Windows version supported comment Windows 11 (64 bits) yes should work Windows 10 (64 bits) yes actively tested \u2014 \u2014 \u2014 Windows 10 (32 bits) no \u2014 \u2014 \u2014 Windows 8.1 no end of life reached Windows 8 no end of life reached Windows 7 no end of life reached Windows Vista no end of life reached Windows XP no end of life reached", "title": "Supported versions"}, {"location": "cozy-device-helper/", "text": "Cozy Device Helper \u00b6 This library allows to know more information about the device platform API \u00b6 Platforms \u00b6 import { getPlatform , isWebApp , isMobileApp , isIOSApp , isAndroidApp , isFlagshipApp } from 'cozy-device-helper' To know the platform: isFlagshipApp() : return boolean if inside the flagship app. getPlatform() : return ios , android or web isWebApp() : return boolean isMobileApp() : return boolean . True if its a cordova App. False for others. isIOSApp() : return boolean . True if its a cordova App on iOS. isAndroidApp() : return boolean . True if its a cordova App on Android. isAndroid() : return boolean (check if the user is on an android smartphone (native & browser)) isOS() : return boolean (check if the user is on an iOS smartphone (native & browser)) isMobile() : return boolean (check if the user is on an android or iOS smartphone (native & browser)) Device Name \u00b6 import { getDeviceName } from 'cozy-device-helper' To know device name getDeviceName() . Cordova Plugins \u00b6 import { hasDevicePlugin , hasInAppBrowserPlugin , hasSafariPlugin , checkApp , startApp } from 'cozy-device-helper' hasDevicePlugin : return boolean hasInAppBrowserPlugin : return boolean hasSafariPlugin : return a promise which resolve by a boolean checkApp : return a promise that resolves with informations about the application (if installed) or false (if not installed) startApp : Start an Application. Return a promise - False if the application was not able to be started", "title": "Native devices (device-helper)"}, {"location": "cozy-device-helper/#cozy-device-helper", "text": "This library allows to know more information about the device platform", "title": "Cozy Device Helper"}, {"location": "cozy-device-helper/#api", "text": "", "title": "API"}, {"location": "cozy-device-helper/#platforms", "text": "import { getPlatform , isWebApp , isMobileApp , isIOSApp , isAndroidApp , isFlagshipApp } from 'cozy-device-helper' To know the platform: isFlagshipApp() : return boolean if inside the flagship app. getPlatform() : return ios , android or web isWebApp() : return boolean isMobileApp() : return boolean . True if its a cordova App. False for others. isIOSApp() : return boolean . True if its a cordova App on iOS. isAndroidApp() : return boolean . True if its a cordova App on Android. isAndroid() : return boolean (check if the user is on an android smartphone (native & browser)) isOS() : return boolean (check if the user is on an iOS smartphone (native & browser)) isMobile() : return boolean (check if the user is on an android or iOS smartphone (native & browser))", "title": "Platforms"}, {"location": "cozy-device-helper/#device-name", "text": "import { getDeviceName } from 'cozy-device-helper' To know device name getDeviceName() .", "title": "Device Name"}, {"location": "cozy-device-helper/#cordova-plugins", "text": "import { hasDevicePlugin , hasInAppBrowserPlugin , hasSafariPlugin , checkApp , startApp } from 'cozy-device-helper' hasDevicePlugin : return boolean hasInAppBrowserPlugin : return boolean hasSafariPlugin : return a promise which resolve by a boolean checkApp : return a promise that resolves with informations about the application (if installed) or false (if not installed) startApp : Start an Application. Return a promise - False if the application was not able to be started", "title": "Cordova Plugins"}, {"location": "cozy-device-helper/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 3.0.0 (2023-08-23) \u00b6 Features \u00b6 harvest: Update cozy-client from 38.6.0 to 40.2.0 ( 8931b15 ) BREAKING CHANGES \u00b6 harvest: you must have cozy-client >= 40.2.0 2.7.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 2.6.0 (2022-11-14) \u00b6 Features \u00b6 cozy-device-helper: Add biometry_authorisation_denied interface ( d6eb024 ) 2.5.0 (2022-10-03) \u00b6 Features \u00b6 Update device-helper interface ( ba87e8e ) 2.4.1 (2022-10-03) \u00b6 Note: Version bump only for package cozy-device-helper 2.4.0 (2022-09-12) \u00b6 Features \u00b6 Update FlagshipMetadata interface ( b82cf89 ) 2.3.0 (2022-09-06) \u00b6 Bug Fixes \u00b6 Use correct image size ( d290c39 ) Features \u00b6 Update FlagshipMetadata interface ( d8da519 ) 2.2.2 (2022-08-01) \u00b6 Note: Version bump only for package cozy-device-helper 2.2.1 (2022-06-24) \u00b6 Bug Fixes \u00b6 Make isFlagshipApp and getFlagshipMetadata work on node environment ( 636ad93 ) 2.2.0 (2022-06-03) \u00b6 Bug Fixes \u00b6 deps: update dependency @types/react-native to v0.67.7 ( e60dd0d ) Features \u00b6 harvest: HandleOAuthResponse can deal with cozy-data from DOM ( 7c6ac1a ) 2.1.0 (2022-05-10) \u00b6 Bug Fixes \u00b6 cozy-device-helper: Remove type import ( 401d654 ) Features \u00b6 Add name in attributes selected for buildFilesQueryByLabels ( d66c975 ) 2.0.0 (2022-04-28) \u00b6 Bug Fixes \u00b6 FlagshipMetadata is now a getter ( 11948ad ) BREAKING CHANGES \u00b6 flagshipMetadata reference has been replaced with getFlagshipMetadata(). It returns the same information but adds safety at file init 1.18.0 (2022-04-25) \u00b6 Features \u00b6 Add new flagship api file ( 1ef8b2d ) 1.17.0 (2022-02-04) \u00b6 Features \u00b6 Ensure isFlagshipApp returns a boolean value ( 78e7d82 ) 1.16.3 (2022-02-03) \u00b6 Bug Fixes \u00b6 deps: update dependency jest to v26.6.3 ( f442fff ) 1.16.2 (2022-02-01) \u00b6 Bug Fixes \u00b6 deps: update babel monorepo ( dcc215a ) 1.16.1 (2022-01-28) \u00b6 Bug Fixes \u00b6 Update device helper typings location ( d874d8f ) 1.16.0 (2022-01-07) \u00b6 Features \u00b6 Add types property in package.json ( 69f717b ) 1.15.0 (2022-01-06) \u00b6 Features \u00b6 Add a manual typescript declaration file ( cbdb01e ) 1.14.0 (2021-12-28) \u00b6 Features \u00b6 Add a check for flagship app in device-helper ( 20d6d99 ) 1.13.2 (2021-12-20) \u00b6 Note: Version bump only for package cozy-device-helper 1.13.1 (2021-12-02) \u00b6 Note: Version bump only for package cozy-device-helper 1.13.0 (2021-10-22) \u00b6 Features \u00b6 Remove drive from homeHref ( 97010d3 ) 1.12.0 (2021-02-12) \u00b6 Features \u00b6 Add finance theme ( bb8cf35 ) 1.11.0 (2020-11-23) \u00b6 Features \u00b6 All babel cli at 7.12.1 ( 387a24a ) Update @babel/core and babel-jest ( 352ddc3 ) Update jest ( 3b2c32a ) Use ^ for dependencies ( fc28de7 ) 1.10.3 (2020-10-01) \u00b6 Bug Fixes \u00b6 Lint issue ( aa10617 ) 1.10.2 (2020-09-15) \u00b6 Note: Version bump only for package cozy-device-helper 1.10.1 (2020-08-03) \u00b6 Note: Version bump only for package cozy-device-helper 1.10.0 (2020-07-16) \u00b6 Bug Fixes \u00b6 Call revokeSelf if not the owner of the sharing ( f7afc60 ) Features \u00b6 Update lodash accross all packages ( 6a20128 ) 1.9.2 (2020-02-27) \u00b6 Note: Version bump only for package cozy-device-helper 1.9.1 (2020-02-25) \u00b6 Note: Version bump only for package cozy-device-helper 1.9.0 (2020-02-24) \u00b6 Bug Fixes \u00b6 Correctly handle BI errors ( #934 ) ( bbed41d ) Features \u00b6 Checks for cordova\u2019s network info plugin ( 81e0e6b ) 1.8.0 (2019-09-05) \u00b6 Features \u00b6 Add account route ( 7986708 ) 1.7.5 (2019-07-19) \u00b6 Note: Version bump only for package cozy-device-helper 1.7.4 (2019-07-19) \u00b6 Note: Version bump only for package cozy-device-helper 1.7.3 (2019-07-11) \u00b6 Bug Fixes \u00b6 deps: Update dependency lodash to v4.17.13 [SECURITY] ( #648 ) ( 1b36dac ) 1.7.2 (2019-06-03) \u00b6 Bug Fixes \u00b6 HandleOpenURL on universalLink if MobileRouter does not manage it ( b8f5f55 ) device: Check if window in the globals ( 040347d ) 1.7.1 (2019-04-12) \u00b6 Bug Fixes \u00b6 cozy-device-helper: Don\u2019t deeplink on iOS 12_2 or 12_3 ( #377 ) ( b93aa2c ) 1.7.0 (2019-03-25) \u00b6 Features \u00b6 Add an utility to open or redirect for a deeplink ( #354 ) ( 6e1adfd ) 1.6.10 (2019-03-18) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.9 (2019-03-12) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.8 (2019-03-12) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.7 (2019-03-12) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.6 (2019-03-12) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.5 (2019-02-12) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.4 (2019-02-11) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.3 (2019-01-11) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.2 (2018-12-28) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.1 (2018-12-26) \u00b6 Note: Version bump only for package cozy-device-helper 1.6.0 (2018-12-18) \u00b6 Features \u00b6 Add an nativeLinkOpen helper ( f894c43 ) 1.5.2 (2018-12-17) \u00b6 Note: Version bump only for package cozy-device-helper 1.5.1 (2018-12-10) \u00b6 Note: Version bump only for package cozy-device-helper 1.5.0 (2018-12-04) \u00b6 Features \u00b6 device-helper: Add functions to test android or iOS smartphone ( e1553aa ) 1.4.14 (2018-10-09) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.13 (2018-10-02) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.12 (2018-09-27) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.11 (2018-09-25) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.10 (2018-09-25) \u00b6 Bug Fixes \u00b6 add babel-core bridge for v7 ( 18665a8 ), closes /github.com/babel/babel/issues/8206#issuecomment-419705758 use ^7.1.0 for babel-jest issue ( 34b2d14 ) 1.4.9 (2018-09-25) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.8 (2018-09-21) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.7 (2018-08-30) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.6 (2018-08-22) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.5 (2018-08-09) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.4 (2018-08-08) \u00b6 Bug Fixes \u00b6 do not remove dist from npm ( 3542540 ) 1.4.3 (2018-08-08) \u00b6 Bug Fixes \u00b6 do not remove dist from npm ( 28a1373 ) 1.4.2 (2018-08-08) \u00b6 Bug Fixes \u00b6 correctly export functions ( 2cc9e2f ) plugin reference ( 59fd756 ) remove global variable ( 7b8120c ) 1.4.1 (2018-08-08) \u00b6 Note: Version bump only for package cozy-device-helper 1.4.0 (2018-08-08) \u00b6 1.3.0-beta.4 (2018-08-07) \u00b6 Bug Fixes \u00b6 lodash dependency \ud83d\udc1b ( ec507e2 ) mistack word \ud83d\udc1b ( f6c0c2a ) transpile all files ( 7ee2cb7 ) Features \u00b6 Add cordova plugin detection \ud83e\udd16 ( 30498e0 ) Add cozy-device-helper \u260e\ufe0f ( 4420e6b ) Add hasSafariPlugin HOC \ud83d\udce1 ( 5403acc ) add helpers to start applications ( b90e1bf ) Export getPlatform \u2728 ( f8c2953 )", "title": "Change Log"}, {"location": "cozy-device-helper/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "cozy-device-helper/CHANGELOG/#300-2023-08-23", "text": "", "title": "3.0.0 (2023-08-23)"}, {"location": "cozy-device-helper/CHANGELOG/#features", "text": "harvest: Update cozy-client from 38.6.0 to 40.2.0 ( 8931b15 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#breaking-changes", "text": "harvest: you must have cozy-client >= 40.2.0", "title": "BREAKING CHANGES"}, {"location": "cozy-device-helper/CHANGELOG/#270-2023-01-31", "text": "", "title": "2.7.0 (2023-01-31)"}, {"location": "cozy-device-helper/CHANGELOG/#features_1", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#260-2022-11-14", "text": "", "title": "2.6.0 (2022-11-14)"}, {"location": "cozy-device-helper/CHANGELOG/#features_2", "text": "cozy-device-helper: Add biometry_authorisation_denied interface ( d6eb024 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#250-2022-10-03", "text": "", "title": "2.5.0 (2022-10-03)"}, {"location": "cozy-device-helper/CHANGELOG/#features_3", "text": "Update device-helper interface ( ba87e8e )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#241-2022-10-03", "text": "Note: Version bump only for package cozy-device-helper", "title": "2.4.1 (2022-10-03)"}, {"location": "cozy-device-helper/CHANGELOG/#240-2022-09-12", "text": "", "title": "2.4.0 (2022-09-12)"}, {"location": "cozy-device-helper/CHANGELOG/#features_4", "text": "Update FlagshipMetadata interface ( b82cf89 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#230-2022-09-06", "text": "", "title": "2.3.0 (2022-09-06)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes", "text": "Use correct image size ( d290c39 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#features_5", "text": "Update FlagshipMetadata interface ( d8da519 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#222-2022-08-01", "text": "Note: Version bump only for package cozy-device-helper", "title": "2.2.2 (2022-08-01)"}, {"location": "cozy-device-helper/CHANGELOG/#221-2022-06-24", "text": "", "title": "2.2.1 (2022-06-24)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_1", "text": "Make isFlagshipApp and getFlagshipMetadata work on node environment ( 636ad93 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#220-2022-06-03", "text": "", "title": "2.2.0 (2022-06-03)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_2", "text": "deps: update dependency @types/react-native to v0.67.7 ( e60dd0d )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#features_6", "text": "harvest: HandleOAuthResponse can deal with cozy-data from DOM ( 7c6ac1a )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#210-2022-05-10", "text": "", "title": "2.1.0 (2022-05-10)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_3", "text": "cozy-device-helper: Remove type import ( 401d654 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#features_7", "text": "Add name in attributes selected for buildFilesQueryByLabels ( d66c975 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#200-2022-04-28", "text": "", "title": "2.0.0 (2022-04-28)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_4", "text": "FlagshipMetadata is now a getter ( 11948ad )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#breaking-changes_1", "text": "flagshipMetadata reference has been replaced with getFlagshipMetadata(). It returns the same information but adds safety at file init", "title": "BREAKING CHANGES"}, {"location": "cozy-device-helper/CHANGELOG/#1180-2022-04-25", "text": "", "title": "1.18.0 (2022-04-25)"}, {"location": "cozy-device-helper/CHANGELOG/#features_8", "text": "Add new flagship api file ( 1ef8b2d )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1170-2022-02-04", "text": "", "title": "1.17.0 (2022-02-04)"}, {"location": "cozy-device-helper/CHANGELOG/#features_9", "text": "Ensure isFlagshipApp returns a boolean value ( 78e7d82 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1163-2022-02-03", "text": "", "title": "1.16.3 (2022-02-03)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_5", "text": "deps: update dependency jest to v26.6.3 ( f442fff )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#1162-2022-02-01", "text": "", "title": "1.16.2 (2022-02-01)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_6", "text": "deps: update babel monorepo ( dcc215a )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#1161-2022-01-28", "text": "", "title": "1.16.1 (2022-01-28)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_7", "text": "Update device helper typings location ( d874d8f )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#1160-2022-01-07", "text": "", "title": "1.16.0 (2022-01-07)"}, {"location": "cozy-device-helper/CHANGELOG/#features_10", "text": "Add types property in package.json ( 69f717b )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1150-2022-01-06", "text": "", "title": "1.15.0 (2022-01-06)"}, {"location": "cozy-device-helper/CHANGELOG/#features_11", "text": "Add a manual typescript declaration file ( cbdb01e )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1140-2021-12-28", "text": "", "title": "1.14.0 (2021-12-28)"}, {"location": "cozy-device-helper/CHANGELOG/#features_12", "text": "Add a check for flagship app in device-helper ( 20d6d99 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1132-2021-12-20", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.13.2 (2021-12-20)"}, {"location": "cozy-device-helper/CHANGELOG/#1131-2021-12-02", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.13.1 (2021-12-02)"}, {"location": "cozy-device-helper/CHANGELOG/#1130-2021-10-22", "text": "", "title": "1.13.0 (2021-10-22)"}, {"location": "cozy-device-helper/CHANGELOG/#features_13", "text": "Remove drive from homeHref ( 97010d3 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1120-2021-02-12", "text": "", "title": "1.12.0 (2021-02-12)"}, {"location": "cozy-device-helper/CHANGELOG/#features_14", "text": "Add finance theme ( bb8cf35 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1110-2020-11-23", "text": "", "title": "1.11.0 (2020-11-23)"}, {"location": "cozy-device-helper/CHANGELOG/#features_15", "text": "All babel cli at 7.12.1 ( 387a24a ) Update @babel/core and babel-jest ( 352ddc3 ) Update jest ( 3b2c32a ) Use ^ for dependencies ( fc28de7 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1103-2020-10-01", "text": "", "title": "1.10.3 (2020-10-01)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_8", "text": "Lint issue ( aa10617 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#1102-2020-09-15", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.10.2 (2020-09-15)"}, {"location": "cozy-device-helper/CHANGELOG/#1101-2020-08-03", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.10.1 (2020-08-03)"}, {"location": "cozy-device-helper/CHANGELOG/#1100-2020-07-16", "text": "", "title": "1.10.0 (2020-07-16)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_9", "text": "Call revokeSelf if not the owner of the sharing ( f7afc60 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#features_16", "text": "Update lodash accross all packages ( 6a20128 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#192-2020-02-27", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.9.2 (2020-02-27)"}, {"location": "cozy-device-helper/CHANGELOG/#191-2020-02-25", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.9.1 (2020-02-25)"}, {"location": "cozy-device-helper/CHANGELOG/#190-2020-02-24", "text": "", "title": "1.9.0 (2020-02-24)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_10", "text": "Correctly handle BI errors ( #934 ) ( bbed41d )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#features_17", "text": "Checks for cordova\u2019s network info plugin ( 81e0e6b )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#180-2019-09-05", "text": "", "title": "1.8.0 (2019-09-05)"}, {"location": "cozy-device-helper/CHANGELOG/#features_18", "text": "Add account route ( 7986708 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#175-2019-07-19", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.7.5 (2019-07-19)"}, {"location": "cozy-device-helper/CHANGELOG/#174-2019-07-19", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.7.4 (2019-07-19)"}, {"location": "cozy-device-helper/CHANGELOG/#173-2019-07-11", "text": "", "title": "1.7.3 (2019-07-11)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_11", "text": "deps: Update dependency lodash to v4.17.13 [SECURITY] ( #648 ) ( 1b36dac )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#172-2019-06-03", "text": "", "title": "1.7.2 (2019-06-03)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_12", "text": "HandleOpenURL on universalLink if MobileRouter does not manage it ( b8f5f55 ) device: Check if window in the globals ( 040347d )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#171-2019-04-12", "text": "", "title": "1.7.1 (2019-04-12)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_13", "text": "cozy-device-helper: Don\u2019t deeplink on iOS 12_2 or 12_3 ( #377 ) ( b93aa2c )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#170-2019-03-25", "text": "", "title": "1.7.0 (2019-03-25)"}, {"location": "cozy-device-helper/CHANGELOG/#features_19", "text": "Add an utility to open or redirect for a deeplink ( #354 ) ( 6e1adfd )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1610-2019-03-18", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.10 (2019-03-18)"}, {"location": "cozy-device-helper/CHANGELOG/#169-2019-03-12", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.9 (2019-03-12)"}, {"location": "cozy-device-helper/CHANGELOG/#168-2019-03-12", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.8 (2019-03-12)"}, {"location": "cozy-device-helper/CHANGELOG/#167-2019-03-12", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.7 (2019-03-12)"}, {"location": "cozy-device-helper/CHANGELOG/#166-2019-03-12", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.6 (2019-03-12)"}, {"location": "cozy-device-helper/CHANGELOG/#165-2019-02-12", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.5 (2019-02-12)"}, {"location": "cozy-device-helper/CHANGELOG/#164-2019-02-11", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.4 (2019-02-11)"}, {"location": "cozy-device-helper/CHANGELOG/#163-2019-01-11", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.3 (2019-01-11)"}, {"location": "cozy-device-helper/CHANGELOG/#162-2018-12-28", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.2 (2018-12-28)"}, {"location": "cozy-device-helper/CHANGELOG/#161-2018-12-26", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.6.1 (2018-12-26)"}, {"location": "cozy-device-helper/CHANGELOG/#160-2018-12-18", "text": "", "title": "1.6.0 (2018-12-18)"}, {"location": "cozy-device-helper/CHANGELOG/#features_20", "text": "Add an nativeLinkOpen helper ( f894c43 )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#152-2018-12-17", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.5.2 (2018-12-17)"}, {"location": "cozy-device-helper/CHANGELOG/#151-2018-12-10", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.5.1 (2018-12-10)"}, {"location": "cozy-device-helper/CHANGELOG/#150-2018-12-04", "text": "", "title": "1.5.0 (2018-12-04)"}, {"location": "cozy-device-helper/CHANGELOG/#features_21", "text": "device-helper: Add functions to test android or iOS smartphone ( e1553aa )", "title": "Features"}, {"location": "cozy-device-helper/CHANGELOG/#1414-2018-10-09", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.14 (2018-10-09)"}, {"location": "cozy-device-helper/CHANGELOG/#1413-2018-10-02", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.13 (2018-10-02)"}, {"location": "cozy-device-helper/CHANGELOG/#1412-2018-09-27", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.12 (2018-09-27)"}, {"location": "cozy-device-helper/CHANGELOG/#1411-2018-09-25", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.11 (2018-09-25)"}, {"location": "cozy-device-helper/CHANGELOG/#1410-2018-09-25", "text": "", "title": "1.4.10 (2018-09-25)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_14", "text": "add babel-core bridge for v7 ( 18665a8 ), closes /github.com/babel/babel/issues/8206#issuecomment-419705758 use ^7.1.0 for babel-jest issue ( 34b2d14 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#149-2018-09-25", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.9 (2018-09-25)"}, {"location": "cozy-device-helper/CHANGELOG/#148-2018-09-21", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.8 (2018-09-21)"}, {"location": "cozy-device-helper/CHANGELOG/#147-2018-08-30", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.7 (2018-08-30)"}, {"location": "cozy-device-helper/CHANGELOG/#146-2018-08-22", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.6 (2018-08-22)"}, {"location": "cozy-device-helper/CHANGELOG/#145-2018-08-09", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.5 (2018-08-09)"}, {"location": "cozy-device-helper/CHANGELOG/#144-2018-08-08", "text": "", "title": "1.4.4 (2018-08-08)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_15", "text": "do not remove dist from npm ( 3542540 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#143-2018-08-08", "text": "", "title": "1.4.3 (2018-08-08)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_16", "text": "do not remove dist from npm ( 28a1373 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#142-2018-08-08", "text": "", "title": "1.4.2 (2018-08-08)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_17", "text": "correctly export functions ( 2cc9e2f ) plugin reference ( 59fd756 ) remove global variable ( 7b8120c )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#141-2018-08-08", "text": "Note: Version bump only for package cozy-device-helper", "title": "1.4.1 (2018-08-08)"}, {"location": "cozy-device-helper/CHANGELOG/#140-2018-08-08", "text": "", "title": "1.4.0 (2018-08-08)"}, {"location": "cozy-device-helper/CHANGELOG/#130-beta4-2018-08-07", "text": "", "title": "1.3.0-beta.4 (2018-08-07)"}, {"location": "cozy-device-helper/CHANGELOG/#bug-fixes_18", "text": "lodash dependency \ud83d\udc1b ( ec507e2 ) mistack word \ud83d\udc1b ( f6c0c2a ) transpile all files ( 7ee2cb7 )", "title": "Bug Fixes"}, {"location": "cozy-device-helper/CHANGELOG/#features_22", "text": "Add cordova plugin detection \ud83e\udd16 ( 30498e0 ) Add cozy-device-helper \u260e\ufe0f ( 4420e6b ) Add hasSafariPlugin HOC \ud83d\udce1 ( 5403acc ) add helpers to start applications ( b90e1bf ) Export getPlatform \u2728 ( f8c2953 )", "title": "Features"}, {"location": "cozy-doctypes/pull_request_template/", "text": "Thanks for contributing to this documentation. If you added a doctype, please be sure that it is present [ ] in the Readme.md index page [ ] in the toc.yml page [ ] https://github.com/cozy/cozy-store/blob/master/src/locales/en.json [ ] https://github.com/cozy/cozy-store/blob/master/src/config/permissionsIcons.json [ ] https://github.com/cozy/cozy-store/tree/master/src/assets/icons/permissions [ ] https://github.com/cozy/cozy-client/tree/master/packages/cozy-client/src/models/doctypes/locales [ ] https://github.com/cozy/cozy-stack/blob/master/assets/locales/en.po [ ] https://github.com/cozy/cozy-stack/blob/master/assets/styles/cirrus.css", "title": "Pull request template"}, {"location": "cozy-doctypes/docs/", "text": "Doctypes \u00b6 Doctypes represent different types of data. Their primary use is for permissions: an app or konnector will request permissions for one or several doctypes and will not be able to access other doctypes. Note Example: A banking application requests permissions for banking doctypes ( io.cozy.bank.accounts , io.cozy.bank.operations etc..) but cannot access files ( io.cozy.files ). This ensure the segregation and security of your data. In this repository, every (known) doctype and the fields that they contain is described. If you feel the need for another doctype, feel free to open a PR with the description and role of your doctype. Cozy doctypes \u00b6 io.cozy.accounts : Konnector accounts io.cozy.apps : Apps installed in the Cozy io.cozy.apps.suggestions : Suggestions for apps that the user might find useful io.cozy.bank : Banking related data io.cozy.bank.settings : Bank application settings io.cozy.bank.accounts : Bank accounts io.cozy.bank.accounts.stats : Aggregated data about bank accounts io.cozy.bank.operations : Bank transaction io.cozy.bank.balancehistories : Daily balances io.cozy.bank.recurrence : Recurrence group information io.cozy.bank.groups : Group of bank accounts io.cozy.bank.recipients : Recipients for transfert io.cozy.bills : Bills io.cozy.coachco2.settings : CoachCO2 application settings io.cozy.contacts : Contacts io.cozy.contacts.groups : Contacts groups io.cozy.contacts.accounts : Vendors account io.cozy.files : Files Files_metadatas : Metadatas about files io.cozy.files.settings : Files settings io.cozy.files.encryption : Files encryption io.cozy.home.settings : Home settings io.cozy.konnectors : Connectors installed in the cozy io.cozy.identities : Instance owner identities io.cozy.notes : Notes with collaborative edition io.cozy.notes.steps io.cozy.notes.events io.cozy.notes.images io.cozy.notifications : Notifications made by the apps (Email or Push notifications) io.cozy.permissions : Permissions of the instance io.cozy.photos : Photos io.cozy.photos.settings : Photos settings io.cozy.procedures : Administrative procedures io.cozy.docrules : Rules to retrieve documents io.cozy.remote.nextcloud.files : Files on a remote NextCloud (via WebDAV) io.cozy.sessions.logins : Sessions logins entry io.cozy.settings : Instance settings io.cozy.sharings : Documents used for Cozy to Cozy sharings io.cozy.tags : Tags io.cozy.timeseries : Time Series io.cozy.timeseries.geojson : GeoJSON time series io.cozy.todos : Todos io.cozy.todos.list : Todos list io.cozy.todos.item : Todos item Technical doctypes \u00b6 Accounts Types: io.cozy.account_types : OAuth informations and secrets for apps & konnectors cc.cozycloud.autocategorization : Auto categorization remote doctype io.cozy.exports : Instances exports io.cozy.jobs : Instance jobs io.cozy.oauth.clients : OAuth clients informations of the stack io.cozy.oauth.access_codes : Access codes specific to OAuth flow io.cozy.triggers : Job triggers io.cozy.triggers.state : Job triggers states io.cozy.remote.requests : logs of requests via the remote doctypes io.cozy.sessions : cozy-stack sessions io.cozy.shared : cozy-stack doctype for sharings io.cozy.terms : Contains terms of services the user has signed Remote doctypes \u00b6 This repository is where the declaration of remote doctypes is done. Read more about remote doctypes in the cozy stack repository . External doctypes \u00b6 com.bitwarden.ciphers : Ciphers for bitwarden clients com.bitwarden.folders : Folders for bitwarden clients com.unibet.bets : Bets from Unibet website Generic model \u00b6 Relationships \u00b6 Relations between documents are under a relationships object at the root of the document. Relations are referenced by their names. Each relation is an object with a data property containing either null , one reference or an array of references. A reference is an object containing at least a _type with the name of the referenced doctype and an _id with the id of the referenced document inside its doctype. { \"_id\" : \"mobydick\" , \"relationships\" : { \"authors\" : { \"data\" : [{ \"_id\" : \"hermanmelville\" , \"_type\" : \"io.cozy.contacts\" }] } } } External relationships \u00b6 Relationships that reference a document that lives outside the couchdb of the user will have a _type in a different namespace than io.cozy.* , and will have an additional _protocol field. At the moment the only available external relationship is bitwarden with the following format: { \"_id\" : \"secretsafe\" , \"relationships\" : { \"vaultCipher\" : { \"data\" : [{ \"_id\" : \"123abc\" , \"_type\" : \"com.bitwarden.ciphers\" , \"_protocol\" : \"bitwarden\" }] } } } Relationships with metadata \u00b6 A relationship can store additional information, in the metadata attribute. For instance, see the contracts relationship for the accounts. \"relationships\" : { \"contracts\" : { \"data\" : [ { \"_id\" : \"77b662b903f1bac7a78cf8cc12806479\" , \"_type\" : \"io.cozy.bank.accounts\" , \"metadata\" : { \"deletedByVendor\" : false , \"imported\" : true , \"label\" : \"Compte ch\u00e8que\" , \"vendorId\" : \"1337\" } } ] } } Document metadata \u00b6 We distinguish three levels of attributes: The data (e.g. a list of songs from a playlist) The metadata about the data (e.g. the creation date of the playlist itself) The metadata of the cozy document (e.g. the creation date of the cozy document describing the playlist). The third level is described by an object named cozyMetadata at the root of the document. The expected cozyMetadata attributes are the following: doctypeVersion : Name or identifier for the version of the schema used by this document (ie: doctypeVersion: 2 for \u201cThis document conforms to io.cozy.contacts in its version 2\u201d) metadataVersion : Version of the cozyMetadata createdAt : Creation date of the cozy document createdByApp : Slug of the app or connector which created the document createdByAppVersion : Version identifier of the app updatedAt : Last modification date of the cozy document updatedByApps : List of objects representing the applications (slugs and versions) which modified the cozy document in its life and the last update date for each of those apps (one entry per slug, apps should just update the value) sourceAccount : When the document was imported from a connector, identifier of the account in io.cozy.accounts sourceAccountIdentifier : When the document was imported from a connector, identifier of the account on targeted web service (the email address most of the time) \u2139\ufe0f All these attributes are optional and taken care by the apps modifying the document. Unless specified otherwise in the documentation of the doctype, all these attributes may not be present or may have a null value. \u2139\ufe0f For doctypes protected by the stack such as io.cozy.files , any non-expected attribute in cozyMetadata will be refused by the stack. { \"_id\" : \"xxxx\" , \"cozyMetadata\" : { \"doctypeVersion\" : 4 , \"metadataVersion\" : 1 , \"createdAt\" : \"xxxxx\" , \"createdByApp\" : \"xxxx\" , \"createdByAppVersion\" : \"xxxx\" , \"updatedAt\" : \"xxxxx\" , \"updatedByApps\" : [ { \"slug\" : \"xxxxx\" , \"date\" : \"xxxxx\" , \"version\" : 3 } ], \"sourceAccount\" : \"xxxxx\" , \"sourceAccountIdentifier\" : \"test@mail.fr\" } } Date format \u00b6 Date should be formatted in ISO8601 : 2017-04-22T01:00:00-05:00 \u2705 2017-04-22T01:00:00Z \u2705 2017-04-22 \u2705 2017-04-22 01:00 \u274c", "title": "README"}, {"location": "cozy-doctypes/docs/#doctypes", "text": "Doctypes represent different types of data. Their primary use is for permissions: an app or konnector will request permissions for one or several doctypes and will not be able to access other doctypes. Note Example: A banking application requests permissions for banking doctypes ( io.cozy.bank.accounts , io.cozy.bank.operations etc..) but cannot access files ( io.cozy.files ). This ensure the segregation and security of your data. In this repository, every (known) doctype and the fields that they contain is described. If you feel the need for another doctype, feel free to open a PR with the description and role of your doctype.", "title": "Doctypes"}, {"location": "cozy-doctypes/docs/#cozy-doctypes", "text": "io.cozy.accounts : Konnector accounts io.cozy.apps : Apps installed in the Cozy io.cozy.apps.suggestions : Suggestions for apps that the user might find useful io.cozy.bank : Banking related data io.cozy.bank.settings : Bank application settings io.cozy.bank.accounts : Bank accounts io.cozy.bank.accounts.stats : Aggregated data about bank accounts io.cozy.bank.operations : Bank transaction io.cozy.bank.balancehistories : Daily balances io.cozy.bank.recurrence : Recurrence group information io.cozy.bank.groups : Group of bank accounts io.cozy.bank.recipients : Recipients for transfert io.cozy.bills : Bills io.cozy.coachco2.settings : CoachCO2 application settings io.cozy.contacts : Contacts io.cozy.contacts.groups : Contacts groups io.cozy.contacts.accounts : Vendors account io.cozy.files : Files Files_metadatas : Metadatas about files io.cozy.files.settings : Files settings io.cozy.files.encryption : Files encryption io.cozy.home.settings : Home settings io.cozy.konnectors : Connectors installed in the cozy io.cozy.identities : Instance owner identities io.cozy.notes : Notes with collaborative edition io.cozy.notes.steps io.cozy.notes.events io.cozy.notes.images io.cozy.notifications : Notifications made by the apps (Email or Push notifications) io.cozy.permissions : Permissions of the instance io.cozy.photos : Photos io.cozy.photos.settings : Photos settings io.cozy.procedures : Administrative procedures io.cozy.docrules : Rules to retrieve documents io.cozy.remote.nextcloud.files : Files on a remote NextCloud (via WebDAV) io.cozy.sessions.logins : Sessions logins entry io.cozy.settings : Instance settings io.cozy.sharings : Documents used for Cozy to Cozy sharings io.cozy.tags : Tags io.cozy.timeseries : Time Series io.cozy.timeseries.geojson : GeoJSON time series io.cozy.todos : Todos io.cozy.todos.list : Todos list io.cozy.todos.item : Todos item", "title": "Cozy doctypes"}, {"location": "cozy-doctypes/docs/#technical-doctypes", "text": "Accounts Types: io.cozy.account_types : OAuth informations and secrets for apps & konnectors cc.cozycloud.autocategorization : Auto categorization remote doctype io.cozy.exports : Instances exports io.cozy.jobs : Instance jobs io.cozy.oauth.clients : OAuth clients informations of the stack io.cozy.oauth.access_codes : Access codes specific to OAuth flow io.cozy.triggers : Job triggers io.cozy.triggers.state : Job triggers states io.cozy.remote.requests : logs of requests via the remote doctypes io.cozy.sessions : cozy-stack sessions io.cozy.shared : cozy-stack doctype for sharings io.cozy.terms : Contains terms of services the user has signed", "title": "Technical doctypes"}, {"location": "cozy-doctypes/docs/#remote-doctypes", "text": "This repository is where the declaration of remote doctypes is done. Read more about remote doctypes in the cozy stack repository .", "title": "Remote doctypes"}, {"location": "cozy-doctypes/docs/#external-doctypes", "text": "com.bitwarden.ciphers : Ciphers for bitwarden clients com.bitwarden.folders : Folders for bitwarden clients com.unibet.bets : Bets from Unibet website", "title": "External doctypes"}, {"location": "cozy-doctypes/docs/#generic-model", "text": "", "title": "Generic model"}, {"location": "cozy-doctypes/docs/#relationships", "text": "Relations between documents are under a relationships object at the root of the document. Relations are referenced by their names. Each relation is an object with a data property containing either null , one reference or an array of references. A reference is an object containing at least a _type with the name of the referenced doctype and an _id with the id of the referenced document inside its doctype. { \"_id\" : \"mobydick\" , \"relationships\" : { \"authors\" : { \"data\" : [{ \"_id\" : \"hermanmelville\" , \"_type\" : \"io.cozy.contacts\" }] } } }", "title": "Relationships"}, {"location": "cozy-doctypes/docs/#external-relationships", "text": "Relationships that reference a document that lives outside the couchdb of the user will have a _type in a different namespace than io.cozy.* , and will have an additional _protocol field. At the moment the only available external relationship is bitwarden with the following format: { \"_id\" : \"secretsafe\" , \"relationships\" : { \"vaultCipher\" : { \"data\" : [{ \"_id\" : \"123abc\" , \"_type\" : \"com.bitwarden.ciphers\" , \"_protocol\" : \"bitwarden\" }] } } }", "title": "External relationships"}, {"location": "cozy-doctypes/docs/#relationships-with-metadata", "text": "A relationship can store additional information, in the metadata attribute. For instance, see the contracts relationship for the accounts. \"relationships\" : { \"contracts\" : { \"data\" : [ { \"_id\" : \"77b662b903f1bac7a78cf8cc12806479\" , \"_type\" : \"io.cozy.bank.accounts\" , \"metadata\" : { \"deletedByVendor\" : false , \"imported\" : true , \"label\" : \"Compte ch\u00e8que\" , \"vendorId\" : \"1337\" } } ] } }", "title": "Relationships with metadata"}, {"location": "cozy-doctypes/docs/#document-metadata", "text": "We distinguish three levels of attributes: The data (e.g. a list of songs from a playlist) The metadata about the data (e.g. the creation date of the playlist itself) The metadata of the cozy document (e.g. the creation date of the cozy document describing the playlist). The third level is described by an object named cozyMetadata at the root of the document. The expected cozyMetadata attributes are the following: doctypeVersion : Name or identifier for the version of the schema used by this document (ie: doctypeVersion: 2 for \u201cThis document conforms to io.cozy.contacts in its version 2\u201d) metadataVersion : Version of the cozyMetadata createdAt : Creation date of the cozy document createdByApp : Slug of the app or connector which created the document createdByAppVersion : Version identifier of the app updatedAt : Last modification date of the cozy document updatedByApps : List of objects representing the applications (slugs and versions) which modified the cozy document in its life and the last update date for each of those apps (one entry per slug, apps should just update the value) sourceAccount : When the document was imported from a connector, identifier of the account in io.cozy.accounts sourceAccountIdentifier : When the document was imported from a connector, identifier of the account on targeted web service (the email address most of the time) \u2139\ufe0f All these attributes are optional and taken care by the apps modifying the document. Unless specified otherwise in the documentation of the doctype, all these attributes may not be present or may have a null value. \u2139\ufe0f For doctypes protected by the stack such as io.cozy.files , any non-expected attribute in cozyMetadata will be refused by the stack. { \"_id\" : \"xxxx\" , \"cozyMetadata\" : { \"doctypeVersion\" : 4 , \"metadataVersion\" : 1 , \"createdAt\" : \"xxxxx\" , \"createdByApp\" : \"xxxx\" , \"createdByAppVersion\" : \"xxxx\" , \"updatedAt\" : \"xxxxx\" , \"updatedByApps\" : [ { \"slug\" : \"xxxxx\" , \"date\" : \"xxxxx\" , \"version\" : 3 } ], \"sourceAccount\" : \"xxxxx\" , \"sourceAccountIdentifier\" : \"test@mail.fr\" } }", "title": "Document metadata"}, {"location": "cozy-doctypes/docs/#date-format", "text": "Date should be formatted in ISO8601 : 2017-04-22T01:00:00-05:00 \u2705 2017-04-22T01:00:00Z \u2705 2017-04-22 \u2705 2017-04-22 01:00 \u274c", "title": "Date format"}, {"location": "cozy-doctypes/docs/cc.cozycloud.autocategorization/", "text": "Table of contents Auto categorization remote doctype \u00b6 The cc.cozycloud.autocategorization remote doctype is used to anonymously and securely send the user\u2019s bank transactions to an API when he/she enabled the corresponding setting in the Banks app. cc.cozycloud.autocategorization sends an array of io.cozy.bank.operations , but removes some properties to anonymize the data. The following properties are kept: amount date label automaticCategoryId manualCategoryId cozyCategoryId cozyCategoryProba localCategoryId localCategoryProba", "title": "Autocategorization"}, {"location": "cozy-doctypes/docs/cc.cozycloud.autocategorization/#auto-categorization-remote-doctype", "text": "The cc.cozycloud.autocategorization remote doctype is used to anonymously and securely send the user\u2019s bank transactions to an API when he/she enabled the corresponding setting in the Banks app. cc.cozycloud.autocategorization sends an array of io.cozy.bank.operations , but removes some properties to anonymize the data. The following properties are kept: amount date label automaticCategoryId manualCategoryId cozyCategoryId cozyCategoryProba localCategoryId localCategoryProba", "title": "Auto categorization remote doctype"}, {"location": "cozy-doctypes/docs/com.bitwarden.ciphers/", "text": "Table of contents Bitwarden ciphers \u00b6 The com.bitwarden.ciphers doctype is used to store secret things for the bitwarden clients . There are 4 types of ciphers: Login Secure note Card Identity Attributes \u00b6 type : {int} - from 1 for login to 4 for identity (see the list above) shared_with_cozy : {bool} - true if the cipher is in the cozy organization favorite : {bool} - true if the cipher has been marked as a favorite in a client name : {string} - the name of the cipher, encrypted as a cipherString with AES notes : {string} - some notes about the cipher, encrypted folder_id : {string} - the identifier of a bitwarden folder login : {object} - an object only used when type is 1 (see below) data : {object} - a map of encrypted properties on the cipher fields : {array} - a list of objects, with type , name , and value (encrypted) organization_id : {uuid} - the identifier of a bitwarden organization collection_id : {uuid} - the identifier of the collection (see bitwarden organization ) cozyMetadata : {object} - the cozyMetadata deletedDate : {string} - the soft deletion date of the cipher. It is used to trash ciphers. Logins \u00b6 When the cipher has type 1 (login), the login is an object with these fields: uris : {array} - an array of uri (an encrypted string) and match ( null or a number) username : {string} - the encrypted username/login/identifier password : {string} - the encrypted password passwordRevisionDate : {date} - the last time the password was changed totp : {string} - the encrypted information about the second factor (2FA) Example \u00b6 { \"_id\" : \"44907c0262681483ab53e944fa077496\" , \"_rev\" : \"1-ded69b8f2b34ba6095f7637868453138\" , \"type\" : 1 , \"shared_with_cozy\" : false , \"name\" : \"2.ygPX4ld50/Z2kEjdEWvhHg==|1nxqZVBUcnMk9bxzQDJyqQ==|HRjAlp45dJ2RBRBGY6yvDvZseOD49oimuUU5y12MuHk=\" , \"login\" : { \"uris\" : [ { \"uri\" : \"2.DNrdKV2iNY+RtJbqFnPu7Q==|vhIZA5pXFngJRCnZlYjTmQV0ybQdJ6lNzt1CoTauwVI=|PiDEUFpvEaJtrKADSnyuqALajPHnDmfQsiDLEqF+3YY=\" } ], \"username\" : \"2.+uazyy7smAtIToJfqcS8yw==|IhmkZ0OHV+kX7txsPsSztA==|tDc1Zgknyl/JMn/O44hWZBaywSsHGeRGvK7ffEr5SdM=\" , \"password\" : \"2.L+41A7ch4GypwrIFXG5vkA==|S3eFnoNtk1IpsT4gcfcNrw==|lqdBTpSHKqTJtgBBXBXqm2K249AF1gZMec4cFf5gqR0=\" }, \"fields\" : null , \"organization_id\" : \"8869e3ee461551cc2bc4d5d9a107dbf9\" , \"collection_id\" : \"8869e3ee461551cc2bc4d5d9a107d0c1\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-09-24T15:48:19.55593719+02:00\" , \"updatedAt\" : \"2019-09-24T15:48:19.55593719+02:00\" } }", "title": "Bitwarden ciphers"}, {"location": "cozy-doctypes/docs/com.bitwarden.ciphers/#bitwarden-ciphers", "text": "The com.bitwarden.ciphers doctype is used to store secret things for the bitwarden clients . There are 4 types of ciphers: Login Secure note Card Identity", "title": "Bitwarden ciphers"}, {"location": "cozy-doctypes/docs/com.bitwarden.ciphers/#attributes", "text": "type : {int} - from 1 for login to 4 for identity (see the list above) shared_with_cozy : {bool} - true if the cipher is in the cozy organization favorite : {bool} - true if the cipher has been marked as a favorite in a client name : {string} - the name of the cipher, encrypted as a cipherString with AES notes : {string} - some notes about the cipher, encrypted folder_id : {string} - the identifier of a bitwarden folder login : {object} - an object only used when type is 1 (see below) data : {object} - a map of encrypted properties on the cipher fields : {array} - a list of objects, with type , name , and value (encrypted) organization_id : {uuid} - the identifier of a bitwarden organization collection_id : {uuid} - the identifier of the collection (see bitwarden organization ) cozyMetadata : {object} - the cozyMetadata deletedDate : {string} - the soft deletion date of the cipher. It is used to trash ciphers.", "title": "Attributes"}, {"location": "cozy-doctypes/docs/com.bitwarden.ciphers/#logins", "text": "When the cipher has type 1 (login), the login is an object with these fields: uris : {array} - an array of uri (an encrypted string) and match ( null or a number) username : {string} - the encrypted username/login/identifier password : {string} - the encrypted password passwordRevisionDate : {date} - the last time the password was changed totp : {string} - the encrypted information about the second factor (2FA)", "title": "Logins"}, {"location": "cozy-doctypes/docs/com.bitwarden.ciphers/#example", "text": "{ \"_id\" : \"44907c0262681483ab53e944fa077496\" , \"_rev\" : \"1-ded69b8f2b34ba6095f7637868453138\" , \"type\" : 1 , \"shared_with_cozy\" : false , \"name\" : \"2.ygPX4ld50/Z2kEjdEWvhHg==|1nxqZVBUcnMk9bxzQDJyqQ==|HRjAlp45dJ2RBRBGY6yvDvZseOD49oimuUU5y12MuHk=\" , \"login\" : { \"uris\" : [ { \"uri\" : \"2.DNrdKV2iNY+RtJbqFnPu7Q==|vhIZA5pXFngJRCnZlYjTmQV0ybQdJ6lNzt1CoTauwVI=|PiDEUFpvEaJtrKADSnyuqALajPHnDmfQsiDLEqF+3YY=\" } ], \"username\" : \"2.+uazyy7smAtIToJfqcS8yw==|IhmkZ0OHV+kX7txsPsSztA==|tDc1Zgknyl/JMn/O44hWZBaywSsHGeRGvK7ffEr5SdM=\" , \"password\" : \"2.L+41A7ch4GypwrIFXG5vkA==|S3eFnoNtk1IpsT4gcfcNrw==|lqdBTpSHKqTJtgBBXBXqm2K249AF1gZMec4cFf5gqR0=\" }, \"fields\" : null , \"organization_id\" : \"8869e3ee461551cc2bc4d5d9a107dbf9\" , \"collection_id\" : \"8869e3ee461551cc2bc4d5d9a107d0c1\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-09-24T15:48:19.55593719+02:00\" , \"updatedAt\" : \"2019-09-24T15:48:19.55593719+02:00\" } }", "title": "Example"}, {"location": "cozy-doctypes/docs/com.bitwarden.contacts/", "text": "Table of contents Bitwarden contacts \u00b6 The com.bitwarden.contacts doctype is used to share organizations with other users. A com.bitwarden.contacts may be linked to a Cozy contacts by using the email attribute. Attributes \u00b6 email : {string} - the email of the contact public_key : {string} - the public key of the contact confirmed : {bool} - true if the contact\u2019s fingerprint phrase has been verified and confirmed by the user cozyMetadata : {object} - the cozyMetadata Example \u00b6 { \"_id\" : \"49a6e10fc3718829c4dac13a9e015597\" , \"_rev\" : \"1-49847ab10b103b2e084b0231e339ddce\" , \"email\" : \"me@bob.cozy.localhost\" , \"public_key\" : \"4.MbW...QVdA==\" , \"confirmed\" : true , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2021-08-30T17:41:49.991184+02:00\" , \"updatedAt\" : \"2021-08-30T17:41:49.991184+02:00\" } }", "title": "Bitwarden contacts"}, {"location": "cozy-doctypes/docs/com.bitwarden.contacts/#bitwarden-contacts", "text": "The com.bitwarden.contacts doctype is used to share organizations with other users. A com.bitwarden.contacts may be linked to a Cozy contacts by using the email attribute.", "title": "Bitwarden contacts"}, {"location": "cozy-doctypes/docs/com.bitwarden.contacts/#attributes", "text": "email : {string} - the email of the contact public_key : {string} - the public key of the contact confirmed : {bool} - true if the contact\u2019s fingerprint phrase has been verified and confirmed by the user cozyMetadata : {object} - the cozyMetadata", "title": "Attributes"}, {"location": "cozy-doctypes/docs/com.bitwarden.contacts/#example", "text": "{ \"_id\" : \"49a6e10fc3718829c4dac13a9e015597\" , \"_rev\" : \"1-49847ab10b103b2e084b0231e339ddce\" , \"email\" : \"me@bob.cozy.localhost\" , \"public_key\" : \"4.MbW...QVdA==\" , \"confirmed\" : true , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2021-08-30T17:41:49.991184+02:00\" , \"updatedAt\" : \"2021-08-30T17:41:49.991184+02:00\" } }", "title": "Example"}, {"location": "cozy-doctypes/docs/com.bitwarden.folders/", "text": "Table of contents Bitwarden folders \u00b6 The com.bitwarden.folders doctype is used to organize ciphers . Attributes \u00b6 name : {string} - the name of the folder, encrypted as a cipherString with AES cozyMetadata : {object} - the cozyMetadata Example \u00b6 { \"_id\" : \"44907c0262681483ab53e944fa0782e1\" , \"_rev\" : \"1-63242020f047a03e828514af2546c914\" , \"name\" : \"2.wqUYK+tfBUcUospPv28uhw==|FCcImzd1G6Xq8sO1mF9+Xw==|am84ofcVS+NM0fWhm4WIECC+iBQ9fldOtVy1JrfTmyg=\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-09-24T15:51:29.320878421+02:00\" , \"updatedAt\" : \"2019-09-24T15:51:29.320878421+02:00\" } }", "title": "Bitwarden folders"}, {"location": "cozy-doctypes/docs/com.bitwarden.folders/#bitwarden-folders", "text": "The com.bitwarden.folders doctype is used to organize ciphers .", "title": "Bitwarden folders"}, {"location": "cozy-doctypes/docs/com.bitwarden.folders/#attributes", "text": "name : {string} - the name of the folder, encrypted as a cipherString with AES cozyMetadata : {object} - the cozyMetadata", "title": "Attributes"}, {"location": "cozy-doctypes/docs/com.bitwarden.folders/#example", "text": "{ \"_id\" : \"44907c0262681483ab53e944fa0782e1\" , \"_rev\" : \"1-63242020f047a03e828514af2546c914\" , \"name\" : \"2.wqUYK+tfBUcUospPv28uhw==|FCcImzd1G6Xq8sO1mF9+Xw==|am84ofcVS+NM0fWhm4WIECC+iBQ9fldOtVy1JrfTmyg=\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-09-24T15:51:29.320878421+02:00\" , \"updatedAt\" : \"2019-09-24T15:51:29.320878421+02:00\" } }", "title": "Example"}, {"location": "cozy-doctypes/docs/com.bitwarden.organizations/", "text": "Table of contents Bitwarden organization \u00b6 The com.bitwarden.organization doctype is used to group ciphers in a single unit and/or to share them with other bitwarden contacts . Attributes \u00b6 name : {string} - the name of the organization members : {object} - the members of the organization (see below) defaultCollection : {object} - the collection of the organization (see below) cozyMetadata : {object} - the cozyMetadata Members \u00b6 An organization can be shared with a list of members. email : {string} - the email of the member from bitwarden contacts key : {string} - the organization\u2019s key encrypted with the public key of the member from bitwarden contacts name : {string} - the name of the member owner : {bool} - true if the member owns the organization status : {int} - the status of the member ( 0 = invited , 1 = accepted , 2 = confirmed ) user_id : {string} - the id of the member from bitwarden contacts Note that the name and key attributes may be missing if the member status is still invited as those data are sent only when he accepts the first Cozy sharing from organization\u2019s owner. Collection \u00b6 A collection is a virtual container for ciphers . A ciphers can live alone or included in a collection. Any collection is linked to an organization. By construction the Bitwarden protocol allows an organization to contain one or more collections. But at Cozy we defined that an organization must contain exactly one collection. So there is no need seperate those entities, and so there is no dedicated doctype for a collection. The collection entity exists to comply with the Bitwarden protocol. _id : {string} - the id of the collection name : {string} - the name of the collection, encrypted as a cipherString with AES Example \u00b6 { \"_id\" : \"8869e3ee461551cc2bc4d5d9a107dbf9\" , \"_rev\" : \"2-1926d7ef135d622721fc2e44519399cf\" , \"name\" : \"test\" , \"members\" : { \"alice.cozy.localhost:8080\" : { \"email\" : \"me@alice.cozy.localhost\" , \"key\" : \"4.Xzx...+w3Q==\" , \"name\" : \"Alice\" , \"owner\" : true , \"status\" : 2 , \"user_id\" : \"49a6e10fc3718829c4dac13a9e0036b0\" }, \"bob.cozy.localhost:8080\" : { \"email\" : \"me@bob.cozy.localhost\" , \"key\" : \"4.MbW...QVdA==\" , \"name\" : \"Bob\" , \"status\" : 2 , \"user_id\" : \"49a6e10fc3718829c4dac13a9e015597\" } }, \"defaultCollection\" : { \"_id\" : \"8869e3ee461551cc2bc4d5d9a107d0c1\" , \"name\" : \"2.zedwpSJJACs2y+QSzxwqNA==|VB6iWyyRM++AFH7QjsJ/iw==|INFs55T//Ge1CIpyHh1tritNhaxfXGHDgb5yLyzqjjk=\" }, \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2021-08-30T17:29:31.431874+02:00\" , \"updatedAt\" : \"2021-08-30T17:29:31.431874+02:00\" } }", "title": "Bitwarden organizations"}, {"location": "cozy-doctypes/docs/com.bitwarden.organizations/#bitwarden-organization", "text": "The com.bitwarden.organization doctype is used to group ciphers in a single unit and/or to share them with other bitwarden contacts .", "title": "Bitwarden organization"}, {"location": "cozy-doctypes/docs/com.bitwarden.organizations/#attributes", "text": "name : {string} - the name of the organization members : {object} - the members of the organization (see below) defaultCollection : {object} - the collection of the organization (see below) cozyMetadata : {object} - the cozyMetadata", "title": "Attributes"}, {"location": "cozy-doctypes/docs/com.bitwarden.organizations/#members", "text": "An organization can be shared with a list of members. email : {string} - the email of the member from bitwarden contacts key : {string} - the organization\u2019s key encrypted with the public key of the member from bitwarden contacts name : {string} - the name of the member owner : {bool} - true if the member owns the organization status : {int} - the status of the member ( 0 = invited , 1 = accepted , 2 = confirmed ) user_id : {string} - the id of the member from bitwarden contacts Note that the name and key attributes may be missing if the member status is still invited as those data are sent only when he accepts the first Cozy sharing from organization\u2019s owner.", "title": "Members"}, {"location": "cozy-doctypes/docs/com.bitwarden.organizations/#collection", "text": "A collection is a virtual container for ciphers . A ciphers can live alone or included in a collection. Any collection is linked to an organization. By construction the Bitwarden protocol allows an organization to contain one or more collections. But at Cozy we defined that an organization must contain exactly one collection. So there is no need seperate those entities, and so there is no dedicated doctype for a collection. The collection entity exists to comply with the Bitwarden protocol. _id : {string} - the id of the collection name : {string} - the name of the collection, encrypted as a cipherString with AES", "title": "Collection"}, {"location": "cozy-doctypes/docs/com.bitwarden.organizations/#example", "text": "{ \"_id\" : \"8869e3ee461551cc2bc4d5d9a107dbf9\" , \"_rev\" : \"2-1926d7ef135d622721fc2e44519399cf\" , \"name\" : \"test\" , \"members\" : { \"alice.cozy.localhost:8080\" : { \"email\" : \"me@alice.cozy.localhost\" , \"key\" : \"4.Xzx...+w3Q==\" , \"name\" : \"Alice\" , \"owner\" : true , \"status\" : 2 , \"user_id\" : \"49a6e10fc3718829c4dac13a9e0036b0\" }, \"bob.cozy.localhost:8080\" : { \"email\" : \"me@bob.cozy.localhost\" , \"key\" : \"4.MbW...QVdA==\" , \"name\" : \"Bob\" , \"status\" : 2 , \"user_id\" : \"49a6e10fc3718829c4dac13a9e015597\" } }, \"defaultCollection\" : { \"_id\" : \"8869e3ee461551cc2bc4d5d9a107d0c1\" , \"name\" : \"2.zedwpSJJACs2y+QSzxwqNA==|VB6iWyyRM++AFH7QjsJ/iw==|INFs55T//Ge1CIpyHh1tritNhaxfXGHDgb5yLyzqjjk=\" }, \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2021-08-30T17:29:31.431874+02:00\" , \"updatedAt\" : \"2021-08-30T17:29:31.431874+02:00\" } }", "title": "Example"}, {"location": "cozy-doctypes/docs/com.ecoledirecte.notes/", "text": "Table of contents Ecole Directe notes \u00b6 The com.ecoledirecte.notes doctype is used to store the notes for a given student com.ecoledirecte.notes are generated by Ecole Direct connector . Attributes \u00b6 The available attributes in a com.ecoledirecte.notes document are : student : {string} - Student unique id devoir : {string} - devoir label codeMatiere : {string} - subject unique code libelleMatiere : {string} - subject label codeSousMatiere : {string} - sub subject code typeDevoir : {string} - label for homework type enLettre : {boolean} - ? coef : {number} - coefficient noteSur : {number} - note total valeur : {float} - note value nonSignificatif : {boolean} - should this note be used in average calculation I suppose date : {date} - date of the note dateSaisie : {date} - date when the note was typed valeurisee : {boolean} - ? moyenneClasse : {float} - class average elementsProgramme : {array} - liste of competencies related to this devoir descriptiif : {string} - description idElemProg : {number} - program item number valeur : {number} - value, ? cdt : {boolean} - ? idCompetence : {number} - competency id libelleCompetence : {string} - comptency label", "title": "Com.ecoledirecte.notes"}, {"location": "cozy-doctypes/docs/com.ecoledirecte.notes/#ecole-directe-notes", "text": "The com.ecoledirecte.notes doctype is used to store the notes for a given student com.ecoledirecte.notes are generated by Ecole Direct connector .", "title": "Ecole Directe notes"}, {"location": "cozy-doctypes/docs/com.ecoledirecte.notes/#attributes", "text": "The available attributes in a com.ecoledirecte.notes document are : student : {string} - Student unique id devoir : {string} - devoir label codeMatiere : {string} - subject unique code libelleMatiere : {string} - subject label codeSousMatiere : {string} - sub subject code typeDevoir : {string} - label for homework type enLettre : {boolean} - ? coef : {number} - coefficient noteSur : {number} - note total valeur : {float} - note value nonSignificatif : {boolean} - should this note be used in average calculation I suppose date : {date} - date of the note dateSaisie : {date} - date when the note was typed valeurisee : {boolean} - ? moyenneClasse : {float} - class average elementsProgramme : {array} - liste of competencies related to this devoir descriptiif : {string} - description idElemProg : {number} - program item number valeur : {number} - value, ? cdt : {boolean} - ? idCompetence : {number} - competency id libelleCompetence : {string} - comptency label", "title": "Attributes"}, {"location": "cozy-doctypes/docs/com.ecoledirecte.textbook.day/", "text": "Table of contents Ecole Directe Homework days doctype \u00b6 The com.ecoledirecte.textbook.day doctype is used to store all the homeworks of a given student for a given day. It follows Ecole Direct website api waiting for a more generic data structure com.ecoledirecte.textbook.day are generated by Ecole Direct connector . Attributes \u00b6 The available attributes in a com.ecoledirecte.textbook.day document are : date : {date} - The day the homework must be done student : {string} - Student unique id matieres : {array} - list of homeworks by subjects : entityCode : {string} - unique code for the entity the student is part of entityLibelle : {string} - entity label entityType : {string} - ? matiere : {string} - subject label codeMatiere : {string} - subject unique code nomProf : {string} - professor\u2019s name id : {string} - homework unique id interrogation : {boolean} - ? blogActif : {boolean} - ? aFaire : {object} idDevoir : {string} - homework unique id contenu : {string} - base64 encoded html details about the homework rendreEnLigne : {boolean} - ? donneLe : {date} - the date the homework was given effectue : {boolean} - is the homework done ressource : {string} - base64 encoded html details about the homework elementsProg : {array} - ? liensManuel : {array} - ? contenuDeSeance : {string} - base64 encoded html text contenuDeSeance : {object} idDevoir : {string} - homework unique id contenu : {string} - base64 encoded html details about the homework elementsProg : {array} - ? liensManuel : {array} - ? Relationships attributes \u00b6 ressourceDocuments : {array} - list of linked ressource files contenuDeSeanceDocuments : {array} - list of linked files documents : {array} - list of linked document files", "title": "Com.ecoledirecte.textbook.day"}, {"location": "cozy-doctypes/docs/com.ecoledirecte.textbook.day/#ecole-directe-homework-days-doctype", "text": "The com.ecoledirecte.textbook.day doctype is used to store all the homeworks of a given student for a given day. It follows Ecole Direct website api waiting for a more generic data structure com.ecoledirecte.textbook.day are generated by Ecole Direct connector .", "title": "Ecole Directe Homework days doctype"}, {"location": "cozy-doctypes/docs/com.ecoledirecte.textbook.day/#attributes", "text": "The available attributes in a com.ecoledirecte.textbook.day document are : date : {date} - The day the homework must be done student : {string} - Student unique id matieres : {array} - list of homeworks by subjects : entityCode : {string} - unique code for the entity the student is part of entityLibelle : {string} - entity label entityType : {string} - ? matiere : {string} - subject label codeMatiere : {string} - subject unique code nomProf : {string} - professor\u2019s name id : {string} - homework unique id interrogation : {boolean} - ? blogActif : {boolean} - ? aFaire : {object} idDevoir : {string} - homework unique id contenu : {string} - base64 encoded html details about the homework rendreEnLigne : {boolean} - ? donneLe : {date} - the date the homework was given effectue : {boolean} - is the homework done ressource : {string} - base64 encoded html details about the homework elementsProg : {array} - ? liensManuel : {array} - ? contenuDeSeance : {string} - base64 encoded html text contenuDeSeance : {object} idDevoir : {string} - homework unique id contenu : {string} - base64 encoded html details about the homework elementsProg : {array} - ? liensManuel : {array} - ?", "title": "Attributes"}, {"location": "cozy-doctypes/docs/com.ecoledirecte.textbook.day/#relationships-attributes", "text": "ressourceDocuments : {array} - list of linked ressource files contenuDeSeanceDocuments : {array} - list of linked files documents : {array} - list of linked document files", "title": "Relationships attributes"}, {"location": "cozy-doctypes/docs/com.unibet.bets/", "text": "Table of contents Unibet bets doctype \u00b6 com.unibet.bets \u00b6 Description \u00b6 Represents a bet from the Unibet website api. Mandatory attributes \u00b6 idfobet : {float} - seems to be the id of the bet as \u2018int.version\u2019 betlegs : {array} - Bets on which repose the main bet date : {date} - Date as a timestamp \u2026 Example \u00b6 { betlegs: { ... }, stake: 5, returnWithoutBonus: null, bonusReturn: null, totalReturn: 0, totalOdd: 78.01, potentialReturnWithoutBonus: null, specialOfferName: null, specialOfferAmount: null, isSettled: true, date: 1520287914000, externalReference: '1/1', isFreeBets: false, isCashoutAvailable: false, cashoutAvailableValue: null, idfobet: 172075178.1 } }", "title": "Bets Unibet"}, {"location": "cozy-doctypes/docs/com.unibet.bets/#unibet-bets-doctype", "text": "", "title": "Unibet bets doctype"}, {"location": "cozy-doctypes/docs/com.unibet.bets/#comunibetbets", "text": "", "title": "com.unibet.bets"}, {"location": "cozy-doctypes/docs/com.unibet.bets/#description", "text": "Represents a bet from the Unibet website api.", "title": "Description"}, {"location": "cozy-doctypes/docs/com.unibet.bets/#mandatory-attributes", "text": "idfobet : {float} - seems to be the id of the bet as \u2018int.version\u2019 betlegs : {array} - Bets on which repose the main bet date : {date} - Date as a timestamp \u2026", "title": "Mandatory attributes"}, {"location": "cozy-doctypes/docs/com.unibet.bets/#example", "text": "{ betlegs: { ... }, stake: 5, returnWithoutBonus: null, bonusReturn: null, totalReturn: 0, totalOdd: 78.01, potentialReturnWithoutBonus: null, specialOfferName: null, specialOfferAmount: null, isSettled: true, date: 1520287914000, externalReference: '1/1', isFreeBets: false, isCashoutAvailable: false, cashoutAvailableValue: null, idfobet: 172075178.1 } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.account_types/", "text": "Cozy account types doctype io.cozy.account_types Cozy account types doctype \u00b6 io.cozy.account_types \u00b6 The io.cozy.account_types can be used for two main purposes: It can contain secret configuration parameters needed by the webapp/konnectors (API Tokens, API URLS, \u2026). Every time a konnector job is executed, the stack can give some of these secret parameters to the konnector It can contain an OAuth configuration for a service. It simplifies the development of konnectors for OAuth providers, and avoids race conditions when the same account is used by several konnectors. grant_mode {string}: Grant mode, part of the OAuth standard client_id {string}: Client ID, part of the OAuth standard client_secret {string}: Client secret, part of the OAuth standard auth_endpoint {string}: The endpoint of the external service authentication token_endpoint {bool}: The endpoint of the external service token exchange token_mode {string}: Mode of token auth retreiving( form / basic / get ) redirect_uri {[]string}: List of redirect URIs given by the client. Part of the OAuth standard extras {map[string]string}: Extra auth query parameters slug {string}: Slug of the webapp/konnector secret {object}: JSON object given as an environment variable to the konnector", "title": "Accounts Types"}, {"location": "cozy-doctypes/docs/io.cozy.account_types/#cozy-account-types-doctype", "text": "", "title": "Cozy account types doctype"}, {"location": "cozy-doctypes/docs/io.cozy.account_types/#iocozyaccount_types", "text": "The io.cozy.account_types can be used for two main purposes: It can contain secret configuration parameters needed by the webapp/konnectors (API Tokens, API URLS, \u2026). Every time a konnector job is executed, the stack can give some of these secret parameters to the konnector It can contain an OAuth configuration for a service. It simplifies the development of konnectors for OAuth providers, and avoids race conditions when the same account is used by several konnectors. grant_mode {string}: Grant mode, part of the OAuth standard client_id {string}: Client ID, part of the OAuth standard client_secret {string}: Client secret, part of the OAuth standard auth_endpoint {string}: The endpoint of the external service authentication token_endpoint {bool}: The endpoint of the external service token exchange token_mode {string}: Mode of token auth retreiving( form / basic / get ) redirect_uri {[]string}: List of redirect URIs given by the client. Part of the OAuth standard extras {map[string]string}: Extra auth query parameters slug {string}: Slug of the webapp/konnector secret {object}: JSON object given as an environment variable to the konnector", "title": "io.cozy.account_types"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/", "text": "Table of contents Cozy Accounts doctype \u00b6 The io.cozy.accounts doctype stores authentification informations used by konnectors to connect to external services or API. Accounts can be managed in Cozy-Home (via Harvest ). They are generally associated to a io.cozy.triggers document. io.cozy.accounts attributes are: account_type : {string} Slug of the konnector the account is related to. Note this could be a relationship to the konnector manifest, but we keep this field for historical reasons. auth : {object} (Optional) Contains authentification data, typically a couple with login / password . This field should not be used when oauth is present. login : {string} (Optional) Main credentials field to use, displayed as default account name by harvest. Some konnectors do not use a login parameter, but identifier or email . In this case the attribute role: 'identifier' should be added to the parameter object in the konnector\u2019s manifest. accountName : {string} (Optional) If defined, will be used preferentially over login or email or the first konnerctor parameter with role: 'identifier' as the account name. (Used when the account has no identifiable name, commonly when using an aggregator account) credentials_encrypted : {string} Stores the encrypted auth fields using type: password in the konnector\u2019s manifest, typically the password field. token : {string} (Optional) Token stored for OAuth konnectors new_identifier : {string} (Deprecated) identifier : {string} (Depracted) oauth : {object} (Optional) Credentials field used for OAuth konnectors such as banking konnectors. This field should not be used when auth is present. access_token {string} (Optional) token_type {string} (Optional) expires_at {string} (Optional) refresh_token {string} (Optional) client_id {string} (Optional) client_secret {string} (Optional) query {object} (Optional) Map of keys and values (array of strings). oauth_callback_results {object} (Optional) data : {object} (Optional) Additional custom data. This is useful to store arbitrary data related to the account. For instance, this can be used to store an account status, the date of the last retrieved document, etc. defaultFolderPath : {string} Default destination folder used by cozy-stack for folder re-creation when the destination folder has been removed. If not provided, it will be generated by cozy-stack using the attribte of the auth object pointed by identifier and the konnector\u2019s name. identifier {string} (Optional) Name of the attribute in the auth object that can be used to name the account. state : {string} (Optional) The account state is used to communicate between the konnector and Harvest to ask for a needed 2FA Code or to tell to reset the konnector session for example. Here are the used values for now: TWOFA_NEEDED : The service is asking for a Two Factor connexion and the related code (sent by the service) must be provided by the user. This status can be further precised with its type. This allows the UI presented to the user to have custom messages, depending on the type of two factor authentication required by the vendor. TWOFA_NEEDED.EMAIL : If the two factor authentication is done by email TWOFA_NEEDED.SMS : If the two factor authentication is done by SMS TWOFA_NEEDED_RETRY : The 2FA code provided by the user is wrong, the user can retry by providing a new one. TWO_FA_NEEDED_RETRY.EMAIL and TWO_FA_NEEDED_RETRY.SMS can also be used. RESET_SESSION : By finding this state, the konnector should reset the login session if there is one stored and reset the state. twoFACode : When a 2FA code is asked by the service, Harvest will ask the user for it from and send it to the konnector via this attribute. mutedErrors : {array} (Optional) A list of errors that have been discarded by the user and will no longer be shown in the UI. See below for more information. token : {string} (Optional) User token for banking aggregator used only in bi-aggregator account userId : {string} (Optional) User id for banking aggregator used only in bi-aggregator-user account About the name of the account \u00b6 We need a name for the account displayed to the user in harvest and for cozy-stack to create the associated folder if needed. If missing, harvest will determine the value of the identifier attribute based on the following rules: 1. a konnector\u2019s manifest field name if it has the role: \"identifier\" attribute 2. login if auth.login is defined 3. identifier if auth.identifier is defined 4. new_identifier if auth.new_identifier is defined 5. email if auth.email is defined If the identifier attribute is defined, the account name will be chosen based on these rules: 1. auth[identifer] if defined (we use the value of the identifier attibute here) 2. _id For banking connectors, the identifier attribute contains the string identifier so, the name of the account is the value of auth.identifier . Attributes \u00b6 mutedErrors \u00b6 This field is used to keep track of konnector errors that have been muted by the user and shouldn\u2019t be featured in the UI anymore. { \"account_type\" : \"example-konnector\" , \"auth\" : { \"identifier\" : \"0000000000\" }, \"mutedErrors\" : [ { \"type\" : \"LOGIN_FAILED\" , \"mutedAt\" : \"2019-12-01T00:48:01.404911778Z\" } ] } Relationships \u00b6 parent \u00b6 An account may have a parent relationship. It is used to indicate that this accounts depends on another one. Generally, the konnector should be able to handle by itself this kind of relationshiop, like querying the database to get the information it needs. A parent relationship is aimed to be an account overriden by the account it is linked to, but it can also be use as an aggregator account. See Cozy-stack documentation about aggregator accounts . { \"relationships\" : { \"parent\" : { \"data\" : { \"_id\" : \"aggregator-service-account\" , \"_type\" : \"io.cozy.accounts\" } } } } Vault Cipher vaultCipher \u00b6 An account can be synced in a password manager. In that case, the vaultCipher relationship can be used to store data used to synchronize the document with the remote endpoint. { \"relationships\" : { \"vaultCipher\" : { \"data\" : { \"_id\" : \"123abc\" , \"_type\" : \"com.bitwarden.ciphers\" , \"_protocol\" : \"bitwarden\" } } } } Contracts contracts \u00b6 When the connector brings contracts (in the case of banking connectors, contracts means individual banking accounts), the connector stores information on the contracts in the contracts relationship. Relationship items store extra information in the metadata key of the relationship item. vendorId : the id of the contract on the vendor side deletedByVendor : whether it was deleted on the vendor side imported : whether it should be imported on the vendor side label : Label of the contract { \"relationships\" : { \"contracts\" : { \"data\" : [ { \"_id\" : \"77b662b903f1bac7a78cf8cc12806479\" , \"_type\" : \"io.cozy.bank.accounts\" , \"metadata\" : { \"deletedByVendor\" : false , \"imported\" : true , \"label\" : \"Compte ch\u00e8que\" , \"vendorId\" : \"1337\" } }, { \"_id\" : \"07c731e303e0d50a5407b7eca9389890\" , \"_type\" : \"io.cozy.bank.accounts\" , \"metadata\" : { \"deletedByVendor\" : false , \"imported\" : false , \"label\" : \"Assurance Vie\" , \"vendorId\" : \"1338\" } } ] } } } Examples \u00b6 Freemobile (regular connector, with current deprecation) \u00b6 { \"_id\" : \"c8ae8c7e5554f223816c71a066f1a621\" , \"id\" : \"c8ae8c7e5554f223816c71a066f1a621\" , \"account_type\" : \"freemobile\" , \"auth\" : { \"credentials_encrypted\" : \"aaDtwWSWsdpbbbbbbbbbbbbbbOzp...n4Y8c=\" , \"login\" : \"0612345678\" }, \"defaultFolderPath\" : \"/Administratif/Free Mobile/0612345678\" , \"identifier\" : \"login\" , \"state\" : \"LOGIN_SUCCESS\" , \"cozyMetadata\" : { \"createdAt\" : \"2022-11-15T16:12:10.736Z\" , \"metadataVersion\" : 1 , \"updatedAt\" : \"2022-11-15T16:32:58.617Z\" , \"updatedByApps\" : [ { \"date\" : \"2022-11-15T16:32:58.617Z\" } ] } } Caisse d\u2019\u00c9pargne (Budget Insights connector) \u00b6 The connectors based on Budget Insight API are storing specific informations into data attribute. { \"account_type\" : \"caissedepargne1\" , \"auth\" : { \"bankIds\" : [ \"1\" ] }, \"data\" : { \"auth\" : { \"bi\" : { \"connId\" : 1556 } } } }", "title": "Accounts"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#cozy-accounts-doctype", "text": "The io.cozy.accounts doctype stores authentification informations used by konnectors to connect to external services or API. Accounts can be managed in Cozy-Home (via Harvest ). They are generally associated to a io.cozy.triggers document. io.cozy.accounts attributes are: account_type : {string} Slug of the konnector the account is related to. Note this could be a relationship to the konnector manifest, but we keep this field for historical reasons. auth : {object} (Optional) Contains authentification data, typically a couple with login / password . This field should not be used when oauth is present. login : {string} (Optional) Main credentials field to use, displayed as default account name by harvest. Some konnectors do not use a login parameter, but identifier or email . In this case the attribute role: 'identifier' should be added to the parameter object in the konnector\u2019s manifest. accountName : {string} (Optional) If defined, will be used preferentially over login or email or the first konnerctor parameter with role: 'identifier' as the account name. (Used when the account has no identifiable name, commonly when using an aggregator account) credentials_encrypted : {string} Stores the encrypted auth fields using type: password in the konnector\u2019s manifest, typically the password field. token : {string} (Optional) Token stored for OAuth konnectors new_identifier : {string} (Deprecated) identifier : {string} (Depracted) oauth : {object} (Optional) Credentials field used for OAuth konnectors such as banking konnectors. This field should not be used when auth is present. access_token {string} (Optional) token_type {string} (Optional) expires_at {string} (Optional) refresh_token {string} (Optional) client_id {string} (Optional) client_secret {string} (Optional) query {object} (Optional) Map of keys and values (array of strings). oauth_callback_results {object} (Optional) data : {object} (Optional) Additional custom data. This is useful to store arbitrary data related to the account. For instance, this can be used to store an account status, the date of the last retrieved document, etc. defaultFolderPath : {string} Default destination folder used by cozy-stack for folder re-creation when the destination folder has been removed. If not provided, it will be generated by cozy-stack using the attribte of the auth object pointed by identifier and the konnector\u2019s name. identifier {string} (Optional) Name of the attribute in the auth object that can be used to name the account. state : {string} (Optional) The account state is used to communicate between the konnector and Harvest to ask for a needed 2FA Code or to tell to reset the konnector session for example. Here are the used values for now: TWOFA_NEEDED : The service is asking for a Two Factor connexion and the related code (sent by the service) must be provided by the user. This status can be further precised with its type. This allows the UI presented to the user to have custom messages, depending on the type of two factor authentication required by the vendor. TWOFA_NEEDED.EMAIL : If the two factor authentication is done by email TWOFA_NEEDED.SMS : If the two factor authentication is done by SMS TWOFA_NEEDED_RETRY : The 2FA code provided by the user is wrong, the user can retry by providing a new one. TWO_FA_NEEDED_RETRY.EMAIL and TWO_FA_NEEDED_RETRY.SMS can also be used. RESET_SESSION : By finding this state, the konnector should reset the login session if there is one stored and reset the state. twoFACode : When a 2FA code is asked by the service, Harvest will ask the user for it from and send it to the konnector via this attribute. mutedErrors : {array} (Optional) A list of errors that have been discarded by the user and will no longer be shown in the UI. See below for more information. token : {string} (Optional) User token for banking aggregator used only in bi-aggregator account userId : {string} (Optional) User id for banking aggregator used only in bi-aggregator-user account", "title": "Cozy Accounts doctype"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#about-the-name-of-the-account", "text": "We need a name for the account displayed to the user in harvest and for cozy-stack to create the associated folder if needed. If missing, harvest will determine the value of the identifier attribute based on the following rules: 1. a konnector\u2019s manifest field name if it has the role: \"identifier\" attribute 2. login if auth.login is defined 3. identifier if auth.identifier is defined 4. new_identifier if auth.new_identifier is defined 5. email if auth.email is defined If the identifier attribute is defined, the account name will be chosen based on these rules: 1. auth[identifer] if defined (we use the value of the identifier attibute here) 2. _id For banking connectors, the identifier attribute contains the string identifier so, the name of the account is the value of auth.identifier .", "title": "About the name of the account"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#attributes", "text": "", "title": "Attributes"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#mutederrors", "text": "This field is used to keep track of konnector errors that have been muted by the user and shouldn\u2019t be featured in the UI anymore. { \"account_type\" : \"example-konnector\" , \"auth\" : { \"identifier\" : \"0000000000\" }, \"mutedErrors\" : [ { \"type\" : \"LOGIN_FAILED\" , \"mutedAt\" : \"2019-12-01T00:48:01.404911778Z\" } ] }", "title": "mutedErrors"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#relationships", "text": "", "title": "Relationships"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#parent", "text": "An account may have a parent relationship. It is used to indicate that this accounts depends on another one. Generally, the konnector should be able to handle by itself this kind of relationshiop, like querying the database to get the information it needs. A parent relationship is aimed to be an account overriden by the account it is linked to, but it can also be use as an aggregator account. See Cozy-stack documentation about aggregator accounts . { \"relationships\" : { \"parent\" : { \"data\" : { \"_id\" : \"aggregator-service-account\" , \"_type\" : \"io.cozy.accounts\" } } } }", "title": "parent"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#vault-cipher-vaultcipher", "text": "An account can be synced in a password manager. In that case, the vaultCipher relationship can be used to store data used to synchronize the document with the remote endpoint. { \"relationships\" : { \"vaultCipher\" : { \"data\" : { \"_id\" : \"123abc\" , \"_type\" : \"com.bitwarden.ciphers\" , \"_protocol\" : \"bitwarden\" } } } }", "title": "Vault Cipher vaultCipher"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#contracts-contracts", "text": "When the connector brings contracts (in the case of banking connectors, contracts means individual banking accounts), the connector stores information on the contracts in the contracts relationship. Relationship items store extra information in the metadata key of the relationship item. vendorId : the id of the contract on the vendor side deletedByVendor : whether it was deleted on the vendor side imported : whether it should be imported on the vendor side label : Label of the contract { \"relationships\" : { \"contracts\" : { \"data\" : [ { \"_id\" : \"77b662b903f1bac7a78cf8cc12806479\" , \"_type\" : \"io.cozy.bank.accounts\" , \"metadata\" : { \"deletedByVendor\" : false , \"imported\" : true , \"label\" : \"Compte ch\u00e8que\" , \"vendorId\" : \"1337\" } }, { \"_id\" : \"07c731e303e0d50a5407b7eca9389890\" , \"_type\" : \"io.cozy.bank.accounts\" , \"metadata\" : { \"deletedByVendor\" : false , \"imported\" : false , \"label\" : \"Assurance Vie\" , \"vendorId\" : \"1338\" } } ] } } }", "title": "Contracts contracts"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#examples", "text": "", "title": "Examples"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#freemobile-regular-connector-with-current-deprecation", "text": "{ \"_id\" : \"c8ae8c7e5554f223816c71a066f1a621\" , \"id\" : \"c8ae8c7e5554f223816c71a066f1a621\" , \"account_type\" : \"freemobile\" , \"auth\" : { \"credentials_encrypted\" : \"aaDtwWSWsdpbbbbbbbbbbbbbbOzp...n4Y8c=\" , \"login\" : \"0612345678\" }, \"defaultFolderPath\" : \"/Administratif/Free Mobile/0612345678\" , \"identifier\" : \"login\" , \"state\" : \"LOGIN_SUCCESS\" , \"cozyMetadata\" : { \"createdAt\" : \"2022-11-15T16:12:10.736Z\" , \"metadataVersion\" : 1 , \"updatedAt\" : \"2022-11-15T16:32:58.617Z\" , \"updatedByApps\" : [ { \"date\" : \"2022-11-15T16:32:58.617Z\" } ] } }", "title": "Freemobile (regular connector, with current deprecation)"}, {"location": "cozy-doctypes/docs/io.cozy.accounts/#caisse-depargne-budget-insights-connector", "text": "The connectors based on Budget Insight API are storing specific informations into data attribute. { \"account_type\" : \"caissedepargne1\" , \"auth\" : { \"bankIds\" : [ \"1\" ] }, \"data\" : { \"auth\" : { \"bi\" : { \"connId\" : 1556 } } } }", "title": "Caisse d'\u00c9pargne (Budget Insights connector)"}, {"location": "cozy-doctypes/docs/io.cozy.apps/", "text": "Table of contents \u00b6 Table of contents Apps doctype Attributes Example Apps doctype \u00b6 The io.cozy.apps doctype is used to store installed apps. Apps (or Webapps) are core applications used to interact with the instance data. For example, the drive app can handle files, photos will manage photos & albums and banks the financial data. When an app is installed, the Cozy stack creates a new io.cozy.apps document in the instance io.cozy.apps database. You can get more informations on the official docs . Attributes \u00b6 The available attributes in a io.cozy.apps document are available in the official docs: https://docs.cozy.io/en/cozy-apps-registry/#properties-meaning-reference Example \u00b6 This is the truncated version of the official Cozy drive app. { \"name\" : \"Drive\" , \"name_prefix\" : \"Cozy\" , \"slug\" : \"drive\" , \"version\" : \"1.18.3\" , \"type\" : \"webapp\" , \"licence\" : \"AGPL-3.0\" , \"icon\" : \"public/app-icon.svg\" , \"categories\" : [ \"cozy\" ], \"source\" : \"https://github.com/cozy/cozy-drive\" , \"editor\" : \"Cozy\" , \"developer\" : { \"name\" : \"Cozy Cloud\" , \"url\" : \"https://cozy.io\" }, \"routes\" : { \"/\" : { \"folder\" : \"/\" , \"index\" : \"index.html\" , \"public\" : false }, \"/intents\" : { \"folder\" : \"/intents\" , \"index\" : \"index.html\" , \"public\" : false } }, \"intents\" : [ { \"action\" : \"OPEN\" , \"type\" : [ \"io.cozy.files\" ], \"href\" : \"/intents\" } ], \"permissions\" : { \"files\" : { \"description\" : \"Required to access the files\" , \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"ALL\" ] }, \"apps\" : { \"description\" : \"Required by the cozy-bar to display the icons of the apps\" , \"type\" : \"io.cozy.apps\" , \"verbs\" : [ \"GET\" ] } } } Special io.cozy.apps doctypes \u00b6 Some folders are remarkable, like the \u2018Administrative\u2019 and the \u2018Photos\u2019 folders. You shouldn\u2019t address them by their path as it may vary depending on the user language and the user may have renamed them anyways. To identify them, you can ask for a special referenced_by attribute . For example, a request for all io.cozy.files referended by the doctype io.cozy.apps and the document id administrative will return you the io.cozy.files document of the folder \u2018Administrative\u2019 whatever its name or path. Here is the list: ADMINISTRATIVE FOLDER: io.cozy.apps/administrative PHOTOS FOLDER: io.cozy.apps/photos Root Folder of Photos. Used to create PHOTOS_BACKUP FOLDER & PHOTOS_UPLOAD FOLDER PHOTOS_BACKUP FOLDER: io.cozy.apps/photos/mobile Folder used to put photos synched by the native app PHOTOS_UPLOAD FOLDER: io.cozy.apps/photos/upload Folder used to put photos uploaded by the Photo web app.", "title": "Apps"}, {"location": "cozy-doctypes/docs/io.cozy.apps/#table-of-contents", "text": "Table of contents Apps doctype Attributes Example", "title": "Table of contents"}, {"location": "cozy-doctypes/docs/io.cozy.apps/#apps-doctype", "text": "The io.cozy.apps doctype is used to store installed apps. Apps (or Webapps) are core applications used to interact with the instance data. For example, the drive app can handle files, photos will manage photos & albums and banks the financial data. When an app is installed, the Cozy stack creates a new io.cozy.apps document in the instance io.cozy.apps database. You can get more informations on the official docs .", "title": "Apps doctype"}, {"location": "cozy-doctypes/docs/io.cozy.apps/#attributes", "text": "The available attributes in a io.cozy.apps document are available in the official docs: https://docs.cozy.io/en/cozy-apps-registry/#properties-meaning-reference", "title": "Attributes"}, {"location": "cozy-doctypes/docs/io.cozy.apps/#example", "text": "This is the truncated version of the official Cozy drive app. { \"name\" : \"Drive\" , \"name_prefix\" : \"Cozy\" , \"slug\" : \"drive\" , \"version\" : \"1.18.3\" , \"type\" : \"webapp\" , \"licence\" : \"AGPL-3.0\" , \"icon\" : \"public/app-icon.svg\" , \"categories\" : [ \"cozy\" ], \"source\" : \"https://github.com/cozy/cozy-drive\" , \"editor\" : \"Cozy\" , \"developer\" : { \"name\" : \"Cozy Cloud\" , \"url\" : \"https://cozy.io\" }, \"routes\" : { \"/\" : { \"folder\" : \"/\" , \"index\" : \"index.html\" , \"public\" : false }, \"/intents\" : { \"folder\" : \"/intents\" , \"index\" : \"index.html\" , \"public\" : false } }, \"intents\" : [ { \"action\" : \"OPEN\" , \"type\" : [ \"io.cozy.files\" ], \"href\" : \"/intents\" } ], \"permissions\" : { \"files\" : { \"description\" : \"Required to access the files\" , \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"ALL\" ] }, \"apps\" : { \"description\" : \"Required by the cozy-bar to display the icons of the apps\" , \"type\" : \"io.cozy.apps\" , \"verbs\" : [ \"GET\" ] } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.apps/#special-iocozyapps-doctypes", "text": "Some folders are remarkable, like the \u2018Administrative\u2019 and the \u2018Photos\u2019 folders. You shouldn\u2019t address them by their path as it may vary depending on the user language and the user may have renamed them anyways. To identify them, you can ask for a special referenced_by attribute . For example, a request for all io.cozy.files referended by the doctype io.cozy.apps and the document id administrative will return you the io.cozy.files document of the folder \u2018Administrative\u2019 whatever its name or path. Here is the list: ADMINISTRATIVE FOLDER: io.cozy.apps/administrative PHOTOS FOLDER: io.cozy.apps/photos Root Folder of Photos. Used to create PHOTOS_BACKUP FOLDER & PHOTOS_UPLOAD FOLDER PHOTOS_BACKUP FOLDER: io.cozy.apps/photos/mobile Folder used to put photos synched by the native app PHOTOS_UPLOAD FOLDER: io.cozy.apps/photos/upload Folder used to put photos uploaded by the Photo web app.", "title": "Special io.cozy.apps doctypes"}, {"location": "cozy-doctypes/docs/io.cozy.apps.suggestions/", "text": "Table of contents Apps suggestions doctype \u00b6 The io.cozy.apps.suggestions doctype is used to store apps that are not yet installed, but might be useful for the user. io.cozy.apps.suggestions are used by Cozy-Banks to extract which connectors can be suggested to the user based on his / her banking operations and used by Cozy-Pass to extract which connectors can be suggested to the user based on his / her ciphers. Attributes \u00b6 The available attributes in a io.cozy.apps.suggestions document are : slug : {string} - The suggested app\u2019s slug silenced : {boolean} - Whether the user asked to silence the suggestion or not reason : {Object} - An object describing why the suggestion is made reason.code : {string} - A code describing the reason of the suggestion. See below for existing codes Relationships \u00b6 io.cozy.apps.suggestions can have the following relationships: transactions : an array of relationships pointing to io.cozy.bank.operations documents that match with the app Example \u00b6 { \"slug\" : \"deezer\" , \"silenced\" : false , \"reason\" : { \"code\" : \"FOUND_TRANSACTION\" }, \"relationships\" : { \"transactions\" : { \"data\" : [ { \"_id\" : \"12345abcdef\" , \"_type\" : \"io.cozy.bank.operations\" } ] } }, \"cozyMetadata\" : { \"createdAt\" : \"2019-04-01T11:41:32\" , \"createdByApp\" : \"banks\" } } See cozyMetadata documentation for more informations about it. Reason codes \u00b6 FOUND_TRANSACTION : a banking transaction matching this app was found FOUND_CIPHER : a bitwarden cipher matching this app was found", "title": "App suggestions"}, {"location": "cozy-doctypes/docs/io.cozy.apps.suggestions/#apps-suggestions-doctype", "text": "The io.cozy.apps.suggestions doctype is used to store apps that are not yet installed, but might be useful for the user. io.cozy.apps.suggestions are used by Cozy-Banks to extract which connectors can be suggested to the user based on his / her banking operations and used by Cozy-Pass to extract which connectors can be suggested to the user based on his / her ciphers.", "title": "Apps suggestions doctype"}, {"location": "cozy-doctypes/docs/io.cozy.apps.suggestions/#attributes", "text": "The available attributes in a io.cozy.apps.suggestions document are : slug : {string} - The suggested app\u2019s slug silenced : {boolean} - Whether the user asked to silence the suggestion or not reason : {Object} - An object describing why the suggestion is made reason.code : {string} - A code describing the reason of the suggestion. See below for existing codes", "title": "Attributes"}, {"location": "cozy-doctypes/docs/io.cozy.apps.suggestions/#relationships", "text": "io.cozy.apps.suggestions can have the following relationships: transactions : an array of relationships pointing to io.cozy.bank.operations documents that match with the app", "title": "Relationships"}, {"location": "cozy-doctypes/docs/io.cozy.apps.suggestions/#example", "text": "{ \"slug\" : \"deezer\" , \"silenced\" : false , \"reason\" : { \"code\" : \"FOUND_TRANSACTION\" }, \"relationships\" : { \"transactions\" : { \"data\" : [ { \"_id\" : \"12345abcdef\" , \"_type\" : \"io.cozy.bank.operations\" } ] } }, \"cozyMetadata\" : { \"createdAt\" : \"2019-04-01T11:41:32\" , \"createdByApp\" : \"banks\" } } See cozyMetadata documentation for more informations about it.", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.apps.suggestions/#reason-codes", "text": "FOUND_TRANSACTION : a banking transaction matching this app was found FOUND_CIPHER : a bitwarden cipher matching this app was found", "title": "Reason codes"}, {"location": "cozy-doctypes/docs/io.cozy.bank/", "text": "Table of contents Cozy Bank doctypes \u00b6 Cozy can store and manipulate bank related datas, distributed across several doctypes. io.cozy.bank.settings \u00b6 This doctype store information about Bank application settings. There is only one document, by default: { notifications: { amountMax: { enable: false, value: 30 } } } The doctype also stores the following data: - lastImportSuccess : {Object} - Information on the last successful import - savedTransactionsCount : {number} - Number of successfully imported operations - balancesNotifications : {Object} - Informations on the latest accounts balances notified - : {string} - Last notified balance of the account io.cozy.bank.accounts \u00b6 This doctype stores information about a Bank account: label : {string} - The bank account label (e.g. John Doe Bank Account ) institutionLabel : {string} - The financial institution name the bank account belongs to balance : {number} - The current account balance type : {string} - The account type in the list ['none', 'bank', 'cash', 'asset', 'credit card', 'liability'] number : {string} - The bank account number in its institution iban : {string} - The bank account international identifier serviceID : {number} - In case of external service used to import transactions, this key can store the service\u2019s account ID; can be undefined is the account isn\u2019t managed by any external service vendorId : {string} - Id of the bank account on the vendor side loan : {Object} - Specific properties for loan accounts. Will be undefined for all other account types contactName : {string} - The name of the contact in the credit institution totalAmount : {number} - The total amount of the loan availableAmount : {number} - The currently available amount usedAmount : {number} - The amount already used subscriptionDate : {date} - The date on which the loan has been subscribed maturityDate : {date} - The end date of the loan nextPaymentAmount : {number} - The amount of the next payment nextPaymentDate : {date} - The date of the next payment rate : {number} - The loan rate (between 0 and 100) nbPaymentsLeft : {number} - The number of remaining payments nbPaymentsDone : {number} - The number of payments made nbPaymentsTotal : {number} - The total number of payments lastPaymentAmount : {number} - The amount of the last payment lastPaymentDate : {date} - The date of the last payment accountLabel : {string} - The loan account label insuranceLabel : {string} - The insurance label duration : {number} - The loan duration in months relationships : {Object} - Relationships to other documents connection : { HasOne } The account used to retrieve this document. This is used by Harvest to be able to edit an io.cozy.bank.accounts through the \u201cConfiguration\u201d tab of an io.cozy.accounts . checkingsAccount : { HasOne } - In case of a credit card account, links to the bankaccount on which all the transactions will be debited at the end of the month owners : { HasMany } - List of owners for this account Example \u00b6 { \"_id\": \"2165d9a310deadbeeffc08d54c45102\", \"balance\": 1337.73, \"institutionLabel\": \"Soci\u00e9t\u00e9 G\u00e9n\u00e9rale (Particuliers)\", \"label\": \"Livret D\u00e9velop. Durable (x1337)\", \"linxoId\": \"123456\", \"metadata\": { \"version\": 1 }, \"number\": \"03791 00048085818\", \"shortLabel\": \"Livret D\u00e9velop. Durable\", \"type\": \"Savings\", \"relationships\": { \"connection\": { \"_id\": \"2165d9a310deadbeeffc08d54c45404\", \"_type\": \"io.cozy.accounts\" } } } io.cozy.bank.accounts.stats \u00b6 This doctype stores aggregated data about bank accounts: periodStart : {date} - The start of the reference period periodEnd : {date} - The end of the reference period income : {number} - The average income on the reference period additionalIncome : {number} - The average additional income on the reference period mortgage : {number} - The average mortgage expense on the reference period loans : {number} - The average total loans expense on the reference period fixedCharges : {number} - The average fixed charges on the reference period currency : {string} - A 3 uppercased chars defining the currecny used for the transaction as stated in ISO4217 Relationships \u00b6 account : {object} - The associated account Example \u00b6 { \"_id\": \"f1aacd3254509687c07e48279b42cd50\", \"periodStart\": \"2019-03-01T00:00:00\", \"periodEnd\": \"2019-06-30T23:59:59\", \"income\": 2345.67, \"additionalIncome\": 123.45, \"mortgage\": 567.89, \"loans\": 678.9, \"fixedCharges\": 234.56, \"currency\": \"EUR\", \"relationships\": { \"account\": { \"data\": { \"_id\": \"f1aacd3254509687c07e48279b42f3de\", \"_type\": \"io.cozy.bank.accounts\" } } } } io.cozy.bank.operations \u00b6 This doctype stors informations about a bank transaction: label : {string} - The label describing the transaction type : {string} - A type in the list : ['none', 'credit card', 'cash', 'check', 'transfer', 'internal transfer', 'debit card', 'deposit', 'financial fee', 'direct debit'] date : {date} - The debit/credit date of the transaction on which the account is debited/credited. Is different from the realizationDate with deferred debit cards realisationDate : {date} - The realization date of the transaction on which the operation really occured applicationDate : {string} - The date the transaction is affected to, after a manual modification dateOperation : {date} - The date the transaction is registered in the account dateImport : {date} - The date the transaction is imported (can differ of the date of creation of the document as the import can be done by an external service) amount : {number} - The amount of the transaction currency : {string} - A 3 uppercased chars defining the currecny used for the transaction as stated in ISO4217 automaticCategoryId : {string} - A category that apply to the transaction and is automatically calculated. This property should be hydrated by the connector. See the \u00ab categories \u00bb section below to know more about categories manualCategoryId : {string} - A category that apply to the transaction and is manually selected by the user cozyCategoryId : {string} - A category found by Cozy cozyCategoryProba : {number} - The probability of Cozy category localCategoryId : {string} - A category found by Cozy, based on the user recategorization habits localCategoryProba : {number} - The probability of local category account : {identifier} - The related account id the transaction belongs to bills : {array[ ]} - List of bills id. reimbursements : {array[ ]} - List of bills id. creditOperations : {array[ ]} - List of credit operations id debitOperations : {array[ ]} - List of debit operations id parent : {_id} - In case of a split transaction, the one refers the global transaction the split one belongs to vendorId : {string} - Id of the transaction on the vendor side vendorAccountId : {string} - Id of the transaction\u2019s account on the vendor side For the dates, any string or integer which can be interpreted by new Date(date) is possible but the best the result of Date.toString() -> like \u2018Fri Mar 09 2018 19:04:40 GMT+0100 (CET)\u2019 which contains the time zones. Categories \u00b6 There are up to four categories that can be assigned to a io.cozy.bank.operations document. But there is only one that a connector has to set when retrieving the transactions from a bank: automaticCategoryId . This property has to be one of the categories ID listed here . If you want to see more human labels, you can check the translations of each label in english or french . Other category properties are to be set by other sources: the user or Cozy Banks services. Example \u00b6 { \"_id\": \"f0426fdeadbeef55755ee7f4d6555\", \"account\": \"15fb6402426bcdeadbeeffd5f4587bb\", \"amount\": 10, \"automaticCategoryId\": \"400110\", \"currency\": \"EUR\", \"date\": \"2017-09-22 00:00:00+01:00\", \"dateOperation\": null, \"label\": \"M PIERRE RICHARD\", \"linxoId\": \"845811337\", \"cozyCategoryId\": \"400110\", \"cozyCategoryProba\": 0.9323, \"metadata\": { \"dateImport\": \"2018-03-09T09:23:40.075Z\", \"version\": 1 }, \"originalBankLabel\": \"VIR RECU 5383518660S DE: M PIERRE RICHARD J MOTIF: Cascade REF: NOT PROVIDED\", \"type\": \"transfer\" } io.cozy.bank.balancehistories \u00b6 This doctype stores a year of daily balances : year : {number} - The year of the balances balances : {object} - A day (YYYY-MM-DD format) / balance (number) map Relationships \u00b6 account : {object} - The associated account Example \u00b6 { \"_id\": \"f1aacd3254509687c07e48279b42cd50\", \"year\": 2018, \"balances\": { \"2018-01-01\": 8000, \"2018-01-02\": 8000.42, \"2018-01-03\": 1337 }, \"metadata\": { \"version\": 1 }, \"relationships\": { \"account\": { \"data\": { \"_id\": \"f1aacd3254509687c07e48279b42f3de\", \"_type\": \"io.cozy.bank.accounts\" } } } } io.cozy.bank.recurrence \u00b6 Stores a recurrence group information. Those objects are created by the recurrence service that tries to find recurring transactions. Transactions that are found as recurrent have a HasOne relationship to a io.cozy.bank.recurrence object. manualLabel : {string} - The year of the balances automaticLabel : {string} - A day (YYYY-MM-DD format) / balance (number) map amounts : {Array } - Amounts that can be matched to the recurrence (come from the transactions) categoryIds : {Array } - Category ids of the transactions that have been linked status : {Enum<\u201congoing\u201d,\u201dfinished\u201d>} - A recurrence can be stated as \u201cfinished\u201d if transactions should not longer match it. For example if a telco contract has finished. stats : {Object} - Statistics used during matching stats.deltas.median : Median time distance in days between operations. For example, for a monthly recurrence, this should be 30. latestDate : {String} Date of the last transaction that is part of the recurrence. This is used to compute the next occurence of the recurrence latestAmount : {number} Amount of the last transaction that is part of the recurrence. accounts : {Array } Ids of the bank accounts that have participated to the recurrence. This is used to compute planned transactions. io.cozy.bank.groups \u00b6 Groups banks accounts together. label : {string} - Name of the group accounts : {Array} - Ids of io.cozy.bank.accounts Exemple \u00b6 { \"_id\" : \"2a432e54822e7caeed02367a6e1f5739\" , \"accounts\" : [ \"cla4\" , \"gen3\" ], \"id\" : \"2a432e54822e7caeed02367a6e1f5739\" , \"label\" : \"My Group\" } io.cozy.bank.recipients \u00b6 Used to make a transfert vendorAccountId : io.cozy.bank.accounts.vendorId Exemple \u00b6 { \"_id\" : \"recipient_internal_1\" , \"category\" : \"internal\" , \"bankName\" : \"Caisse d'\u00c9pargne\" , \"bic\" : \"CEPAFRPP627\" , \"label\" : \"Isabelle checkings\" , \"currency\" : \"EUR\" , \"iban\" : \"FR3330002005500000157841Z27\" , \"vendorLastUpdate\" : \"2020-02-12 16:12:58\" , \"vendorAccountId\" : 1 , \"deleted\" : null }", "title": "Banking doctypes"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#cozy-bank-doctypes", "text": "Cozy can store and manipulate bank related datas, distributed across several doctypes.", "title": "Cozy Bank doctypes"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybanksettings", "text": "This doctype store information about Bank application settings. There is only one document, by default: { notifications: { amountMax: { enable: false, value: 30 } } } The doctype also stores the following data: - lastImportSuccess : {Object} - Information on the last successful import - savedTransactionsCount : {number} - Number of successfully imported operations - balancesNotifications : {Object} - Informations on the latest accounts balances notified - : {string} - Last notified balance of the account", "title": "io.cozy.bank.settings"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybankaccounts", "text": "This doctype stores information about a Bank account: label : {string} - The bank account label (e.g. John Doe Bank Account ) institutionLabel : {string} - The financial institution name the bank account belongs to balance : {number} - The current account balance type : {string} - The account type in the list ['none', 'bank', 'cash', 'asset', 'credit card', 'liability'] number : {string} - The bank account number in its institution iban : {string} - The bank account international identifier serviceID : {number} - In case of external service used to import transactions, this key can store the service\u2019s account ID; can be undefined is the account isn\u2019t managed by any external service vendorId : {string} - Id of the bank account on the vendor side loan : {Object} - Specific properties for loan accounts. Will be undefined for all other account types contactName : {string} - The name of the contact in the credit institution totalAmount : {number} - The total amount of the loan availableAmount : {number} - The currently available amount usedAmount : {number} - The amount already used subscriptionDate : {date} - The date on which the loan has been subscribed maturityDate : {date} - The end date of the loan nextPaymentAmount : {number} - The amount of the next payment nextPaymentDate : {date} - The date of the next payment rate : {number} - The loan rate (between 0 and 100) nbPaymentsLeft : {number} - The number of remaining payments nbPaymentsDone : {number} - The number of payments made nbPaymentsTotal : {number} - The total number of payments lastPaymentAmount : {number} - The amount of the last payment lastPaymentDate : {date} - The date of the last payment accountLabel : {string} - The loan account label insuranceLabel : {string} - The insurance label duration : {number} - The loan duration in months relationships : {Object} - Relationships to other documents connection : { HasOne } The account used to retrieve this document. This is used by Harvest to be able to edit an io.cozy.bank.accounts through the \u201cConfiguration\u201d tab of an io.cozy.accounts . checkingsAccount : { HasOne } - In case of a credit card account, links to the bankaccount on which all the transactions will be debited at the end of the month owners : { HasMany } - List of owners for this account", "title": "io.cozy.bank.accounts"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#example", "text": "{ \"_id\": \"2165d9a310deadbeeffc08d54c45102\", \"balance\": 1337.73, \"institutionLabel\": \"Soci\u00e9t\u00e9 G\u00e9n\u00e9rale (Particuliers)\", \"label\": \"Livret D\u00e9velop. Durable (x1337)\", \"linxoId\": \"123456\", \"metadata\": { \"version\": 1 }, \"number\": \"03791 00048085818\", \"shortLabel\": \"Livret D\u00e9velop. Durable\", \"type\": \"Savings\", \"relationships\": { \"connection\": { \"_id\": \"2165d9a310deadbeeffc08d54c45404\", \"_type\": \"io.cozy.accounts\" } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybankaccountsstats", "text": "This doctype stores aggregated data about bank accounts: periodStart : {date} - The start of the reference period periodEnd : {date} - The end of the reference period income : {number} - The average income on the reference period additionalIncome : {number} - The average additional income on the reference period mortgage : {number} - The average mortgage expense on the reference period loans : {number} - The average total loans expense on the reference period fixedCharges : {number} - The average fixed charges on the reference period currency : {string} - A 3 uppercased chars defining the currecny used for the transaction as stated in ISO4217", "title": "io.cozy.bank.accounts.stats"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#relationships", "text": "account : {object} - The associated account", "title": "Relationships"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#example_1", "text": "{ \"_id\": \"f1aacd3254509687c07e48279b42cd50\", \"periodStart\": \"2019-03-01T00:00:00\", \"periodEnd\": \"2019-06-30T23:59:59\", \"income\": 2345.67, \"additionalIncome\": 123.45, \"mortgage\": 567.89, \"loans\": 678.9, \"fixedCharges\": 234.56, \"currency\": \"EUR\", \"relationships\": { \"account\": { \"data\": { \"_id\": \"f1aacd3254509687c07e48279b42f3de\", \"_type\": \"io.cozy.bank.accounts\" } } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybankoperations", "text": "This doctype stors informations about a bank transaction: label : {string} - The label describing the transaction type : {string} - A type in the list : ['none', 'credit card', 'cash', 'check', 'transfer', 'internal transfer', 'debit card', 'deposit', 'financial fee', 'direct debit'] date : {date} - The debit/credit date of the transaction on which the account is debited/credited. Is different from the realizationDate with deferred debit cards realisationDate : {date} - The realization date of the transaction on which the operation really occured applicationDate : {string} - The date the transaction is affected to, after a manual modification dateOperation : {date} - The date the transaction is registered in the account dateImport : {date} - The date the transaction is imported (can differ of the date of creation of the document as the import can be done by an external service) amount : {number} - The amount of the transaction currency : {string} - A 3 uppercased chars defining the currecny used for the transaction as stated in ISO4217 automaticCategoryId : {string} - A category that apply to the transaction and is automatically calculated. This property should be hydrated by the connector. See the \u00ab categories \u00bb section below to know more about categories manualCategoryId : {string} - A category that apply to the transaction and is manually selected by the user cozyCategoryId : {string} - A category found by Cozy cozyCategoryProba : {number} - The probability of Cozy category localCategoryId : {string} - A category found by Cozy, based on the user recategorization habits localCategoryProba : {number} - The probability of local category account : {identifier} - The related account id the transaction belongs to bills : {array[ ]} - List of bills id. reimbursements : {array[ ]} - List of bills id. creditOperations : {array[ ]} - List of credit operations id debitOperations : {array[ ]} - List of debit operations id parent : {_id} - In case of a split transaction, the one refers the global transaction the split one belongs to vendorId : {string} - Id of the transaction on the vendor side vendorAccountId : {string} - Id of the transaction\u2019s account on the vendor side For the dates, any string or integer which can be interpreted by new Date(date) is possible but the best the result of Date.toString() -> like \u2018Fri Mar 09 2018 19:04:40 GMT+0100 (CET)\u2019 which contains the time zones.", "title": "io.cozy.bank.operations"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#categories", "text": "There are up to four categories that can be assigned to a io.cozy.bank.operations document. But there is only one that a connector has to set when retrieving the transactions from a bank: automaticCategoryId . This property has to be one of the categories ID listed here . If you want to see more human labels, you can check the translations of each label in english or french . Other category properties are to be set by other sources: the user or Cozy Banks services.", "title": "Categories"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#example_2", "text": "{ \"_id\": \"f0426fdeadbeef55755ee7f4d6555\", \"account\": \"15fb6402426bcdeadbeeffd5f4587bb\", \"amount\": 10, \"automaticCategoryId\": \"400110\", \"currency\": \"EUR\", \"date\": \"2017-09-22 00:00:00+01:00\", \"dateOperation\": null, \"label\": \"M PIERRE RICHARD\", \"linxoId\": \"845811337\", \"cozyCategoryId\": \"400110\", \"cozyCategoryProba\": 0.9323, \"metadata\": { \"dateImport\": \"2018-03-09T09:23:40.075Z\", \"version\": 1 }, \"originalBankLabel\": \"VIR RECU 5383518660S DE: M PIERRE RICHARD J MOTIF: Cascade REF: NOT PROVIDED\", \"type\": \"transfer\" }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybankbalancehistories", "text": "This doctype stores a year of daily balances : year : {number} - The year of the balances balances : {object} - A day (YYYY-MM-DD format) / balance (number) map", "title": "io.cozy.bank.balancehistories"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#relationships_1", "text": "account : {object} - The associated account", "title": "Relationships"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#example_3", "text": "{ \"_id\": \"f1aacd3254509687c07e48279b42cd50\", \"year\": 2018, \"balances\": { \"2018-01-01\": 8000, \"2018-01-02\": 8000.42, \"2018-01-03\": 1337 }, \"metadata\": { \"version\": 1 }, \"relationships\": { \"account\": { \"data\": { \"_id\": \"f1aacd3254509687c07e48279b42f3de\", \"_type\": \"io.cozy.bank.accounts\" } } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybankrecurrence", "text": "Stores a recurrence group information. Those objects are created by the recurrence service that tries to find recurring transactions. Transactions that are found as recurrent have a HasOne relationship to a io.cozy.bank.recurrence object. manualLabel : {string} - The year of the balances automaticLabel : {string} - A day (YYYY-MM-DD format) / balance (number) map amounts : {Array } - Amounts that can be matched to the recurrence (come from the transactions) categoryIds : {Array } - Category ids of the transactions that have been linked status : {Enum<\u201congoing\u201d,\u201dfinished\u201d>} - A recurrence can be stated as \u201cfinished\u201d if transactions should not longer match it. For example if a telco contract has finished. stats : {Object} - Statistics used during matching stats.deltas.median : Median time distance in days between operations. For example, for a monthly recurrence, this should be 30. latestDate : {String} Date of the last transaction that is part of the recurrence. This is used to compute the next occurence of the recurrence latestAmount : {number} Amount of the last transaction that is part of the recurrence. accounts : {Array } Ids of the bank accounts that have participated to the recurrence. This is used to compute planned transactions.", "title": "io.cozy.bank.recurrence"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybankgroups", "text": "Groups banks accounts together. label : {string} - Name of the group accounts : {Array} - Ids of io.cozy.bank.accounts", "title": "io.cozy.bank.groups"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#exemple", "text": "{ \"_id\" : \"2a432e54822e7caeed02367a6e1f5739\" , \"accounts\" : [ \"cla4\" , \"gen3\" ], \"id\" : \"2a432e54822e7caeed02367a6e1f5739\" , \"label\" : \"My Group\" }", "title": "Exemple"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#iocozybankrecipients", "text": "Used to make a transfert vendorAccountId : io.cozy.bank.accounts.vendorId", "title": "io.cozy.bank.recipients"}, {"location": "cozy-doctypes/docs/io.cozy.bank/#exemple_1", "text": "{ \"_id\" : \"recipient_internal_1\" , \"category\" : \"internal\" , \"bankName\" : \"Caisse d'\u00c9pargne\" , \"bic\" : \"CEPAFRPP627\" , \"label\" : \"Isabelle checkings\" , \"currency\" : \"EUR\" , \"iban\" : \"FR3330002005500000157841Z27\" , \"vendorLastUpdate\" : \"2020-02-12 16:12:58\" , \"vendorAccountId\" : 1 , \"deleted\" : null }", "title": "Exemple"}, {"location": "cozy-doctypes/docs/io.cozy.bills/", "text": "Table of contents Bills doctype \u00b6 io.cozy.bills \u00b6 Description \u00b6 Represents a bill (invoice) or a refund from a vendor. Mandatory attributes \u00b6 vendor : {string} - Vendor which issued the bill date : {date} - Date the bill was emitted, a string ISO8601 formated (in JS you can have that with (new Date()).toJSON() ) amount : {number} - Amount of the bill, always positive even if it is a refund currency : the currency, must respects ISO standard : https://en.wikipedia.org/wiki/ISO_4217 Optional attributes (but some are important depending the context) \u00b6 recurrence : {string} : this means that the bills is a recurring one and the value of this attribute gives the frequency. Here is a list of possible values. weekly monthly bi-monthly yearly matchingCriterias : {object} some criterias which can be used to match bills with bank operations labelRegex : {string} (example: \"\\\\bcpam\\\\b\" ) : regexp used to match operation label amountLowerDelta : (float): default 0.001 : positive value. Authorized lower difference between bill amount and bank operation value amountUpperDelta : (float): default 0.001 : positive value. Authorized upper difference between bill amount and bank operation value dateLowerDelta : (int): default 15 : (positive value). Authorized lower difference in days between the bill date and the bank operation date dateUpperDelta : (int): default 29 : (positive value). Authorized upper difference in days between the bill date and the bank operation date type : {string} - Type of the bill (see below for existing types) isRefund : {boolean} - Indicate if the bill represents a refund/reimbursement subtype : {string} - Used for labelling the bill. ie: \u201cOst\u00e9opathie\u201d originalDate - For health bills, represents the date of the health act (presumably the date the account was charged) originalAmount : {number} - Original amount in case of a partial refund groupAmount : Group amount in case this bill was part of a grouped refund thirdPartyRefund : {number} - Amount reimbursed to third parties socialSecurityRefund : {number} - Amount reimbursed to social security isThirdPartyPayer : {boolean} - Indicate if the bill has been already covered by a third party payer. This attribute can be useful when Cozy retrieves bills issued by french medical insurances. When this attribute is in \u201ctrue\u201d no associated debit is expected to be found in the client bank statements. document relationship : {object} - The associated file. ex: \"relationships\" : { \"document\" : { \"data\" : { \"_id\" : \"c43645a93831827c7ec512eac3006e51\" , \"_type\" : \"io.cozy.files\" } } } io.cozy.files:c43645a93831827c7ec512eac3006e51 invoice : {string} - (legacy) The associated file. ex: io.cozy.files:c43645a93831827c7ec512eac3006e51 fileUrl : {string} - The url used to download the pdf from vendor. debitOperations : {array[io.cozy.bank.operations._id]} - List of debit operations id creditOperations : {array[io.cozy.bank.operations._id]} - List of credit operations id vendorRef : {string} - Vendor reference for this bill. Ex : 'INV-2018-09-12534' Types \u00b6 health_costs : Health related bills phone : Phone related bills income : Salary income or allowances related bills Some more attributes for reimbursement bills \u00b6 The are some more possible attributes for reimbursement bills. The original* attributes are there to help the connector to link this bills to their original debit operation. isRefund : {boolean} - Indicate if the bill represents a refund/reimbursement (defaults to false) subtype : {string} - Used for labelling the bill. ie: \u201cOst\u00e9opathie\u201d (optionnal) originalAmount : {number} - Original amount in case of a partial refund originalDate - Represents the date of the associated spent (presumably the date the account was charged) Example \u00b6 { \"_id\": \"62e5d80d6e11d19992b7efce794263f0\", \"amount\": 700, \"beneficiary\": \"PIERRE RICHARD\", \"date\": \"2018-02-07T23:00:00.000Z\", \"groupAmount\": 7.5, \"isRefund\": true, \"metadata\": { \"version\": 1 }, \"originalAmount\": 25, \"originalDate\": \"2018-03-11T23:00:00.000Z\", \"socialSecurityRefund\": 17.5, \"subtype\": \"Consultation sp\u00e9cialiste\", \"type\": \"health_costs\", \"vendor\": \"Harmonie\" } Attributes for pay type \u00b6 date : {date} - The payment date periodStart : {date} - The start of the payment period periodEnd : {date} - The end of the payment period isRefund : {boolean} - Indicates that the pay represents a positive operation employer : {boolean} - The employer name Example \u00b6 { \"_id\": \"62e5d80d6e11d19992b7efce794263f0\", \"vendor\": \"Payfit\", \"type\": \"pay\", \"amount\": 1500, \"date\": \"2018-10-31T00:00:00.000Z\", \"periodStart\": \"2018-10-01T00:00:00.000Z\", \"periodEnd\": \"2018-10-31T00:00:00.000Z\", \"employer\": \"COZY CLOUD\", \"isRefund\": true, \"metadata\": { \"version\": 1 } \"relationships\": { \"document\": { \"data\": { \"_id\": \"c43645a93831827c7ec512eac3006e51\", \"_type\": \"io.cozy.files\" } } } }", "title": "Bills"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#bills-doctype", "text": "", "title": "Bills doctype"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#iocozybills", "text": "", "title": "io.cozy.bills"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#description", "text": "Represents a bill (invoice) or a refund from a vendor.", "title": "Description"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#mandatory-attributes", "text": "vendor : {string} - Vendor which issued the bill date : {date} - Date the bill was emitted, a string ISO8601 formated (in JS you can have that with (new Date()).toJSON() ) amount : {number} - Amount of the bill, always positive even if it is a refund currency : the currency, must respects ISO standard : https://en.wikipedia.org/wiki/ISO_4217", "title": "Mandatory attributes"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#optional-attributes-but-some-are-important-depending-the-context", "text": "recurrence : {string} : this means that the bills is a recurring one and the value of this attribute gives the frequency. Here is a list of possible values. weekly monthly bi-monthly yearly matchingCriterias : {object} some criterias which can be used to match bills with bank operations labelRegex : {string} (example: \"\\\\bcpam\\\\b\" ) : regexp used to match operation label amountLowerDelta : (float): default 0.001 : positive value. Authorized lower difference between bill amount and bank operation value amountUpperDelta : (float): default 0.001 : positive value. Authorized upper difference between bill amount and bank operation value dateLowerDelta : (int): default 15 : (positive value). Authorized lower difference in days between the bill date and the bank operation date dateUpperDelta : (int): default 29 : (positive value). Authorized upper difference in days between the bill date and the bank operation date type : {string} - Type of the bill (see below for existing types) isRefund : {boolean} - Indicate if the bill represents a refund/reimbursement subtype : {string} - Used for labelling the bill. ie: \u201cOst\u00e9opathie\u201d originalDate - For health bills, represents the date of the health act (presumably the date the account was charged) originalAmount : {number} - Original amount in case of a partial refund groupAmount : Group amount in case this bill was part of a grouped refund thirdPartyRefund : {number} - Amount reimbursed to third parties socialSecurityRefund : {number} - Amount reimbursed to social security isThirdPartyPayer : {boolean} - Indicate if the bill has been already covered by a third party payer. This attribute can be useful when Cozy retrieves bills issued by french medical insurances. When this attribute is in \u201ctrue\u201d no associated debit is expected to be found in the client bank statements. document relationship : {object} - The associated file. ex: \"relationships\" : { \"document\" : { \"data\" : { \"_id\" : \"c43645a93831827c7ec512eac3006e51\" , \"_type\" : \"io.cozy.files\" } } } io.cozy.files:c43645a93831827c7ec512eac3006e51 invoice : {string} - (legacy) The associated file. ex: io.cozy.files:c43645a93831827c7ec512eac3006e51 fileUrl : {string} - The url used to download the pdf from vendor. debitOperations : {array[io.cozy.bank.operations._id]} - List of debit operations id creditOperations : {array[io.cozy.bank.operations._id]} - List of credit operations id vendorRef : {string} - Vendor reference for this bill. Ex : 'INV-2018-09-12534'", "title": "Optional attributes (but some are important depending the context)"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#types", "text": "health_costs : Health related bills phone : Phone related bills income : Salary income or allowances related bills", "title": "Types"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#some-more-attributes-for-reimbursement-bills", "text": "The are some more possible attributes for reimbursement bills. The original* attributes are there to help the connector to link this bills to their original debit operation. isRefund : {boolean} - Indicate if the bill represents a refund/reimbursement (defaults to false) subtype : {string} - Used for labelling the bill. ie: \u201cOst\u00e9opathie\u201d (optionnal) originalAmount : {number} - Original amount in case of a partial refund originalDate - Represents the date of the associated spent (presumably the date the account was charged)", "title": "Some more attributes for reimbursement bills"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#example", "text": "{ \"_id\": \"62e5d80d6e11d19992b7efce794263f0\", \"amount\": 700, \"beneficiary\": \"PIERRE RICHARD\", \"date\": \"2018-02-07T23:00:00.000Z\", \"groupAmount\": 7.5, \"isRefund\": true, \"metadata\": { \"version\": 1 }, \"originalAmount\": 25, \"originalDate\": \"2018-03-11T23:00:00.000Z\", \"socialSecurityRefund\": 17.5, \"subtype\": \"Consultation sp\u00e9cialiste\", \"type\": \"health_costs\", \"vendor\": \"Harmonie\" }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#attributes-for-pay-type", "text": "date : {date} - The payment date periodStart : {date} - The start of the payment period periodEnd : {date} - The end of the payment period isRefund : {boolean} - Indicates that the pay represents a positive operation employer : {boolean} - The employer name", "title": "Attributes for pay type"}, {"location": "cozy-doctypes/docs/io.cozy.bills/#example_1", "text": "{ \"_id\": \"62e5d80d6e11d19992b7efce794263f0\", \"vendor\": \"Payfit\", \"type\": \"pay\", \"amount\": 1500, \"date\": \"2018-10-31T00:00:00.000Z\", \"periodStart\": \"2018-10-01T00:00:00.000Z\", \"periodEnd\": \"2018-10-31T00:00:00.000Z\", \"employer\": \"COZY CLOUD\", \"isRefund\": true, \"metadata\": { \"version\": 1 } \"relationships\": { \"document\": { \"data\": { \"_id\": \"c43645a93831827c7ec512eac3006e51\", \"_type\": \"io.cozy.files\" } } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.coachco2/", "text": "Cozy CoachCO2 settings doctype \u00b6 Description \u00b6 This doctype stores information about CoachCO2 application settings. There is only one document. Attributes: \u00b6 account : {Object} - Current account displayed, copy of the associated io.cozy.account document bikeGoal : {Object} - Informations about the bike goal feature showAlert : {boolean} - Whether an alert is displayed requesting activation of the bike goal feature showAlertSuccess : {boolean} - Whether an alert is displayed when the goal is reached activated : {boolean} - Whether the feature is enabled sendToDACC : {boolean} - Whether the user has agreed to share their data with the DACC onboarded : {boolean} - Whether the user as completed the onboarding onboardingStep : {number} - The actual onboard step of the user firstname : {string} - The user\u2019s firstname requested in the onboarding lastname : {string} - The user\u2019s lastname requested in the onboarding daysToReach : {number} - The user\u2019s goal days to reach requested in the onboarding CO2Emission : {Object} - Informations about the CO2 Emission feature showAlert : {boolean} - Whether an alert is displayed requesting activation of the DACC sendToDACC : {boolean} - Whether the user has agreed to share their data with the DACC hidePoiModal : {boolean} - Whether to display the POI modal when changing the purpose (except for the \u201cGoing to or from work\u201d choice) isAllAccountsSelected : {boolean} - If the \u201call sources\u201d option is selected, in this case account is null", "title": "CoachCO2"}, {"location": "cozy-doctypes/docs/io.cozy.coachco2/#cozy-coachco2-settings-doctype", "text": "", "title": "Cozy CoachCO2 settings doctype"}, {"location": "cozy-doctypes/docs/io.cozy.coachco2/#description", "text": "This doctype stores information about CoachCO2 application settings. There is only one document.", "title": "Description"}, {"location": "cozy-doctypes/docs/io.cozy.coachco2/#attributes", "text": "account : {Object} - Current account displayed, copy of the associated io.cozy.account document bikeGoal : {Object} - Informations about the bike goal feature showAlert : {boolean} - Whether an alert is displayed requesting activation of the bike goal feature showAlertSuccess : {boolean} - Whether an alert is displayed when the goal is reached activated : {boolean} - Whether the feature is enabled sendToDACC : {boolean} - Whether the user has agreed to share their data with the DACC onboarded : {boolean} - Whether the user as completed the onboarding onboardingStep : {number} - The actual onboard step of the user firstname : {string} - The user\u2019s firstname requested in the onboarding lastname : {string} - The user\u2019s lastname requested in the onboarding daysToReach : {number} - The user\u2019s goal days to reach requested in the onboarding CO2Emission : {Object} - Informations about the CO2 Emission feature showAlert : {boolean} - Whether an alert is displayed requesting activation of the DACC sendToDACC : {boolean} - Whether the user has agreed to share their data with the DACC hidePoiModal : {boolean} - Whether to display the POI modal when changing the purpose (except for the \u201cGoing to or from work\u201d choice) isAllAccountsSelected : {boolean} - If the \u201call sources\u201d option is selected, in this case account is null", "title": "Attributes:"}, {"location": "cozy-doctypes/docs/io.cozy.contacts/", "text": "Table of contents Cozy Contacts doctype \u00b6 io.cozy.contacts \u00b6 The io.cozy.contacts doctype is loosely based on the vCard RFC , in that some of the attributes have been renamed for clarity. The attributes with a ? are optional. indexes : {object} Used to sort contacts in different ways byFamilyNameGivenNameEmailCozyUrl : {string} displayName : {string} Displayed name in cozy applications fullname? : {string} Unstructured representation of the name (example: \"Dr. Gregory House, M.D.\" ) name? : {object} Optional structured representation of the name, with the following possible attributes: familyName? : {string} (example: \"House\" ) givenName? : {string} (example: \"Gregory\" ) additionalName? : {string} (example: \"J.\" ) namePrefix? : {string} (example: \"Dr.\" ) nameSuffix? : {string} (example: \"III\" ) birthday? : {date} (example: \"1959-05-15\" ) gender? : {string} male|female note? : {string} email? : {array} An array of email addresses objects with the following attributes: address : {string} Email address type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ) label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use address address? : {array} An array of postal addresses objects with the following attributes: id? : {string} id of the address street? : {string} Street name pobox? : {string} P.O Box number city? : {string} City name region? : {string} Region name number? : {string} Lane number code? : {string} Postal code country? : {string} Country name type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ) label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use address extendedAddress? : {object} locality? : {string} Locality name building? : {string} Building number stairs? : {string} Stairs number floor? : {string} Apartment floor apartment? : {string} Apartment number entrycode? : {string} Entry code formattedAddress? : {string} Unstructured version of the address geo? : {object} geo? : {array} Coordinates of the address, must be [long, lat] cozyCategory? : {\u201chome|work\u201d} The category of the address type phone? : {array} An array of phone number objects with the following attributes: number : {string} type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ), could be provided by Contacts app too as voice|fax|cell label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use number cozy? : {array} An array of cozy instances with the following attributes: url : {string} type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ) label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use instance url? : {string} Deprecated. Cozy instance url. Use cozy? array of cozy instances instead. company : {string} Company jobTitle : {string} Job title relationships : {object} links between documents groups : {object} groups the contact belongs to data : {array} list of groups _id : {string} id of the io.cozy.contacts.groups document _type : {string} doctype \u201cio.cozy.contacts.groups\u201d accounts : {object} data : {array} list of accounts _id : {string} id of the io.cozy.contacts.accounts document _type : {string} doctype \u201cio.cozy.contacts.accounts\u201d trashed? : {boolean} is true if the contact is marked for removal and will be deleted soon (e.g. after remote deletion is confirmed) me : {boolean} whether the contact matches the cozy owner (defaults to false ) nationalities? : {array} 2-letter iso3166 country codes (can be set in io.cozy.identities for legal reasons in Banks) birthcity? : {string} City of birth of a contact (can be set in io.cozy.identities for legal reasons in Banks) birthcountry? : {string} Country of birth of a contact (can be set in io.cozy.identities for legal reasons in Banks) metadata : {object} previous metadata information. cozy : {boolean} whether the contact has been created by cozy google : {object} Google metadata version : {integer} used for migrations. Current version is 1 cozyMetaData : {object} \u2026 cozyMetadata : Document metadata sync : {object} ded4265b38c54b0683408c76d9ebd : {object} id of the sourceContactsAccount konnector : {string} example : \"google\" lastSync : {date} (example: \"2018-10-19T10:58:37.025688+02:00\" ) Last time a sync task updated this contact contactsAccountsId : {string} id of the io.cozy.contacts.accounts object id : {string} id of the remote object remoteRev : {string} latest rev of the remote object io.cozy.contacts.groups \u00b6 Used to group contacts together. A group can obviously have multiple contacts, but contacts can also be part of multiple groups. name : {string} is the group\u2019s public name trashed? : {boolean} is true if the group is marked for removal and will be deleted soon metadata : {object} version : {integer} Used for migrations. Current version is 1 relationships : {object} links between documents accounts : {object} data : {array} list of accounts _id : {string} id of the io.cozy.contacts.accounts document _type : {string} doctype \u201cio.cozy.contacts.accounts\u201d cozyMetaData : {object} \u2026 cozyMetadata : Document metadata sync : {object} ded4265b38c54b0683408c76d9ebd : {object} id of the io.cozy.contacts.accounts object konnector : {string} example : \"google\" lastSync : {date} (example: \"2018-10-19T10:58:37.025688+02:00\" ) contactsAccountsId : {string} id of the io.cozy.contacts.accounts object id : {string} id of the remote object remoteRev : {string} latest rev of the remote object io.cozy.contacts.accounts \u00b6 Used to know which accounts (Google, Apple, etc) a contact is related to. id : {id} id of the io.cozy.contacts.account object name : {string} name of the account (example: \"toto@gmail.com\" ) type : {string} konnector type (example: \"konnector-google\" ) canLinkContacts : {boolean} whether contacts can be linked or unlinked to this source shouldSyncOrphan : {boolean} whether we should sync orphans with this account or not sourceAccount : {string} id of the related io.cozy.accounts lastSync : {date} last remote sync (example: \"2018-10-19T10:58:37.025688+02:00\" ) lastLocalSync : {date} last local sync (example: \"2018-10-19T10:58:37.025688+02:00\" ) syncToken : {string} used to only retrieve what have been edited since last sync (See request sync token ) version : {integer}", "title": "Contacts"}, {"location": "cozy-doctypes/docs/io.cozy.contacts/#cozy-contacts-doctype", "text": "", "title": "Cozy Contacts doctype"}, {"location": "cozy-doctypes/docs/io.cozy.contacts/#iocozycontacts", "text": "The io.cozy.contacts doctype is loosely based on the vCard RFC , in that some of the attributes have been renamed for clarity. The attributes with a ? are optional. indexes : {object} Used to sort contacts in different ways byFamilyNameGivenNameEmailCozyUrl : {string} displayName : {string} Displayed name in cozy applications fullname? : {string} Unstructured representation of the name (example: \"Dr. Gregory House, M.D.\" ) name? : {object} Optional structured representation of the name, with the following possible attributes: familyName? : {string} (example: \"House\" ) givenName? : {string} (example: \"Gregory\" ) additionalName? : {string} (example: \"J.\" ) namePrefix? : {string} (example: \"Dr.\" ) nameSuffix? : {string} (example: \"III\" ) birthday? : {date} (example: \"1959-05-15\" ) gender? : {string} male|female note? : {string} email? : {array} An array of email addresses objects with the following attributes: address : {string} Email address type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ) label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use address address? : {array} An array of postal addresses objects with the following attributes: id? : {string} id of the address street? : {string} Street name pobox? : {string} P.O Box number city? : {string} City name region? : {string} Region name number? : {string} Lane number code? : {string} Postal code country? : {string} Country name type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ) label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use address extendedAddress? : {object} locality? : {string} Locality name building? : {string} Building number stairs? : {string} Stairs number floor? : {string} Apartment floor apartment? : {string} Apartment number entrycode? : {string} Entry code formattedAddress? : {string} Unstructured version of the address geo? : {object} geo? : {array} Coordinates of the address, must be [long, lat] cozyCategory? : {\u201chome|work\u201d} The category of the address type phone? : {array} An array of phone number objects with the following attributes: number : {string} type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ), could be provided by Contacts app too as voice|fax|cell label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use number cozy? : {array} An array of cozy instances with the following attributes: url : {string} type? : {string} A user-provided localized type (example: \"Personnal\" , \"Profressional\" , \"Other\" ) label? : {string} A keyword to identify the type, must be work|home primary? : {boolean} Indicates a preferred-use instance url? : {string} Deprecated. Cozy instance url. Use cozy? array of cozy instances instead. company : {string} Company jobTitle : {string} Job title relationships : {object} links between documents groups : {object} groups the contact belongs to data : {array} list of groups _id : {string} id of the io.cozy.contacts.groups document _type : {string} doctype \u201cio.cozy.contacts.groups\u201d accounts : {object} data : {array} list of accounts _id : {string} id of the io.cozy.contacts.accounts document _type : {string} doctype \u201cio.cozy.contacts.accounts\u201d trashed? : {boolean} is true if the contact is marked for removal and will be deleted soon (e.g. after remote deletion is confirmed) me : {boolean} whether the contact matches the cozy owner (defaults to false ) nationalities? : {array} 2-letter iso3166 country codes (can be set in io.cozy.identities for legal reasons in Banks) birthcity? : {string} City of birth of a contact (can be set in io.cozy.identities for legal reasons in Banks) birthcountry? : {string} Country of birth of a contact (can be set in io.cozy.identities for legal reasons in Banks) metadata : {object} previous metadata information. cozy : {boolean} whether the contact has been created by cozy google : {object} Google metadata version : {integer} used for migrations. Current version is 1 cozyMetaData : {object} \u2026 cozyMetadata : Document metadata sync : {object} ded4265b38c54b0683408c76d9ebd : {object} id of the sourceContactsAccount konnector : {string} example : \"google\" lastSync : {date} (example: \"2018-10-19T10:58:37.025688+02:00\" ) Last time a sync task updated this contact contactsAccountsId : {string} id of the io.cozy.contacts.accounts object id : {string} id of the remote object remoteRev : {string} latest rev of the remote object", "title": "io.cozy.contacts"}, {"location": "cozy-doctypes/docs/io.cozy.contacts/#iocozycontactsgroups", "text": "Used to group contacts together. A group can obviously have multiple contacts, but contacts can also be part of multiple groups. name : {string} is the group\u2019s public name trashed? : {boolean} is true if the group is marked for removal and will be deleted soon metadata : {object} version : {integer} Used for migrations. Current version is 1 relationships : {object} links between documents accounts : {object} data : {array} list of accounts _id : {string} id of the io.cozy.contacts.accounts document _type : {string} doctype \u201cio.cozy.contacts.accounts\u201d cozyMetaData : {object} \u2026 cozyMetadata : Document metadata sync : {object} ded4265b38c54b0683408c76d9ebd : {object} id of the io.cozy.contacts.accounts object konnector : {string} example : \"google\" lastSync : {date} (example: \"2018-10-19T10:58:37.025688+02:00\" ) contactsAccountsId : {string} id of the io.cozy.contacts.accounts object id : {string} id of the remote object remoteRev : {string} latest rev of the remote object", "title": "io.cozy.contacts.groups"}, {"location": "cozy-doctypes/docs/io.cozy.contacts/#iocozycontactsaccounts", "text": "Used to know which accounts (Google, Apple, etc) a contact is related to. id : {id} id of the io.cozy.contacts.account object name : {string} name of the account (example: \"toto@gmail.com\" ) type : {string} konnector type (example: \"konnector-google\" ) canLinkContacts : {boolean} whether contacts can be linked or unlinked to this source shouldSyncOrphan : {boolean} whether we should sync orphans with this account or not sourceAccount : {string} id of the related io.cozy.accounts lastSync : {date} last remote sync (example: \"2018-10-19T10:58:37.025688+02:00\" ) lastLocalSync : {date} last local sync (example: \"2018-10-19T10:58:37.025688+02:00\" ) syncToken : {string} used to only retrieve what have been edited since last sync (See request sync token ) version : {integer}", "title": "io.cozy.contacts.accounts"}, {"location": "cozy-doctypes/docs/io.cozy.docrules/", "text": "Table of contents Cozy DocRules doctype \u00b6 io.cozy.docrules \u00b6 This doctype represents docrules , i.e. rules used to retrieve documents in the Cozy. _id : {string} - The fixed rule ID, that should respect this nomenclature: .docrules/ . For instance: io.cozy.docrules/payslips . description : {string} - The rule description. doctype : {string} - The doctype of the documents targeted by the rule. rule : {object} limit : {number} - The maximum number of documents to retrieve with this rule. selector : {object} - The selector to target documents, following the Mango syntax Note the rule attributes, i.e. limit and selector can be parametrised by using a {var-name} notation. In the example below, {date} is a rule parameter used to find payslips before this date, while {limit} restricts the number of documents retrieved. See here for an example on how to pass parameters to a rule. Example \u00b6 { \"_id\" : \"io.cozy.docrules/payslips\" , \"description\" : \"Get payslips from the given date\" , \"doctype\" : \"io.cozy.files\" , \"rule\" : { \"limit\" : \"{limit}\" , \"selector\" : { \"cozyMetadata.classification\" : \"payslip\" , \"cozyMetadata.createdAt\" : { \"$lt\" : \"{date}\" } } } }", "title": "DocRules"}, {"location": "cozy-doctypes/docs/io.cozy.docrules/#cozy-docrules-doctype", "text": "", "title": "Cozy DocRules doctype"}, {"location": "cozy-doctypes/docs/io.cozy.docrules/#iocozydocrules", "text": "This doctype represents docrules , i.e. rules used to retrieve documents in the Cozy. _id : {string} - The fixed rule ID, that should respect this nomenclature: .docrules/ . For instance: io.cozy.docrules/payslips . description : {string} - The rule description. doctype : {string} - The doctype of the documents targeted by the rule. rule : {object} limit : {number} - The maximum number of documents to retrieve with this rule. selector : {object} - The selector to target documents, following the Mango syntax Note the rule attributes, i.e. limit and selector can be parametrised by using a {var-name} notation. In the example below, {date} is a rule parameter used to find payslips before this date, while {limit} restricts the number of documents retrieved. See here for an example on how to pass parameters to a rule.", "title": "io.cozy.docrules"}, {"location": "cozy-doctypes/docs/io.cozy.docrules/#example", "text": "{ \"_id\" : \"io.cozy.docrules/payslips\" , \"description\" : \"Get payslips from the given date\" , \"doctype\" : \"io.cozy.files\" , \"rule\" : { \"limit\" : \"{limit}\" , \"selector\" : { \"cozyMetadata.classification\" : \"payslip\" , \"cozyMetadata.createdAt\" : { \"$lt\" : \"{date}\" } } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.exports/", "text": "Cozy exports doctype io.cozy.exports Cozy exports doctype \u00b6 io.cozy.exports \u00b6 The io.cozy.exports doctype holds the informations about the instance exports. An export is divided into several parts of equal size. domain {string}: The instance domain of the export parts_size {int}: Size of each export part parts_cursors {[]string}: List of cursors parts with_doctypes {[]string}: List of exported doctypes without_files {bool}: Either the files are exported or not state : {string}: State of the export (exporting/done/error) created_at {timestamp}: Date of creation expires_at {timestamp}: Date of expiration total_size : Total size of the export, with all the parts creation_duration {duration}: Total elapsed time for the export generation", "title": "Exports"}, {"location": "cozy-doctypes/docs/io.cozy.exports/#cozy-exports-doctype", "text": "", "title": "Cozy exports doctype"}, {"location": "cozy-doctypes/docs/io.cozy.exports/#iocozyexports", "text": "The io.cozy.exports doctype holds the informations about the instance exports. An export is divided into several parts of equal size. domain {string}: The instance domain of the export parts_size {int}: Size of each export part parts_cursors {[]string}: List of cursors parts with_doctypes {[]string}: List of exported doctypes without_files {bool}: Either the files are exported or not state : {string}: State of the export (exporting/done/error) created_at {timestamp}: Date of creation expires_at {timestamp}: Date of expiration total_size : Total size of the export, with all the parts creation_duration {duration}: Total elapsed time for the export generation", "title": "io.cozy.exports"}, {"location": "cozy-doctypes/docs/io.cozy.files/", "text": "Table of contents Cozy Files doctype \u00b6 io.cozy.files \u00b6 The io.cozy.files doctype is used for both the files and directories. Folder \u00b6 For a folder, its attributes are: type : {string} always directory name : {string} the directory name path : {string} the path to this directory, which is the path of its parent, then / , then its name restore_path : {string} the restore path of the directory, if is in the trash created_at : {timestamp} the date of the creation of this directory given by the client updated_at : {timestamp} the date of the last update of this directory given by the client tags : {array of strings} a list of tags It also has a relationship with its parent in the JSON-API representation, and another called data with the files and directory inside it. Files \u00b6 The attributes of a file are: type : {string} always file name : {string} the file name trashed : {bool} true if the file is in the trash restore_path : {string} the restore path of the file, if is in the trash md5sum : {string} the checksum of its content, computed with the MD5 algorithm created_at : {date} the date of the creation of this file given by the client updated_at : {date} the date of the last update of this file given by the client tags : {array of strings} a list of tags. It is currently used to know if a file was uploaded through the mobile photo sync, with the value library . size : {number} the size of its content, in bytes executable : {bool} true is the file has the executable bit on UNIX ( chmod +x ) class : {string} a class in the list: ['image', 'document', 'audio', 'video', 'text', 'binary', 'pdf', 'files', 'code', 'slide', 'spreadsheet', 'text', 'zip', 'shortcut'] mime : {string} the full mime-type metadata : {map} an optional map of metadata ( Full metadata description ), with for example: width : {number} height : {number} datetime : {date} : date in original image file metadata gps : {map} : localization metadata with the following attributes lat : {float}: latitude long : {float}: longitude city : {string}: nearest city (optional) zip : {string}: postal code of the nearest city (optional) country : {string}: name of the associated country if any (optional) persons : {array}: the maps can have the following attributes (optional) name : {string}: then name of the tagged person on the photo created_at : {date}: date of creation of the tag x : {float}: x coordinate in the photo where the person is y : {float}: y coordinate in the photo where the person is icon : {string} : A small SVG file to use as icon for this file (optional) carbonCopy : {boolean} : if the document is the original document imported by the connector electronicSafe : {boolean} : if the document is secured in a secure storage \u26a0 carbonCopy and electronicSafe both need specific permission to be added to a document. It also has a relationship with its parent in the JSON-API representation. For an image , there are 3 links to thumbnails: small , medium , and large . These thumbnail links are valid for 10 minutes. After that, links will return a 400 Bad Request response code. Trash \u00b6 When a file or a directory is put in the trash bin, some attributes are updated: - trashed is set to true, but only for files: directories never have this attribute. - The restore_path is set, for both files and directories. - \u26a0\ufe0f The restore_path is not set on children. For instance, if a directory foo is trashed, it will have a restore_path but not the children. - The path is updated only for directories, starting with .cozy_trash Here is how one could query files and directories not in the trash, through a mango query: _id: { $ne: 'io.cozy.files.trash-dir' }, path: { $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] }, trashed: { $or: [{ $exists: false }, { $eq: false }] } References \u00b6 It\u2019s possible to link a file or a folder to another document. It\u2019s called a reference . It appears in the JSON-API representation as a refererenced_by relationship. CozyMetadata \u00b6 The io.cozy.files doctype has the standard cozyMetadata , but with some more fields: createdOn : {string} the instance URL on which the file has created (useful if the file is shared between several cozy instances) uploadedAt : {date} the server date/time of the last upload (when the content was changed) uploadedOn : {string} the instance URL on which the file content was changed the last time uploadedBy : {map} information on which app has made the last upload slug : {string} the slug of the application that has made the upload version : {string} the version number of this application oauthClient : {map} if the upload was made by an OAuth Client, information about it ( id , name , and kind ) Example (JSON-API format) \u00b6 { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"3-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"sunset.jpg\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2018-01-02T20:38:04Z\" , \"updated_at\" : \"2019-06-12T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2018-01-02T20:38:04Z\" , \"height\" : 1080 , \"width\" : 1920 , \"icon\" : \"\" }, \"size\" : 12 , \"executable\" : false , \"class\" : \"image\" , \"mime\" : \"image/jpg\" , \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-06-11T01:02:03Z\" , \"createdByApp\" : \"flickr\" , \"createdByAppVersion\" : \"1.2.3\" , \"createdOn\" : \"https://alice.cozy.example\" , \"updatedAt\" : \"2019-06-12T12:40:06Z\" , \"updatedByApps\" : [ { \"slug\" : \"flickr\" , \"date\" : \"2019-06-11T01:02:03Z\" , \"version\" : \"1.2.3\" , \"instance\" : \"https://alice.cozy.example\" }, { \"slug\" : \"cozy-desktop\" , \"date\" : \"2019-06-12T12:40:06Z\" , \"version\" : \"3.13.2\" , \"instance\" : \"https://alice.cozy.example\" } ], \"uploadedAt\" : \"2019-06-11T20:34:56Z\" , \"uploadedOn\" : \"https://alice.cozy.example\" , \"uploadedBy\" : { \"slug\" : \"cozy-desktop\" , \"version\" : \"3.13.2\" , \"oauthClient\" : { \"id\" : \"9aaa6886-8b69-11e9-8412-b7855fb3838f\" , \"kind\" : \"desktop\" , \"name\" : \"Cozy Drive - mac book pro d'Alice\" } }, \"sourceAccount\" : \"07b49550-8b60-11e9-bb7e-87717e829039\" , \"sourceAccountIdentifier\" : \"157ae784\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references\" }, \"data\" : [ { \"type\" : \"io.cozy.albums\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"small\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/small\" , \"medium\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/medium\" , \"large\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/large\" } } } Shortcuts \u00b6 Shortcuts (or hyperlinks) are a special type of files. They are served with the application/internet-shortcut mime-type, they have a .url extension, and respect the URL file format . They can have metadata : sharing.status will be set if the link can be used to open a sharing. 2 values are possible: new and seen , depending on whether the link has been opened. target.cozyMetadata.instance is set to the cozy instance when relevant (mostly sharing and internal links) target._type is the doctype of the destination of the link (when the link goes to a sharing or document inside a cozy) target.mime is the mime-type of the destination of the link (when it is a file) target.app is the slug of the destination app (internal links only). icon {string?} contains the base64 encoded image or svg binary if mimetype is not present. iconMimeType {string?} contains the mime-type of the icon. Example (JSON format) \u00b6 { \"_id\" : \"629fb233be550a21174ac8e19f0043af\" , \"_rev\" : \"1-61c7804bdb4f9f8dae5a363cb9a30dd8\" , \"type\" : \"file\" , \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"trashed\" : false , \"md5sum\" : \"vfEMDpJShs8QeIlsDmw9VA==\" , \"created_at\" : \"2020-02-10T20:38:04Z\" , \"updated_at\" : \"2020-02-10T20:38:04Z\" , \"tags\" : [], \"metadata\" : { \"sharing\" : { \"status\" : \"new\" }, \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" }, \"icon\" : \"[encoded base64 string of the content of the icon or svg binary]\" , \"iconMimeType\" : \"image/svg+xml\" }, \"size\" : 62 , \"executable\" : false , \"class\" : \"shortcut\" , \"mime\" : \"application/shortcut\" , \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-02-10T20:38:04Z\" , \"createdOn\" : \"https://bob.cozy.example/\" , \"updatedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedOn\" : \"https://bob.cozy.example/\" } } io.cozy.files.versions \u00b6 The io.cozy.files.versions is used to track old versions of a file content, when files versioning is enabled. The attributes of a version are: size : {number} the size of its content, in bytes md5sum : {string} the checksum of its content, computed with the MD5 algorithm updated_at : {date} the date of the last update of this file given by the client tags : {array of strings} a list of tags metadata : {map} an optional map of metadata. It also has the same cozyMetadata that a file (including the uploaded* fields), and a relationship to the versioned file. Example (CouchDB format) \u00b6 { \"_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/3-0e6d5b72\" , \"_rev\" : \"1-782839bf19cf4edbc29b82f77b28482f\" , \"updated_at\" : \"2019-06-12T12:38:04Z\" , \"size\" : \"12\" , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2018-01-02T20:38:04Z\" , \"height\" : 1080 , \"width\" : 1920 }, \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-06-11T20:34:56Z\" , \"createdOn\" : \"https://alice.cozy.example\" , \"updatedAt\" : \"2019-06-11T20:34:56Z\" , \"uploadedAt\" : \"2019-06-11T20:34:56Z\" , \"uploadedBy\" : { \"slug\" : \"drive\" }, \"uploadedOn\" : \"https://alice.cozy.example\" }, \"relationships\" : { \"file\" : { \"data\" : { \"_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"_type\" : \"io.cozy.files\" } } } } io.cozy.files.settings \u00b6 This doctype is used to store settings for files. It is currenly only used for the qualification migration service. lastProcessedFileDate: {string} the cozyMetadata.updatedAt date of the last processed file. It is used to know from where the query should be starting on an index sorted by date. io.cozy.files.encryption \u00b6 This doctype is used to store encryption keys for directories. The encryption keys are stored encrypted in the same way than bitwarden\u2019s ciphers , and are used to encrypt/decrypt files\u2019 binary inside the directory. _id : {string} refers to its directory id: io.cozy.files/ key : {string} the encrypted key, used to encrypt/decrypt files inside the directory.", "title": "Files"}, {"location": "cozy-doctypes/docs/io.cozy.files/#cozy-files-doctype", "text": "", "title": "Cozy Files doctype"}, {"location": "cozy-doctypes/docs/io.cozy.files/#iocozyfiles", "text": "The io.cozy.files doctype is used for both the files and directories.", "title": "io.cozy.files"}, {"location": "cozy-doctypes/docs/io.cozy.files/#folder", "text": "For a folder, its attributes are: type : {string} always directory name : {string} the directory name path : {string} the path to this directory, which is the path of its parent, then / , then its name restore_path : {string} the restore path of the directory, if is in the trash created_at : {timestamp} the date of the creation of this directory given by the client updated_at : {timestamp} the date of the last update of this directory given by the client tags : {array of strings} a list of tags It also has a relationship with its parent in the JSON-API representation, and another called data with the files and directory inside it.", "title": "Folder"}, {"location": "cozy-doctypes/docs/io.cozy.files/#files", "text": "The attributes of a file are: type : {string} always file name : {string} the file name trashed : {bool} true if the file is in the trash restore_path : {string} the restore path of the file, if is in the trash md5sum : {string} the checksum of its content, computed with the MD5 algorithm created_at : {date} the date of the creation of this file given by the client updated_at : {date} the date of the last update of this file given by the client tags : {array of strings} a list of tags. It is currently used to know if a file was uploaded through the mobile photo sync, with the value library . size : {number} the size of its content, in bytes executable : {bool} true is the file has the executable bit on UNIX ( chmod +x ) class : {string} a class in the list: ['image', 'document', 'audio', 'video', 'text', 'binary', 'pdf', 'files', 'code', 'slide', 'spreadsheet', 'text', 'zip', 'shortcut'] mime : {string} the full mime-type metadata : {map} an optional map of metadata ( Full metadata description ), with for example: width : {number} height : {number} datetime : {date} : date in original image file metadata gps : {map} : localization metadata with the following attributes lat : {float}: latitude long : {float}: longitude city : {string}: nearest city (optional) zip : {string}: postal code of the nearest city (optional) country : {string}: name of the associated country if any (optional) persons : {array}: the maps can have the following attributes (optional) name : {string}: then name of the tagged person on the photo created_at : {date}: date of creation of the tag x : {float}: x coordinate in the photo where the person is y : {float}: y coordinate in the photo where the person is icon : {string} : A small SVG file to use as icon for this file (optional) carbonCopy : {boolean} : if the document is the original document imported by the connector electronicSafe : {boolean} : if the document is secured in a secure storage \u26a0 carbonCopy and electronicSafe both need specific permission to be added to a document. It also has a relationship with its parent in the JSON-API representation. For an image , there are 3 links to thumbnails: small , medium , and large . These thumbnail links are valid for 10 minutes. After that, links will return a 400 Bad Request response code.", "title": "Files"}, {"location": "cozy-doctypes/docs/io.cozy.files/#trash", "text": "When a file or a directory is put in the trash bin, some attributes are updated: - trashed is set to true, but only for files: directories never have this attribute. - The restore_path is set, for both files and directories. - \u26a0\ufe0f The restore_path is not set on children. For instance, if a directory foo is trashed, it will have a restore_path but not the children. - The path is updated only for directories, starting with .cozy_trash Here is how one could query files and directories not in the trash, through a mango query: _id: { $ne: 'io.cozy.files.trash-dir' }, path: { $or: [{ $exists: false }, { $regex: '^(?!/.cozy_trash)' }] }, trashed: { $or: [{ $exists: false }, { $eq: false }] }", "title": "Trash"}, {"location": "cozy-doctypes/docs/io.cozy.files/#references", "text": "It\u2019s possible to link a file or a folder to another document. It\u2019s called a reference . It appears in the JSON-API representation as a refererenced_by relationship.", "title": "References"}, {"location": "cozy-doctypes/docs/io.cozy.files/#cozymetadata", "text": "The io.cozy.files doctype has the standard cozyMetadata , but with some more fields: createdOn : {string} the instance URL on which the file has created (useful if the file is shared between several cozy instances) uploadedAt : {date} the server date/time of the last upload (when the content was changed) uploadedOn : {string} the instance URL on which the file content was changed the last time uploadedBy : {map} information on which app has made the last upload slug : {string} the slug of the application that has made the upload version : {string} the version number of this application oauthClient : {map} if the upload was made by an OAuth Client, information about it ( id , name , and kind )", "title": "CozyMetadata"}, {"location": "cozy-doctypes/docs/io.cozy.files/#example-json-api-format", "text": "{ \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"3-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"sunset.jpg\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2018-01-02T20:38:04Z\" , \"updated_at\" : \"2019-06-12T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2018-01-02T20:38:04Z\" , \"height\" : 1080 , \"width\" : 1920 , \"icon\" : \"\" }, \"size\" : 12 , \"executable\" : false , \"class\" : \"image\" , \"mime\" : \"image/jpg\" , \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-06-11T01:02:03Z\" , \"createdByApp\" : \"flickr\" , \"createdByAppVersion\" : \"1.2.3\" , \"createdOn\" : \"https://alice.cozy.example\" , \"updatedAt\" : \"2019-06-12T12:40:06Z\" , \"updatedByApps\" : [ { \"slug\" : \"flickr\" , \"date\" : \"2019-06-11T01:02:03Z\" , \"version\" : \"1.2.3\" , \"instance\" : \"https://alice.cozy.example\" }, { \"slug\" : \"cozy-desktop\" , \"date\" : \"2019-06-12T12:40:06Z\" , \"version\" : \"3.13.2\" , \"instance\" : \"https://alice.cozy.example\" } ], \"uploadedAt\" : \"2019-06-11T20:34:56Z\" , \"uploadedOn\" : \"https://alice.cozy.example\" , \"uploadedBy\" : { \"slug\" : \"cozy-desktop\" , \"version\" : \"3.13.2\" , \"oauthClient\" : { \"id\" : \"9aaa6886-8b69-11e9-8412-b7855fb3838f\" , \"kind\" : \"desktop\" , \"name\" : \"Cozy Drive - mac book pro d'Alice\" } }, \"sourceAccount\" : \"07b49550-8b60-11e9-bb7e-87717e829039\" , \"sourceAccountIdentifier\" : \"157ae784\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references\" }, \"data\" : [ { \"type\" : \"io.cozy.albums\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"small\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/small\" , \"medium\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/medium\" , \"large\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/large\" } } }", "title": "Example (JSON-API format)"}, {"location": "cozy-doctypes/docs/io.cozy.files/#shortcuts", "text": "Shortcuts (or hyperlinks) are a special type of files. They are served with the application/internet-shortcut mime-type, they have a .url extension, and respect the URL file format . They can have metadata : sharing.status will be set if the link can be used to open a sharing. 2 values are possible: new and seen , depending on whether the link has been opened. target.cozyMetadata.instance is set to the cozy instance when relevant (mostly sharing and internal links) target._type is the doctype of the destination of the link (when the link goes to a sharing or document inside a cozy) target.mime is the mime-type of the destination of the link (when it is a file) target.app is the slug of the destination app (internal links only). icon {string?} contains the base64 encoded image or svg binary if mimetype is not present. iconMimeType {string?} contains the mime-type of the icon.", "title": "Shortcuts"}, {"location": "cozy-doctypes/docs/io.cozy.files/#example-json-format", "text": "{ \"_id\" : \"629fb233be550a21174ac8e19f0043af\" , \"_rev\" : \"1-61c7804bdb4f9f8dae5a363cb9a30dd8\" , \"type\" : \"file\" , \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"trashed\" : false , \"md5sum\" : \"vfEMDpJShs8QeIlsDmw9VA==\" , \"created_at\" : \"2020-02-10T20:38:04Z\" , \"updated_at\" : \"2020-02-10T20:38:04Z\" , \"tags\" : [], \"metadata\" : { \"sharing\" : { \"status\" : \"new\" }, \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" }, \"icon\" : \"[encoded base64 string of the content of the icon or svg binary]\" , \"iconMimeType\" : \"image/svg+xml\" }, \"size\" : 62 , \"executable\" : false , \"class\" : \"shortcut\" , \"mime\" : \"application/shortcut\" , \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-02-10T20:38:04Z\" , \"createdOn\" : \"https://bob.cozy.example/\" , \"updatedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedOn\" : \"https://bob.cozy.example/\" } }", "title": "Example (JSON format)"}, {"location": "cozy-doctypes/docs/io.cozy.files/#iocozyfilesversions", "text": "The io.cozy.files.versions is used to track old versions of a file content, when files versioning is enabled. The attributes of a version are: size : {number} the size of its content, in bytes md5sum : {string} the checksum of its content, computed with the MD5 algorithm updated_at : {date} the date of the last update of this file given by the client tags : {array of strings} a list of tags metadata : {map} an optional map of metadata. It also has the same cozyMetadata that a file (including the uploaded* fields), and a relationship to the versioned file.", "title": "io.cozy.files.versions"}, {"location": "cozy-doctypes/docs/io.cozy.files/#example-couchdb-format", "text": "{ \"_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/3-0e6d5b72\" , \"_rev\" : \"1-782839bf19cf4edbc29b82f77b28482f\" , \"updated_at\" : \"2019-06-12T12:38:04Z\" , \"size\" : \"12\" , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2018-01-02T20:38:04Z\" , \"height\" : 1080 , \"width\" : 1920 }, \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-06-11T20:34:56Z\" , \"createdOn\" : \"https://alice.cozy.example\" , \"updatedAt\" : \"2019-06-11T20:34:56Z\" , \"uploadedAt\" : \"2019-06-11T20:34:56Z\" , \"uploadedBy\" : { \"slug\" : \"drive\" }, \"uploadedOn\" : \"https://alice.cozy.example\" }, \"relationships\" : { \"file\" : { \"data\" : { \"_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"_type\" : \"io.cozy.files\" } } } }", "title": "Example (CouchDB format)"}, {"location": "cozy-doctypes/docs/io.cozy.files/#iocozyfilessettings", "text": "This doctype is used to store settings for files. It is currenly only used for the qualification migration service. lastProcessedFileDate: {string} the cozyMetadata.updatedAt date of the last processed file. It is used to know from where the query should be starting on an index sorted by date.", "title": "io.cozy.files.settings"}, {"location": "cozy-doctypes/docs/io.cozy.files/#iocozyfilesencryption", "text": "This doctype is used to store encryption keys for directories. The encryption keys are stored encrypted in the same way than bitwarden\u2019s ciphers , and are used to encrypt/decrypt files\u2019 binary inside the directory. _id : {string} refers to its directory id: io.cozy.files/ key : {string} the encrypted key, used to encrypt/decrypt files inside the directory.", "title": "io.cozy.files.encryption"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/", "text": "Metadata on io.cozy.files documents \u00b6 Generic metadata \u00b6 For generic metadata like createdAt or updatedAt , please follow the cozy-doctypes doc about generic model Image files \u00b6 For pictures files, like jpg , png , gif \u2026 width : {number} height : {number} datetime : {date} : date in original image file metadata gps : {map} : localization metadata with the following attributes lat : {float}: latitude long : {float}: longitude city : {string}: nearest city (optional) zip : {string}: postal code of the nearest city (optional) country : {string}: name of the associated country if any (optional) persons : {array}: the maps can have the following attributes (optional) name : {string}: then name of the tagged person on the photo created_at : {date}: date of creation of the tag x : {float}: x coordinate in the photo where the person is y : {float}: y coordinate in the photo where the person is Cozy Note files \u00b6 For a Cozy Note, here is the list: content : {object} - The Note\u2019s content. See https://prosemirror.net/docs/ref/#model for more informations schema : {object} - The Note\u2019s schema. See https://prosemirror.net/docs/guide/#schema for more informations title : {string} - The Note\u2019s title version : {int} - The Note\u2019s version Document qualification \u00b6 It is possible to add semantics to documents in order to qualify them. A qualification model is available here that describes the qualification attributes for a set of documents. A qualification consists of a label bound to some fixed attributes, i.e. purpose , sourceCategory , sourceSubCategory and subjects , all explained in the next section. Note that for a given label, it is possible to customize the model attributes values, by following these rules: If a value is defined for the attributes purpose , sourceCategory , sourceSubCategory , it is not possible to customize it. If a value is not defined for one of these attributes, a custom value can be defined, if it exists in their respective known values list in the model, e.g. knownSourceCategory . If some subjects values are set, they must be included in the given qualification. Extra subjects values can be set, but they should exist in the subjectsKnownValues model list. A document qualification is typically set by konnectors or by applications such as Cozy Drive through the cozy-scanner library. Data structure \u00b6 Example \u00b6 Here is a qualification example: { \"qualification\": { \"label\": \"driver_license\", \"purpose\": \"attestation\", \"sourceCategory\": \"gov\", \"sourceSubCategory\": \"transport\", \"subjects\": [\"permit\", \"driving\"] } } Qualification attributes \u00b6 A qualification can be composed of the following attributes: label : {string} the document label, which precisely specify what is the document. It is the only mandatory attribute in the qualification. Examples: driver_license , car_insurance , bank_statement , etc. purpose : {string} the goal of the document: for instance, an identity document has an attestation goal, to attest an identity. In the same manner, the purpose of a bill is to invoice something. Examples: attestation , invoice , contract , report , etc. sourceCategory : {string} the activity field of the source that produced the document. Examples: gov , bank , health , transport , etc. sourceSubCategory : {string} a precision of the activity field of the source that produced the document. In some cases, it is necessary when the primary field is too broad. Typically, for the driver_license label, gov is the sourceCategory and transport the sourceSubCategory . Examples: transport , health , civil_registration , health , etc. subjects : {array of strings} list what the document is about. For instance, a driver_license has two subjects: permit and driving , because this document is about the permit to drive a vehicle. Another example is the car_insurance : the subjects are insurance and car . Examples: permit , insurance , house , car , etc. For a complete list of the possible values for each attributes, see the qualification model . If you need to add new values, please consider opening an issue or making a pull request to the cozy-client repository. Additional metadata attributes \u00b6 Additional metadata attributes might be set to further describe the document. Most of these attributes heavily depends on the document context and are not expected in every cases. contentAuthor : {string} the author of the document, e.g. impots.gouv , amazon.com , etc. It is currently used as a source meaning. datetime : {date} Equals to the date attribute specified by datetimeLabel . fileIdAttributes : {string} Used to deduplicate files imported by a konnector. This is a concatenation of a set of attributes, separated by #### . For example: mycontractid####myfile.pdf####/mypath/ . datetimeLabel : {string} specify which attribute is used as datetime , e.g. issueDate or startDate . issueDate : {date} issue date of the document emitted by the vendor. startDate : {date} first day of a period, e.g. for a contract. endDate : {date} last day of a period, e.g. for a contract. expirationDate : {date} last day of validity, e.g. for an identity document. referencedDate : {date} reference date, e.g. for a sports club card. [A|B|C|D]ObtentionDate : {date} date of obtaining the driving license [A|B|C|D]. noticePeriod : {string} number of days before expiration alert. contractType : {string} type of employment contract. refTaxIncome : {string} reference tax income. netSocialAmount : {string} net social amount. employerName : {string} name of the employer. taxNumber : {string} fiscal reference number. invoiceNumber : {string} invoice number. number : {string} Relative number e.g. iban number for an iban document. contractReference : {string} reference of the related contract. isSubscription : {bool} true if the invoice is related to a subscription plan. labelGivenByUser : {string} custom document name. formReference : {string} reference of the form (ex: \u20182042RICI\u2019). school : {string} school name. country : {string} country name. accountNumber : {string} number of the related account. bicNumber : {string} Number of the related bank. bankName : {string} name of the related bank. carbonCopy : {boolean} : if the document is the original document imported by the connector electronicSafe : {boolean} : if the document is secured in a secure storage backupDeviceIds : {string[]} : id of the devices owning the backup. Only for backup directories. \u26a0 carbonCopy and electronicSafe both need specific permission to be added to a document. Examples \u00b6 Invoices and documents related to payments \u00b6 datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} invoiceNumber : {string} Invoice number contractReference : {string} Reference of the related contract, if any isSubscription : {bool} True if the invoice is related to a subscription plan Payslips \u00b6 datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} Source of the payslip, e.g. payfit.fr employerName : {string} Name of the employer on the payslip startDate : {date} First day of the worked period endDate : {date} Last day of the worked period issueDate : {date} Issue date of the document Tax Notices \u00b6 datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document refTaxIncome : {string} reference tax income. taxNumber : {string} fiscal reference number. Tax Returns \u00b6 datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document formReference : {string} Reference of the form (ex: \u20182042RICI\u2019) Contracts \u00b6 datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} contractReference : {string} Reference of the contract contractType : {string} type of employment contract. issueDate : {date} Issue date of the document startDate : {date} First day of the validity period endDate : {date} Last day of the validity period Certificates \u00b6 datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document startDate : {date} First day of the validity period endDate : {date} Last day of the validity period Diplomas \u00b6 datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} startDate : First day of the validity period label : {string} Short description of the diploma school : {string} School name country : {string} Country name Driving licenses \u00b6 datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' number : {string} Document number country : {string} Country name [A|B|C|D]ObtentionDate : {date} date of obtaining the driving license [A|B|C|D]. Identity documents \u00b6 datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} issueDate : {date} Issue date of the document expirationDate : {date} Last day of validity number : {string} Document number school : {string} School name country : {string} Country name noticePeriod : {string} number of days before expiration alert. Bank Statements \u00b6 datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} startDate : {date} First day of the statement period endDate : {date} Last day of the statement period accountNumber : {string} Number of the related account bankName : {string} Name of the related bank Bank Details (IBAN) \u00b6 datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document accountNumber : {string} Number of the related account bicNumber : {string} Number of the related bank bankName : {string} Name of the related bank Mail \u00b6 datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} Report \u00b6 datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} Files metadata examples \u00b6 Invoices, payment statements, payment schedules \u00b6 // invoice - bouygues telecom \"metadata\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" , }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"bouyguestelecom\" , \"issueDate\" : \"2019-05-10\" , \"contractReference\" : \"0645874398\" , \"invoiceNumber\" : \"KJF949875\" , \"isSubscription\" : true }, \"cozyMetadata\" : { ... } // payment statement - ameli \"metadata\" : { \"qualification\" : { \"label\" : \"health_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"health\" }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"ameli\" , \"issueDate\" : \"2019-05-10\" }, \"cozyMetadata\" : { ... } // payment schedule - EDF \"metadata\" : { \"qualification\" : { \"label\" : \"energy_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"energy\" }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"edf\" , \"iSubscription\" : true , \"issueDate\" : \"2019-05-10\" }, \"cozyMetadata\" : { ... } Taxe notices \u00b6 // taxe notice on income \"metadata\" : { \"qualification\" : { \"label\" : \"tax_notice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"tax\" , \"subjects\" : [ \"tax\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"impots.gouv\" , \"issueDate\" : \"2019-05-10\" , \"taxNumber\" : \"1234567891011\" , \"refTaxIncome\" : \"12345\" }, \"cozyMetadata\" : { ... } // tax return on income \"metadata\" : { \"qualification\" : { \"label\" : \"tax_return\" , \"purpose\" : \"report\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"tax\" , \"subjects\" : [ \"tax\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"impots.gouv\" , \"formReference\" : \"2042RICI\" , \"issueDate\" : \"2019-05-10\" }, \"cozyMetadata\" : { ... } Payslips \u00b6 // payslip - cozycloud \"metadata\" : { \"qualification\" : { \"label\" : \"pay_sheet\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"employer\" , \"subjects\" : [ \"work\" , \"revenues\" ] }, \"datetime\" : \"2019-05-01\" , \"datetimeLabel\" : \"startDate\" , \"contentAuthor\" : \"payfit.fr\" , \"employerName\" : \"cozycloud\" , \"startDate\" : \"2019-05-01\" , \"endDate\" : \"2019-05-31\" }, \"cozyMetadata\" : { ... } Certificates \u00b6 // health insurance attestation - ameli \"metadata\" : { \"qualification\" : { \"label\" : \"national_insurance_card\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"health\" , \"subjects\" : [ \"insurance\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"ameli\" , \"issueDate\" : \"2019-05-10\" , \"startDate\" : \"2019-01-01\" , \"endDate\" : \"2019-12-31\" }, \"cozyMetadata\" : { ... } // car insurance certificate - maif \"metadata\" : { \"qualification\" : { \"label\" : \"car_insurance\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"insurance\" , \"sourceSubCategory\" : \"transport\" , \"subjects\" : [ \"insurance\" , \"car\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"macif\" , \"issueDate\" : \"2019-05-10\" , \"startDate\" : \"2019-01-01\" , \"endDate\" : \"2019-12-31\" }, \"cozyMetadata\" : { ... } // right certificate - CAF \"metadata\" : { \"qualification\" : { \"label\" : \"caf\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"family\" , \"subjects\" : [ \"right\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"caf\" , \"issueDate\" : \"2019-05-10\" , \"startDate\" : \"2019-05-01\" , \"endDate\" : \"2019-05-31\" }, \"cozyMetadata\" : { ... } Identity documents \u00b6 // id card \"metadata\" : { \"qualification\" : { \"label\" : \"national_id_card\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"civil_registration\" , \"subjects\" : [ \"identity\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"france\" , \"issueDate\" : \"2014-05-10\" , \"expirationDate\" : \"2029-05-10\" , \"number\" : \"ABC123456\" , \"country\" : \"france\" , } \"cozyMetadata\" : { ... }", "title": "Files metadata"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#metadata-on-iocozyfiles-documents", "text": "", "title": "Metadata on io.cozy.files documents"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#generic-metadata", "text": "For generic metadata like createdAt or updatedAt , please follow the cozy-doctypes doc about generic model", "title": "Generic metadata"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#image-files", "text": "For pictures files, like jpg , png , gif \u2026 width : {number} height : {number} datetime : {date} : date in original image file metadata gps : {map} : localization metadata with the following attributes lat : {float}: latitude long : {float}: longitude city : {string}: nearest city (optional) zip : {string}: postal code of the nearest city (optional) country : {string}: name of the associated country if any (optional) persons : {array}: the maps can have the following attributes (optional) name : {string}: then name of the tagged person on the photo created_at : {date}: date of creation of the tag x : {float}: x coordinate in the photo where the person is y : {float}: y coordinate in the photo where the person is", "title": "Image files"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#cozy-note-files", "text": "For a Cozy Note, here is the list: content : {object} - The Note\u2019s content. See https://prosemirror.net/docs/ref/#model for more informations schema : {object} - The Note\u2019s schema. See https://prosemirror.net/docs/guide/#schema for more informations title : {string} - The Note\u2019s title version : {int} - The Note\u2019s version", "title": "Cozy Note files"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#document-qualification", "text": "It is possible to add semantics to documents in order to qualify them. A qualification model is available here that describes the qualification attributes for a set of documents. A qualification consists of a label bound to some fixed attributes, i.e. purpose , sourceCategory , sourceSubCategory and subjects , all explained in the next section. Note that for a given label, it is possible to customize the model attributes values, by following these rules: If a value is defined for the attributes purpose , sourceCategory , sourceSubCategory , it is not possible to customize it. If a value is not defined for one of these attributes, a custom value can be defined, if it exists in their respective known values list in the model, e.g. knownSourceCategory . If some subjects values are set, they must be included in the given qualification. Extra subjects values can be set, but they should exist in the subjectsKnownValues model list. A document qualification is typically set by konnectors or by applications such as Cozy Drive through the cozy-scanner library.", "title": "Document qualification"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#data-structure", "text": "", "title": "Data structure"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#example", "text": "Here is a qualification example: { \"qualification\": { \"label\": \"driver_license\", \"purpose\": \"attestation\", \"sourceCategory\": \"gov\", \"sourceSubCategory\": \"transport\", \"subjects\": [\"permit\", \"driving\"] } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#qualification-attributes", "text": "A qualification can be composed of the following attributes: label : {string} the document label, which precisely specify what is the document. It is the only mandatory attribute in the qualification. Examples: driver_license , car_insurance , bank_statement , etc. purpose : {string} the goal of the document: for instance, an identity document has an attestation goal, to attest an identity. In the same manner, the purpose of a bill is to invoice something. Examples: attestation , invoice , contract , report , etc. sourceCategory : {string} the activity field of the source that produced the document. Examples: gov , bank , health , transport , etc. sourceSubCategory : {string} a precision of the activity field of the source that produced the document. In some cases, it is necessary when the primary field is too broad. Typically, for the driver_license label, gov is the sourceCategory and transport the sourceSubCategory . Examples: transport , health , civil_registration , health , etc. subjects : {array of strings} list what the document is about. For instance, a driver_license has two subjects: permit and driving , because this document is about the permit to drive a vehicle. Another example is the car_insurance : the subjects are insurance and car . Examples: permit , insurance , house , car , etc. For a complete list of the possible values for each attributes, see the qualification model . If you need to add new values, please consider opening an issue or making a pull request to the cozy-client repository.", "title": "Qualification attributes"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#additional-metadata-attributes", "text": "Additional metadata attributes might be set to further describe the document. Most of these attributes heavily depends on the document context and are not expected in every cases. contentAuthor : {string} the author of the document, e.g. impots.gouv , amazon.com , etc. It is currently used as a source meaning. datetime : {date} Equals to the date attribute specified by datetimeLabel . fileIdAttributes : {string} Used to deduplicate files imported by a konnector. This is a concatenation of a set of attributes, separated by #### . For example: mycontractid####myfile.pdf####/mypath/ . datetimeLabel : {string} specify which attribute is used as datetime , e.g. issueDate or startDate . issueDate : {date} issue date of the document emitted by the vendor. startDate : {date} first day of a period, e.g. for a contract. endDate : {date} last day of a period, e.g. for a contract. expirationDate : {date} last day of validity, e.g. for an identity document. referencedDate : {date} reference date, e.g. for a sports club card. [A|B|C|D]ObtentionDate : {date} date of obtaining the driving license [A|B|C|D]. noticePeriod : {string} number of days before expiration alert. contractType : {string} type of employment contract. refTaxIncome : {string} reference tax income. netSocialAmount : {string} net social amount. employerName : {string} name of the employer. taxNumber : {string} fiscal reference number. invoiceNumber : {string} invoice number. number : {string} Relative number e.g. iban number for an iban document. contractReference : {string} reference of the related contract. isSubscription : {bool} true if the invoice is related to a subscription plan. labelGivenByUser : {string} custom document name. formReference : {string} reference of the form (ex: \u20182042RICI\u2019). school : {string} school name. country : {string} country name. accountNumber : {string} number of the related account. bicNumber : {string} Number of the related bank. bankName : {string} name of the related bank. carbonCopy : {boolean} : if the document is the original document imported by the connector electronicSafe : {boolean} : if the document is secured in a secure storage backupDeviceIds : {string[]} : id of the devices owning the backup. Only for backup directories. \u26a0 carbonCopy and electronicSafe both need specific permission to be added to a document.", "title": "Additional metadata attributes"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#examples", "text": "", "title": "Examples"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#invoices-and-documents-related-to-payments", "text": "datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} invoiceNumber : {string} Invoice number contractReference : {string} Reference of the related contract, if any isSubscription : {bool} True if the invoice is related to a subscription plan", "title": "Invoices and documents related to payments"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#payslips", "text": "datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} Source of the payslip, e.g. payfit.fr employerName : {string} Name of the employer on the payslip startDate : {date} First day of the worked period endDate : {date} Last day of the worked period issueDate : {date} Issue date of the document", "title": "Payslips"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#tax-notices", "text": "datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document refTaxIncome : {string} reference tax income. taxNumber : {string} fiscal reference number.", "title": "Tax Notices"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#tax-returns", "text": "datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document formReference : {string} Reference of the form (ex: \u20182042RICI\u2019)", "title": "Tax Returns"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#contracts", "text": "datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} contractReference : {string} Reference of the contract contractType : {string} type of employment contract. issueDate : {date} Issue date of the document startDate : {date} First day of the validity period endDate : {date} Last day of the validity period", "title": "Contracts"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#certificates", "text": "datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document startDate : {date} First day of the validity period endDate : {date} Last day of the validity period", "title": "Certificates"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#diplomas", "text": "datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} startDate : First day of the validity period label : {string} Short description of the diploma school : {string} School name country : {string} Country name", "title": "Diplomas"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#driving-licenses", "text": "datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' number : {string} Document number country : {string} Country name [A|B|C|D]ObtentionDate : {date} date of obtaining the driving license [A|B|C|D].", "title": "Driving licenses"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#identity-documents", "text": "datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} issueDate : {date} Issue date of the document expirationDate : {date} Last day of validity number : {string} Document number school : {string} School name country : {string} Country name noticePeriod : {string} number of days before expiration alert.", "title": "Identity documents"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#bank-statements", "text": "datetime : {date} Equals to startDate datetimeLabel : {string} 'startDate' contentAuthor : {string} startDate : {date} First day of the statement period endDate : {date} Last day of the statement period accountNumber : {string} Number of the related account bankName : {string} Name of the related bank", "title": "Bank Statements"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#bank-details-iban", "text": "datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string} issueDate : {date} Issue date of the document accountNumber : {string} Number of the related account bicNumber : {string} Number of the related bank bankName : {string} Name of the related bank", "title": "Bank Details (IBAN)"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#mail", "text": "datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string}", "title": "Mail"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#report", "text": "datetime : {date} Equals to issueDate datetimeLabel : {string} 'issueDate' contentAuthor : {string}", "title": "Report"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#files-metadata-examples", "text": "", "title": "Files metadata examples"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#invoices-payment-statements-payment-schedules", "text": "// invoice - bouygues telecom \"metadata\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" , }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"bouyguestelecom\" , \"issueDate\" : \"2019-05-10\" , \"contractReference\" : \"0645874398\" , \"invoiceNumber\" : \"KJF949875\" , \"isSubscription\" : true }, \"cozyMetadata\" : { ... } // payment statement - ameli \"metadata\" : { \"qualification\" : { \"label\" : \"health_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"health\" }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"ameli\" , \"issueDate\" : \"2019-05-10\" }, \"cozyMetadata\" : { ... } // payment schedule - EDF \"metadata\" : { \"qualification\" : { \"label\" : \"energy_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"energy\" }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"edf\" , \"iSubscription\" : true , \"issueDate\" : \"2019-05-10\" }, \"cozyMetadata\" : { ... }", "title": "Invoices, payment statements, payment schedules"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#taxe-notices", "text": "// taxe notice on income \"metadata\" : { \"qualification\" : { \"label\" : \"tax_notice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"tax\" , \"subjects\" : [ \"tax\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"impots.gouv\" , \"issueDate\" : \"2019-05-10\" , \"taxNumber\" : \"1234567891011\" , \"refTaxIncome\" : \"12345\" }, \"cozyMetadata\" : { ... } // tax return on income \"metadata\" : { \"qualification\" : { \"label\" : \"tax_return\" , \"purpose\" : \"report\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"tax\" , \"subjects\" : [ \"tax\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"impots.gouv\" , \"formReference\" : \"2042RICI\" , \"issueDate\" : \"2019-05-10\" }, \"cozyMetadata\" : { ... }", "title": "Taxe notices"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#payslips_1", "text": "// payslip - cozycloud \"metadata\" : { \"qualification\" : { \"label\" : \"pay_sheet\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"employer\" , \"subjects\" : [ \"work\" , \"revenues\" ] }, \"datetime\" : \"2019-05-01\" , \"datetimeLabel\" : \"startDate\" , \"contentAuthor\" : \"payfit.fr\" , \"employerName\" : \"cozycloud\" , \"startDate\" : \"2019-05-01\" , \"endDate\" : \"2019-05-31\" }, \"cozyMetadata\" : { ... }", "title": "Payslips"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#certificates_1", "text": "// health insurance attestation - ameli \"metadata\" : { \"qualification\" : { \"label\" : \"national_insurance_card\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"health\" , \"subjects\" : [ \"insurance\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"ameli\" , \"issueDate\" : \"2019-05-10\" , \"startDate\" : \"2019-01-01\" , \"endDate\" : \"2019-12-31\" }, \"cozyMetadata\" : { ... } // car insurance certificate - maif \"metadata\" : { \"qualification\" : { \"label\" : \"car_insurance\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"insurance\" , \"sourceSubCategory\" : \"transport\" , \"subjects\" : [ \"insurance\" , \"car\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"macif\" , \"issueDate\" : \"2019-05-10\" , \"startDate\" : \"2019-01-01\" , \"endDate\" : \"2019-12-31\" }, \"cozyMetadata\" : { ... } // right certificate - CAF \"metadata\" : { \"qualification\" : { \"label\" : \"caf\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"family\" , \"subjects\" : [ \"right\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"caf\" , \"issueDate\" : \"2019-05-10\" , \"startDate\" : \"2019-05-01\" , \"endDate\" : \"2019-05-31\" }, \"cozyMetadata\" : { ... }", "title": "Certificates"}, {"location": "cozy-doctypes/docs/io.cozy.files_metadata/#identity-documents_1", "text": "// id card \"metadata\" : { \"qualification\" : { \"label\" : \"national_id_card\" , \"purpose\" : \"attestation\" , \"sourceCategory\" : \"gov\" , \"sourceSubCategory\" : \"civil_registration\" , \"subjects\" : [ \"identity\" ] }, \"datetime\" : \"2019-05-10\" , \"datetimeLabel\" : \"issueDate\" , \"contentAuthor\" : \"france\" , \"issueDate\" : \"2014-05-10\" , \"expirationDate\" : \"2029-05-10\" , \"number\" : \"ABC123456\" , \"country\" : \"france\" , } \"cozyMetadata\" : { ... }", "title": "Identity documents"}, {"location": "cozy-doctypes/docs/io.cozy.home.settings/", "text": "Table of contents Cozy home settings doctype \u00b6 io.cozy.home.settings \u00b6 The io.cozy.home.settings doctype contains one document containing : - default_redirection_snackbar_disabled : {boolean} If the default redirection snackbar has been disabled - default_redirection_view_count : {number} View count of the home app if the default redirection app is different than the home app", "title": "Home settings"}, {"location": "cozy-doctypes/docs/io.cozy.home.settings/#cozy-home-settings-doctype", "text": "", "title": "Cozy home settings doctype"}, {"location": "cozy-doctypes/docs/io.cozy.home.settings/#iocozyhomesettings", "text": "The io.cozy.home.settings doctype contains one document containing : - default_redirection_snackbar_disabled : {boolean} If the default redirection snackbar has been disabled - default_redirection_view_count : {number} View count of the home app if the default redirection app is different than the home app", "title": "io.cozy.home.settings"}, {"location": "cozy-doctypes/docs/io.cozy.identities/", "text": "Table of contents Identities doctype \u00b6 io.cozy.identities \u00b6 Description \u00b6 This doctype represents the differents identities (or profile) of the user, fetched by datasources (connectors most of the time). In an identity, data is grouped by category : contact, tax_information, housing, incomes\u2026 There are three sources of identity, considering the source of the data: source = connector : gathers the data held by the online service is the \u201cuser profile\u201d known by each different service source = manual : attributes manually modified byt the user are stored apart in a \u201cmanual\u201d identity document. There is only one manual identity. source = factorized : data from manual and connector identities are automatically factorized in a single identity of type \u201cfactorized\u201d. There is only one factorized identity. \u2139\ufe0f Whatever the source of the data, all identities must follow the same format, described below. Relation between Identities and Accounts \u00b6 There is one identity per identifier/slug couple: identifier is the unique identifier of the user account, often an email. slug is the brand An identity is associated to a unique io.cozy.accounts . \u2139\ufe0f Multiple connectors may create an identity for a given identifier. That is why an identity will be unique by identifier and slug. \u2139\ufe0f When an account is disconnected in a connector, then the associated CouchDB document is deleted, but not its corresponding identity. If the same \u201cuser account\u201d is connected again, then a new account is created but the corresponding identity is reused. The id of the corresponding account and the identifier of the account are in the .cozyMetadata: sourceAccount : id of the io.cozy.accounts document sourceAccountIdentifier : identifier of this account, for instance \u201cjo32@gmail.com\u201d \u2139\ufe0f The identifier is also stored in the identifier attribute (data is duplicated) Manual identity \u00b6 Data might be modified manually by the user, for instance when modifiying his own contact (i.e. myself contact). Data modified by the user is stored in the \u201cmanual identity\u201d. The identity factorization service will then be able to choose which data should be put into the factorized identity. Factorized identity \u00b6 Data from different identities is factored into a single identity called the \u201cfactorized identity\u201d. It is an identity where source = factorized . For instance, if a user has different email addresses in different online services, only one of these will be chosen to be factorized in the \u201cfactorized identity\u201d. And if the user modifies his email address, then this one will be stored in the \u201cmanual identity\u201d and will be prioritized into the \u201cfactorized identity\u201d to be chosen as default. A service (WIP) is in charge of updating this factorized identity each time a modification occurs in an identity. The service has the knowledge to choose the better information for the factorized identity. \u2139\ufe0f The \u201cfactorized identity\u201d might update the mySelf contact document. Mandatory attributes \u00b6 identifier : {string} Login or other identifier unique to the data source source : {string} A value among [connector | manual | factorized] Contextual attributes \u00b6 Depending on the data retrieved by the source, the identity might include those attibutes: contact : {object} - identity data following the io.cozy.contacts format Some specific data related to brands might be added by konnectors. See maif-data-collect for example. tax_information : {array} - there is one element per year year : {number} year of the last tax_information rfr : {number} \u201crevenu fiscal de r\u00e9f\u00e9rence\u201d, scrapped from \u201cAvis d\u2019imposition\u201d file 1AJ : {number} scrapped from \u201cAvis d\u2019imposition\u201d file 1BJ : {number} scrapped from \u201cAvis d\u2019imposition\u201d file net_monthly_income : {number} (1AJ+1BJ) /12 or RFR/12 currency : {string} https://en.wikipedia.org/wiki/ISO_4217 housing {array} : WIP incomes {array} : WIP Example \u00b6 { \"_id\": \"62e5d66d6e11d19992b7efce794263f0\", \"source\": \"connector\", \"identifier\": \"example@email.com\", \"contact\": { \"address\": [ { \"formattedAddress\": \"2 rue du moulin, 75000 Paris\", \"street\": \"2 rue du moulin\", \"postcode\": \"75000\", \"city\": \"Paris\" } ], \"email\": [ { \"address\": \"example@email.com\" } ], \"name\": { \"familyName\": \"Dupond\", \"givenName\": \"Jean\" }, \"phone\": [ { \"number\": \"06 06 06 06 06\", \"primary\": true, \"type\": \"mobile\" } ], \"maritalStatus\": \"married\", \"numberOfDependants\": 1 }, \"tax_information\": [ { \"year\": 2022, \"RFR\": 56789.10, \"1AJ\": 12345.67, \"1BJ\": 23456.78, \"net_monthly_income\": 1234.56, # RFR/12 \"currency\": \"EUR\", \"file\": \"avis_impot_2022.pdf\" }, { \"year\": 2021, \"RFR\": 45678.91, \"1AJ\": 34567.89, \"1BJ\": 23456.78, \"net_monthly_income\": 3806.5, # RFR/12 \"currency\": \"EUR\", \"file\": \"avis_impot_revenu_2022.pdf\" } ], \"housing\": [ { \"address\": { \"formattedAddress\": \"2 rue du moulin, 75000 Paris\", \"street\": \"2 rue du moulin\", \"postcode\": \"75000\", \"city\": \"Paris\" }, \"construction_year\": 2013, \"residence_type\": \"primary\", \"housing_type\": \"appartment\", \"residents_number\": 1, \"living_space_m2\": 30, \"heating_system\": \"collective\", \"water_heating_system\": \"collective\", \"baking_types\": [{ \"type\": \"electric hob\", \"number\": 1 }], \"energy_providers\": [ // one record per energy_type. It means that if the vendor is the same for gas // and electricity, then there are still two records, one for gas and one for // electricity { \"vendor\": \"edf\", \"energy_type\": \"electricity\", \"contract_number\": \"004037770580\", \"pdl_number\": \"05548480447301\", \"contract_type\": \"TARIF_BLEU_V2\", \"powerkVA\": 6, \"charging_type\": \"monthly\", \"electric_consumption\": [ { \"year\": 2022, \"consumptionkWh\": 210, \"months\": [ { \"month\": 1, \"consumptionkWh\": 65 }, { \"month\": 2, \"consumptionkWh\": 75 }, { \"month\": 3, \"consumptionkWh\": 70 } ] }, { \"year\": 2021, \"consumptionkWh\": 210, \"months\": [ { \"month\": 10, \"consumptionkWh\": 65 }, { \"month\": 11, \"consumptionkWh\": 75 }, { \"month\": 12, \"consumptionkWh\": 70 } ] } ] }, { \"vendor\": \"edf\", \"energy_type\": \"gas\", \"contract_number\": \"004037770545\", \"pce_number\": \"055484804495\", \"contract_type\": \"MCGN_PG\", \"charging_type\": \"monthly\", \"gas_consumption\": [ { \"year\": 2022, \"consumptionkWh\": 145, \"months\": [ { \"month\": 1, \"consumptionkWh\": 30 }, { \"month\": 2, \"consumptionkWh\": 65 }, { \"month\": 3, \"consumptionkWh\": 50 } ] } ] } ] } ], \"cozyMetadata\": { \"doctypeVersion\": 1, \"createdAt\": \"2020-11-23T10:36:49.752Z\", \"createdByApp\": \"edfclientside\", \"createdByAppVersion\": \"1.0.0\", \"updatedAt\": \"2021-11-23T10:36:49.752Z\", \"updatedByApps\": [ { \"date\": \"2021-11-23T10:36:49.752Z\", \"slug\": \"edfclientside\", \"version\": \"1.0.0\" } ], \"sourceAccount\": \"94263f062e5d66d6e11d19992b7efce7\", \"sourceAccountIdentifier\": \"example@email.com\" } }", "title": "Identities"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#identities-doctype", "text": "", "title": "Identities doctype"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#iocozyidentities", "text": "", "title": "io.cozy.identities"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#description", "text": "This doctype represents the differents identities (or profile) of the user, fetched by datasources (connectors most of the time). In an identity, data is grouped by category : contact, tax_information, housing, incomes\u2026 There are three sources of identity, considering the source of the data: source = connector : gathers the data held by the online service is the \u201cuser profile\u201d known by each different service source = manual : attributes manually modified byt the user are stored apart in a \u201cmanual\u201d identity document. There is only one manual identity. source = factorized : data from manual and connector identities are automatically factorized in a single identity of type \u201cfactorized\u201d. There is only one factorized identity. \u2139\ufe0f Whatever the source of the data, all identities must follow the same format, described below.", "title": "Description"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#relation-between-identities-and-accounts", "text": "There is one identity per identifier/slug couple: identifier is the unique identifier of the user account, often an email. slug is the brand An identity is associated to a unique io.cozy.accounts . \u2139\ufe0f Multiple connectors may create an identity for a given identifier. That is why an identity will be unique by identifier and slug. \u2139\ufe0f When an account is disconnected in a connector, then the associated CouchDB document is deleted, but not its corresponding identity. If the same \u201cuser account\u201d is connected again, then a new account is created but the corresponding identity is reused. The id of the corresponding account and the identifier of the account are in the .cozyMetadata: sourceAccount : id of the io.cozy.accounts document sourceAccountIdentifier : identifier of this account, for instance \u201cjo32@gmail.com\u201d \u2139\ufe0f The identifier is also stored in the identifier attribute (data is duplicated)", "title": "Relation between Identities and Accounts"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#manual-identity", "text": "Data might be modified manually by the user, for instance when modifiying his own contact (i.e. myself contact). Data modified by the user is stored in the \u201cmanual identity\u201d. The identity factorization service will then be able to choose which data should be put into the factorized identity.", "title": "Manual identity"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#factorized-identity", "text": "Data from different identities is factored into a single identity called the \u201cfactorized identity\u201d. It is an identity where source = factorized . For instance, if a user has different email addresses in different online services, only one of these will be chosen to be factorized in the \u201cfactorized identity\u201d. And if the user modifies his email address, then this one will be stored in the \u201cmanual identity\u201d and will be prioritized into the \u201cfactorized identity\u201d to be chosen as default. A service (WIP) is in charge of updating this factorized identity each time a modification occurs in an identity. The service has the knowledge to choose the better information for the factorized identity. \u2139\ufe0f The \u201cfactorized identity\u201d might update the mySelf contact document.", "title": "Factorized identity"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#mandatory-attributes", "text": "identifier : {string} Login or other identifier unique to the data source source : {string} A value among [connector | manual | factorized]", "title": "Mandatory attributes"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#contextual-attributes", "text": "Depending on the data retrieved by the source, the identity might include those attibutes: contact : {object} - identity data following the io.cozy.contacts format Some specific data related to brands might be added by konnectors. See maif-data-collect for example. tax_information : {array} - there is one element per year year : {number} year of the last tax_information rfr : {number} \u201crevenu fiscal de r\u00e9f\u00e9rence\u201d, scrapped from \u201cAvis d\u2019imposition\u201d file 1AJ : {number} scrapped from \u201cAvis d\u2019imposition\u201d file 1BJ : {number} scrapped from \u201cAvis d\u2019imposition\u201d file net_monthly_income : {number} (1AJ+1BJ) /12 or RFR/12 currency : {string} https://en.wikipedia.org/wiki/ISO_4217 housing {array} : WIP incomes {array} : WIP", "title": "Contextual attributes"}, {"location": "cozy-doctypes/docs/io.cozy.identities/#example", "text": "{ \"_id\": \"62e5d66d6e11d19992b7efce794263f0\", \"source\": \"connector\", \"identifier\": \"example@email.com\", \"contact\": { \"address\": [ { \"formattedAddress\": \"2 rue du moulin, 75000 Paris\", \"street\": \"2 rue du moulin\", \"postcode\": \"75000\", \"city\": \"Paris\" } ], \"email\": [ { \"address\": \"example@email.com\" } ], \"name\": { \"familyName\": \"Dupond\", \"givenName\": \"Jean\" }, \"phone\": [ { \"number\": \"06 06 06 06 06\", \"primary\": true, \"type\": \"mobile\" } ], \"maritalStatus\": \"married\", \"numberOfDependants\": 1 }, \"tax_information\": [ { \"year\": 2022, \"RFR\": 56789.10, \"1AJ\": 12345.67, \"1BJ\": 23456.78, \"net_monthly_income\": 1234.56, # RFR/12 \"currency\": \"EUR\", \"file\": \"avis_impot_2022.pdf\" }, { \"year\": 2021, \"RFR\": 45678.91, \"1AJ\": 34567.89, \"1BJ\": 23456.78, \"net_monthly_income\": 3806.5, # RFR/12 \"currency\": \"EUR\", \"file\": \"avis_impot_revenu_2022.pdf\" } ], \"housing\": [ { \"address\": { \"formattedAddress\": \"2 rue du moulin, 75000 Paris\", \"street\": \"2 rue du moulin\", \"postcode\": \"75000\", \"city\": \"Paris\" }, \"construction_year\": 2013, \"residence_type\": \"primary\", \"housing_type\": \"appartment\", \"residents_number\": 1, \"living_space_m2\": 30, \"heating_system\": \"collective\", \"water_heating_system\": \"collective\", \"baking_types\": [{ \"type\": \"electric hob\", \"number\": 1 }], \"energy_providers\": [ // one record per energy_type. It means that if the vendor is the same for gas // and electricity, then there are still two records, one for gas and one for // electricity { \"vendor\": \"edf\", \"energy_type\": \"electricity\", \"contract_number\": \"004037770580\", \"pdl_number\": \"05548480447301\", \"contract_type\": \"TARIF_BLEU_V2\", \"powerkVA\": 6, \"charging_type\": \"monthly\", \"electric_consumption\": [ { \"year\": 2022, \"consumptionkWh\": 210, \"months\": [ { \"month\": 1, \"consumptionkWh\": 65 }, { \"month\": 2, \"consumptionkWh\": 75 }, { \"month\": 3, \"consumptionkWh\": 70 } ] }, { \"year\": 2021, \"consumptionkWh\": 210, \"months\": [ { \"month\": 10, \"consumptionkWh\": 65 }, { \"month\": 11, \"consumptionkWh\": 75 }, { \"month\": 12, \"consumptionkWh\": 70 } ] } ] }, { \"vendor\": \"edf\", \"energy_type\": \"gas\", \"contract_number\": \"004037770545\", \"pce_number\": \"055484804495\", \"contract_type\": \"MCGN_PG\", \"charging_type\": \"monthly\", \"gas_consumption\": [ { \"year\": 2022, \"consumptionkWh\": 145, \"months\": [ { \"month\": 1, \"consumptionkWh\": 30 }, { \"month\": 2, \"consumptionkWh\": 65 }, { \"month\": 3, \"consumptionkWh\": 50 } ] } ] } ] } ], \"cozyMetadata\": { \"doctypeVersion\": 1, \"createdAt\": \"2020-11-23T10:36:49.752Z\", \"createdByApp\": \"edfclientside\", \"createdByAppVersion\": \"1.0.0\", \"updatedAt\": \"2021-11-23T10:36:49.752Z\", \"updatedByApps\": [ { \"date\": \"2021-11-23T10:36:49.752Z\", \"slug\": \"edfclientside\", \"version\": \"1.0.0\" } ], \"sourceAccount\": \"94263f062e5d66d6e11d19992b7efce7\", \"sourceAccountIdentifier\": \"example@email.com\" } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.jobs/", "text": "Cozy jobs doctype io.cozy.jobs Cozy jobs doctype \u00b6 io.cozy.jobs \u00b6 The io.cozy.jobs doctype holds the informations about the instance jobs. Jobs are created by triggers to handle specific background tasks. domain {string}: The instance domain of the job worker {string}: Worker type service : Handle services (bank operations matching for example) konnector : Handle konnectors executions thumbnail : Handle image thumbnails computation sendmail : Manages all the mail-related work (sharings, 2FA, passphrase reset, \u2026) migrations : Used to handle Swift layout migrations move : Move worker role is to export an instance data push : This worker is responsible of mobile notifications share-* : share-track , share-replicate & share-upload manage all the share-related data between the instances. unzip : Unzip files updates : Handle app/konnectors updates message {object}: Contains all the specific-worker data (slug, script name, \u2026) manual_execution {bool}: Tells if the job has been manually excuted event {object}: Holds the informations for realtime options {object}: Custom overriden options for the job ( max_exec_count , max_exec_time , timeout ) state {string}: State of the job. Can be queued , running , errored or done queued_at {timestamp}: When the job has been queued started_at {timestamp}: When the job has been started finished_at {timestamp}: When the job has been finished error {string}: Contains the error message if the job failed You can get more informations on the official documentation", "title": "Jobs"}, {"location": "cozy-doctypes/docs/io.cozy.jobs/#cozy-jobs-doctype", "text": "", "title": "Cozy jobs doctype"}, {"location": "cozy-doctypes/docs/io.cozy.jobs/#iocozyjobs", "text": "The io.cozy.jobs doctype holds the informations about the instance jobs. Jobs are created by triggers to handle specific background tasks. domain {string}: The instance domain of the job worker {string}: Worker type service : Handle services (bank operations matching for example) konnector : Handle konnectors executions thumbnail : Handle image thumbnails computation sendmail : Manages all the mail-related work (sharings, 2FA, passphrase reset, \u2026) migrations : Used to handle Swift layout migrations move : Move worker role is to export an instance data push : This worker is responsible of mobile notifications share-* : share-track , share-replicate & share-upload manage all the share-related data between the instances. unzip : Unzip files updates : Handle app/konnectors updates message {object}: Contains all the specific-worker data (slug, script name, \u2026) manual_execution {bool}: Tells if the job has been manually excuted event {object}: Holds the informations for realtime options {object}: Custom overriden options for the job ( max_exec_count , max_exec_time , timeout ) state {string}: State of the job. Can be queued , running , errored or done queued_at {timestamp}: When the job has been queued started_at {timestamp}: When the job has been started finished_at {timestamp}: When the job has been finished error {string}: Contains the error message if the job failed You can get more informations on the official documentation", "title": "io.cozy.jobs"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/", "text": "Table of contents Konnectors doctype \u00b6 The io.cozy.konnectors doctype is used to store installed konnectors. Konnectors are autonomous applications ran on the stack to connect to external services or API. When installing a konnector, the Cozy stack creates a new io.cozy.konnector document from the fields in the manifest.konnector . io.cozy.konnectors are used by Cozy-Store to install and uninstall konnectors, and by Cozy-Home to manage accounts for konnectors Attributes \u00b6 Retrieved from manifest.konnector \u00b6 The available attributes in a io.cozy.konnectors document are : Field Description aggregator Object containing aggregator data. Typically { accountId: 'aggregator-service' } . categories array of categories for your apps (see authorized categories), it will be ['others'] by default if empty clientSide Boolean to specify if the konnector should be run on the client or not data_types (konnector specific) Array of the data type the konnector will manage developer name and url for the developer editor the editor\u2019s name to display on the cozy-bar ( REQUIRED ) features (konnector specific) Array of features added in the konnector from the list below. fields (konnector specific) JSON object describing the fields need by the konnector ( except folder path ). Used to generate a form. See below folders (konnector specific) A list of folders required by the konnector to store files according to datatype (see the specific documentation below ) frequency (konnector specific) A human readable value between monthly , weekly , daily , indicating the interval of time between two runs of the konnector. Default: weekly . icon path to the icon for the home (path in the build) intents (application specific) a list of intents provided by this app (see cozy-stack intents doc for more details) langs Languages available in your app (can be different from locales) language (konnector specific) the konnector development language used (ex: node ) license the SPDX license identifier locales an object with language slug as property, each name property is an object of localized informations (see the second part below) manifest_version The current manifest version used. This is a versioning for the manifest and allow better retrocompatiblity when processing app manifest messages (konnector specific) Array of message identifiers, which can be used by application to display information at known areas. See example below . mobile (application specific) JSON object containing information about app\u2019s mobile version (see cozy-stack routes doc for more details) name the name to display on the home ( REQUIRED ) name_prefix the prefix to display with the name oauth (konnector specific) JSON object containing oAuth information, like scope . If a manifest provides an oauth property, it is considered as an OAuth konnector. Note: scope can be a string or an array. If it is an array, its values will be joined with a space. A false or null value in scope will remove any scope parameter in the request sent to the oauth provider. parameters (konnector specific) Additional parameters which should be passed to the konnector. Used for example for bank konnectors to pass a bankId parameter. partnership an object to provide informations (to display in the Store for example) about a partnership related to the application ( icon description , name and domain ). It can also be used to trigger alternative konnector connection policies for some vendors (see the budget-insight konnector policy in cozy-harvest ). permissions a map of permissions needed by the app (see see cozy-stack permissions doc for more details) platforms (application specific) List of objects for platform native applications. For now there are only two properties: type (i.e. 'ios' or 'linux' ) and the optional url to reach this application page. qualification_labels (konnector specific) Array of one or more labels from the Cozy Client\u2019s qualifications list to associate with the files the konnector will receive from the website. routes (application specific) a map of routes for the app (see cozy-stack routes doc for more details) ( REQUIRED ) screenshots an array of paths to the screenshots of the application (paths in the build) services (application specific) a map of the services associated with the app (see cozy-stack services doc for more details) slug the default slug that should never change (alpha-numeric lowercase) ( REQUIRED ) source where the files of the app can be downloaded (by default it will look for the branch build ) terms an object defining properties for terms that need to be displayed/accepted by the user when installing the application ( more-info-below ) time_interval (konnector specific) By defaults, konnector triggers are scheduled randomly between 00:00 AM and 05:00 AM. Those two values can be overwritten thanks to this property, by passing an array containing two values: first is the interval start hour, second is the interval end hour. Example: [15, 21] will randomly schedule the konnector trigger between 15:00 (03:00 PM) and 21:00 (09:00 PM). The time zone used is GMT. type type of application ( konnector or webapp ) ( REQUIRED ) version the current version number ( REQUIRED ) vendor_link (konnector specific) URL to editor or service website Translated manifest fields \u00b6 Here are the properties that you can override using locales (we recommand to automatically build these properties according to your locales files if you\u2019re using a translating tool like transifex ): name , the app\u2019s name short_description , short description of what the app do long_description , longer and more complete description of the app behaviour changes , description of your new version of the konnector or all changes since the last version fields , An object containing translations for fields. screenshots folders { \"fields\" : { \"email\" : { \"type\" : \"email\" } }, \"locales\" : { \"en\" : { \"short_description\" : \"Collect your Orange's bills\" , \"fields\" : { \"email\" : { \"label\" : \"Identifier (your email)\" } } }, \"fr\" : { \"short_description\" : \"R\u00e9cup\u00e8re vos factures Orange\" , \"fields\" : { \"email\" : { \"label\" : \"Identifiant (votre adresse mail)\" } } } } } Available manifest\u2019s features list : \u00b6 2FA Two Factors identification. BILLS Import bills documents, doctype \u201cio.cozy.bills\u201d. FILES Import files documents, doctype \u201cio.cozy.files\u201d. CAPTCHA_RESOLUTION The konnector using a captcha resolution process. CARBON_COPY The konnector import legally true copy of the original files. DOC_QUALIFICATION The konnector uses the first version of files qualifications, you may stumble upon on some konnectors wich hasn\u2019t been treated. DOC_QUALIFICATION_V2 The konnector uses new version (last one for now) of files qualifications. ELECTRONIC_SAFE Files comes from a known electronic safe. HEALTH The konnector treat health documents HTML_TO_PDF The konnector needs to convert HTML page(s) to make pdf files. IDENTITY The konnector create identity(ies) for doctype \u201cio.cozy.identities\u201d LOGIN_OK The konnector deactivate the auto-notification METADATA_DEDUP The konnector uses a fileIdAttribute as detection to avoid deduplication. VENDOR_REF The konnector uses. SENTRY_V2 The konnector had been migrated (or packaged) to sentry V2 (errors.cozycloud.cc) Other Attributes \u00b6 Attribute Role state Store the installation state of the konnector. Value can be AVAILABLE , INSTALLING , UPGRADING , UNINSTALLING , INSTALLED , READY Example \u00b6 { \"version\" : \"1.0.0\" , \"name\" : \"debug\" , \"type\" : \"konnector\" , \"language\" : \"node\" , \"icon\" : \"icon.svg\" , \"slug\" : \"debug\" , \"source\" : \"git@github.com:konnectors/debug.git\" , \"editor\" : \"Cozy\" , \"vendor_link\" : \"\" , \"categories\" : [ \"\" ], \"fields\" : { \"login\" : { \"type\" : \"text\" }, \"password\" : { \"type\" : \"password\" } }, \"folders\" : [{ \"defaultDir\" : \"$administrative/$konnector/$account\" }], \"data_types\" : [ \"bill\" ], \"screenshots\" : [], \"permissions\" : { \"carbon_copy\" : { \"type\" : \"io.cozy.certified.carbon_copy\" }, \"bank operations\" : { \"type\" : \"io.cozy.bank.operations\" }, \"bills\" : { \"type\" : \"io.cozy.bills\" }, \"files\" : { \"type\" : \"io.cozy.files\" }, \"accounts\" : { \"type\" : \"io.cozy.accounts\" } }, \"developer\" : { \"name\" : \"Cozy Cloud\" , \"url\" : \"https://cozy.io\" }, \"langs\" : [ \"fr\" , \"en\" ], \"locales\" : { \"fr\" : { \"short_description\" : \"\" , \"long_description\" : \"\" , \"permissions\" : { \"carboncopy\" : { \"description\" : \"Utilis\u00e9 pour certifier que vos fichiers sont copie conforme avec les documents d'origine\" }, \"bank operations\" : { \"description\" : \"Utilis\u00e9 pour relier les factures \u00e0 des operations bancaires\" }, \"bills\" : { \"description\" : \"Utilis\u00e9 pour sauver les donn\u00e9es des factures\" }, \"files\" : { \"description\" : \"Utilis\u00e9 pour sauvegarder les factures\" }, \"accounts\" : { \"description\" : \"Utilis\u00e9 pour obtenir les donn\u00e9es du compte\" } } }, \"en\" : { \"short_description\" : \"Fetch your personnal documents.\" , \"long_description\" : \"Fetch the list of bills and personnal documents from your Luko account.\" , \"permissions\" : { \"carboncopy\" : { \"description\" : \"Use to certify your files are the exact copy of the originals\" }, \"bank operations\" : { \"description\" : \"Required to link bank operations to bills\" }, \"bills\" : { \"description\" : \"Required to save the bills data\" }, \"files\" : { \"description\" : \"Required to save the bills\" }, \"accounts\" : { \"description\" : \"Required to get the account's data\" } } } }, \"qualification_labels\" : [ \"\" ], \"features\" : [ \"LOGIN_OK\" , \"METADATA_DEDUP\" , \"CARBON_COPY\" , \"DOC_QUALIFICATION_V2\" , \"SENTRY_V2\" ], \"banksTransactionRegExp\" : \"\\\\bdebug\\\\b\" , \"manifest_version\" : \"2\" }", "title": "Connectors"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/#konnectors-doctype", "text": "The io.cozy.konnectors doctype is used to store installed konnectors. Konnectors are autonomous applications ran on the stack to connect to external services or API. When installing a konnector, the Cozy stack creates a new io.cozy.konnector document from the fields in the manifest.konnector . io.cozy.konnectors are used by Cozy-Store to install and uninstall konnectors, and by Cozy-Home to manage accounts for konnectors", "title": "Konnectors doctype"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/#attributes", "text": "", "title": "Attributes"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/#retrieved-from-manifestkonnector", "text": "The available attributes in a io.cozy.konnectors document are : Field Description aggregator Object containing aggregator data. Typically { accountId: 'aggregator-service' } . categories array of categories for your apps (see authorized categories), it will be ['others'] by default if empty clientSide Boolean to specify if the konnector should be run on the client or not data_types (konnector specific) Array of the data type the konnector will manage developer name and url for the developer editor the editor\u2019s name to display on the cozy-bar ( REQUIRED ) features (konnector specific) Array of features added in the konnector from the list below. fields (konnector specific) JSON object describing the fields need by the konnector ( except folder path ). Used to generate a form. See below folders (konnector specific) A list of folders required by the konnector to store files according to datatype (see the specific documentation below ) frequency (konnector specific) A human readable value between monthly , weekly , daily , indicating the interval of time between two runs of the konnector. Default: weekly . icon path to the icon for the home (path in the build) intents (application specific) a list of intents provided by this app (see cozy-stack intents doc for more details) langs Languages available in your app (can be different from locales) language (konnector specific) the konnector development language used (ex: node ) license the SPDX license identifier locales an object with language slug as property, each name property is an object of localized informations (see the second part below) manifest_version The current manifest version used. This is a versioning for the manifest and allow better retrocompatiblity when processing app manifest messages (konnector specific) Array of message identifiers, which can be used by application to display information at known areas. See example below . mobile (application specific) JSON object containing information about app\u2019s mobile version (see cozy-stack routes doc for more details) name the name to display on the home ( REQUIRED ) name_prefix the prefix to display with the name oauth (konnector specific) JSON object containing oAuth information, like scope . If a manifest provides an oauth property, it is considered as an OAuth konnector. Note: scope can be a string or an array. If it is an array, its values will be joined with a space. A false or null value in scope will remove any scope parameter in the request sent to the oauth provider. parameters (konnector specific) Additional parameters which should be passed to the konnector. Used for example for bank konnectors to pass a bankId parameter. partnership an object to provide informations (to display in the Store for example) about a partnership related to the application ( icon description , name and domain ). It can also be used to trigger alternative konnector connection policies for some vendors (see the budget-insight konnector policy in cozy-harvest ). permissions a map of permissions needed by the app (see see cozy-stack permissions doc for more details) platforms (application specific) List of objects for platform native applications. For now there are only two properties: type (i.e. 'ios' or 'linux' ) and the optional url to reach this application page. qualification_labels (konnector specific) Array of one or more labels from the Cozy Client\u2019s qualifications list to associate with the files the konnector will receive from the website. routes (application specific) a map of routes for the app (see cozy-stack routes doc for more details) ( REQUIRED ) screenshots an array of paths to the screenshots of the application (paths in the build) services (application specific) a map of the services associated with the app (see cozy-stack services doc for more details) slug the default slug that should never change (alpha-numeric lowercase) ( REQUIRED ) source where the files of the app can be downloaded (by default it will look for the branch build ) terms an object defining properties for terms that need to be displayed/accepted by the user when installing the application ( more-info-below ) time_interval (konnector specific) By defaults, konnector triggers are scheduled randomly between 00:00 AM and 05:00 AM. Those two values can be overwritten thanks to this property, by passing an array containing two values: first is the interval start hour, second is the interval end hour. Example: [15, 21] will randomly schedule the konnector trigger between 15:00 (03:00 PM) and 21:00 (09:00 PM). The time zone used is GMT. type type of application ( konnector or webapp ) ( REQUIRED ) version the current version number ( REQUIRED ) vendor_link (konnector specific) URL to editor or service website", "title": "Retrieved from manifest.konnector"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/#translated-manifest-fields", "text": "Here are the properties that you can override using locales (we recommand to automatically build these properties according to your locales files if you\u2019re using a translating tool like transifex ): name , the app\u2019s name short_description , short description of what the app do long_description , longer and more complete description of the app behaviour changes , description of your new version of the konnector or all changes since the last version fields , An object containing translations for fields. screenshots folders { \"fields\" : { \"email\" : { \"type\" : \"email\" } }, \"locales\" : { \"en\" : { \"short_description\" : \"Collect your Orange's bills\" , \"fields\" : { \"email\" : { \"label\" : \"Identifier (your email)\" } } }, \"fr\" : { \"short_description\" : \"R\u00e9cup\u00e8re vos factures Orange\" , \"fields\" : { \"email\" : { \"label\" : \"Identifiant (votre adresse mail)\" } } } } }", "title": "Translated manifest fields"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/#available-manifests-features-list", "text": "2FA Two Factors identification. BILLS Import bills documents, doctype \u201cio.cozy.bills\u201d. FILES Import files documents, doctype \u201cio.cozy.files\u201d. CAPTCHA_RESOLUTION The konnector using a captcha resolution process. CARBON_COPY The konnector import legally true copy of the original files. DOC_QUALIFICATION The konnector uses the first version of files qualifications, you may stumble upon on some konnectors wich hasn\u2019t been treated. DOC_QUALIFICATION_V2 The konnector uses new version (last one for now) of files qualifications. ELECTRONIC_SAFE Files comes from a known electronic safe. HEALTH The konnector treat health documents HTML_TO_PDF The konnector needs to convert HTML page(s) to make pdf files. IDENTITY The konnector create identity(ies) for doctype \u201cio.cozy.identities\u201d LOGIN_OK The konnector deactivate the auto-notification METADATA_DEDUP The konnector uses a fileIdAttribute as detection to avoid deduplication. VENDOR_REF The konnector uses. SENTRY_V2 The konnector had been migrated (or packaged) to sentry V2 (errors.cozycloud.cc)", "title": "Available manifest\u2019s features list :"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/#other-attributes", "text": "Attribute Role state Store the installation state of the konnector. Value can be AVAILABLE , INSTALLING , UPGRADING , UNINSTALLING , INSTALLED , READY", "title": "Other Attributes"}, {"location": "cozy-doctypes/docs/io.cozy.konnectors/#example", "text": "{ \"version\" : \"1.0.0\" , \"name\" : \"debug\" , \"type\" : \"konnector\" , \"language\" : \"node\" , \"icon\" : \"icon.svg\" , \"slug\" : \"debug\" , \"source\" : \"git@github.com:konnectors/debug.git\" , \"editor\" : \"Cozy\" , \"vendor_link\" : \"\" , \"categories\" : [ \"\" ], \"fields\" : { \"login\" : { \"type\" : \"text\" }, \"password\" : { \"type\" : \"password\" } }, \"folders\" : [{ \"defaultDir\" : \"$administrative/$konnector/$account\" }], \"data_types\" : [ \"bill\" ], \"screenshots\" : [], \"permissions\" : { \"carbon_copy\" : { \"type\" : \"io.cozy.certified.carbon_copy\" }, \"bank operations\" : { \"type\" : \"io.cozy.bank.operations\" }, \"bills\" : { \"type\" : \"io.cozy.bills\" }, \"files\" : { \"type\" : \"io.cozy.files\" }, \"accounts\" : { \"type\" : \"io.cozy.accounts\" } }, \"developer\" : { \"name\" : \"Cozy Cloud\" , \"url\" : \"https://cozy.io\" }, \"langs\" : [ \"fr\" , \"en\" ], \"locales\" : { \"fr\" : { \"short_description\" : \"\" , \"long_description\" : \"\" , \"permissions\" : { \"carboncopy\" : { \"description\" : \"Utilis\u00e9 pour certifier que vos fichiers sont copie conforme avec les documents d'origine\" }, \"bank operations\" : { \"description\" : \"Utilis\u00e9 pour relier les factures \u00e0 des operations bancaires\" }, \"bills\" : { \"description\" : \"Utilis\u00e9 pour sauver les donn\u00e9es des factures\" }, \"files\" : { \"description\" : \"Utilis\u00e9 pour sauvegarder les factures\" }, \"accounts\" : { \"description\" : \"Utilis\u00e9 pour obtenir les donn\u00e9es du compte\" } } }, \"en\" : { \"short_description\" : \"Fetch your personnal documents.\" , \"long_description\" : \"Fetch the list of bills and personnal documents from your Luko account.\" , \"permissions\" : { \"carboncopy\" : { \"description\" : \"Use to certify your files are the exact copy of the originals\" }, \"bank operations\" : { \"description\" : \"Required to link bank operations to bills\" }, \"bills\" : { \"description\" : \"Required to save the bills data\" }, \"files\" : { \"description\" : \"Required to save the bills\" }, \"accounts\" : { \"description\" : \"Required to get the account's data\" } } } }, \"qualification_labels\" : [ \"\" ], \"features\" : [ \"LOGIN_OK\" , \"METADATA_DEDUP\" , \"CARBON_COPY\" , \"DOC_QUALIFICATION_V2\" , \"SENTRY_V2\" ], \"banksTransactionRegExp\" : \"\\\\bdebug\\\\b\" , \"manifest_version\" : \"2\" }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.notes/", "text": "Table of contents Cozy notes doctypes \u00b6 io.cozy.notes.documents \u00b6 This doctype is not persisted in CouchDB, it is only used to create a note, and this note will be persisted as an io.cozy.files . Its attributes are: title : {string} the initial title of the note (that will also be used for the file name) dir_id : {string} the id of the directory where the file will be created (optional) schema : {object} the schema used by prosemirror (with notes and marks serialized as arrays to preserve the order). Example (JSON-API format) \u00b6 { \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"attributes\" : { \"title\" : \"My new note\" , \"dir_id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } } } } io.cozy.notes.steps \u00b6 This doctype is used for prosemirror steps. You can see them as a kind of patch on a note. It describes a small transformation on the note. Its attributes are: timestamp : {int} a timestamp of the date when the server accepted the step (it should only be used by the server) sessionID : {string} a random string used to identify the user that made the change version : {int} the version of the note before the change (the step can only be applied to the note if the version matches, else it has to rebased by the client) stepType : {string} the type of the step, as defined by prosemirror from , to , slice : data that can be interpreted by prosemirror in function of the step type. Example (JSON in CouchDB) \u00b6 { \"_id\" : \"d9fc3726f254a0ccfb2ca30d9e00142a/00000001\" , \"_rev\" : \"1-894d54b267404abad9a1cf08f1a8a663\" , \"from\" : 1 , \"sessionID\" : \"cozy.tools75:1576503622324.324.0.9928191162716804\" , \"slice\" : { \"content\" : [ { \"text\" : \"H\" , \"type\" : \"text\" } ] }, \"stepType\" : \"replace\" , \"timestamp\" : 1576503628 , \"to\" : 1 , \"version\" : 1 } io.cozy.notes.telepointers \u00b6 This doctype is not persisted, it is sent by the clients to the stack, and the stack send them to the other clients via the realtime websockets. Its attributes are: sessionID : {string} a random string used to identify the user that made the change type : {string} the type of the telepointer, as defined by prosemirror anchor , head : data that can be interpreted by prosemirror. Example (JSON-API format) \u00b6 { \"data\" : { \"type\" : \"io.cozy.notes.telepointers\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"anchor\" : 7 , \"head\" : 12 , \"type\" : \"textSelection\" } } } io.cozy.notes.events \u00b6 This doctype is only used for sending the events related to a note in the realtime websockets. The client subscribes to a note, and the server send events on this note, that can be a change on the note title, its content, or a telepointer update. Example \u00b6 client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.notes.events\", \"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.documents\", \"sessionID\": \"543781490137\", \"title\": \"this is the new title of this note\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.steps\", \"sessionID\": \"543781490137\", \"version\": 6, \"stepType\": \"replace\", \"from\": 1, \"to\": 1, \"slice\": {\"content\": [{\"type\": \"text\", \"text\": \"H\"}]}}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.telepointers\", \"sessionID\": \"543781490137\", \"anchor\": 7, \"head\": 12, \"type\": \"textSelection\"}}} io.cozy.notes.images \u00b6 This doctype is used to keep track of images added to a note. Its attributes are: name : {string} The image name mime : {string} The image mime-type width : {number} The image width height : {number} The image height willBeResized : {boolean} Set by the stack to determine if the image is too large to be contained in the note and a thumbnail needs to be computed. willBeRemoved : {boolean} Set by the stack to indicate the image needs to be later removed. This is used to give some time to the user to cancel the deletion of an image. Example (JSON in CouchDB) \u00b6 { \"_id\" : \"7690fa7c64f9fa512531319e3df9f472/dd1776a3-6abe-47dc-b0d9-6c0e345b2679\" , \"name\" : \"clisk.png\" , \"mime\" : \"image/svg+xml\" , \"width\" : 341 , \"height\" : 512 }", "title": "Notes"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#cozy-notes-doctypes", "text": "", "title": "Cozy notes doctypes"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#iocozynotesdocuments", "text": "This doctype is not persisted in CouchDB, it is only used to create a note, and this note will be persisted as an io.cozy.files . Its attributes are: title : {string} the initial title of the note (that will also be used for the file name) dir_id : {string} the id of the directory where the file will be created (optional) schema : {object} the schema used by prosemirror (with notes and marks serialized as arrays to preserve the order).", "title": "io.cozy.notes.documents"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#example-json-api-format", "text": "{ \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"attributes\" : { \"title\" : \"My new note\" , \"dir_id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } } } }", "title": "Example (JSON-API format)"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#iocozynotessteps", "text": "This doctype is used for prosemirror steps. You can see them as a kind of patch on a note. It describes a small transformation on the note. Its attributes are: timestamp : {int} a timestamp of the date when the server accepted the step (it should only be used by the server) sessionID : {string} a random string used to identify the user that made the change version : {int} the version of the note before the change (the step can only be applied to the note if the version matches, else it has to rebased by the client) stepType : {string} the type of the step, as defined by prosemirror from , to , slice : data that can be interpreted by prosemirror in function of the step type.", "title": "io.cozy.notes.steps"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#example-json-in-couchdb", "text": "{ \"_id\" : \"d9fc3726f254a0ccfb2ca30d9e00142a/00000001\" , \"_rev\" : \"1-894d54b267404abad9a1cf08f1a8a663\" , \"from\" : 1 , \"sessionID\" : \"cozy.tools75:1576503622324.324.0.9928191162716804\" , \"slice\" : { \"content\" : [ { \"text\" : \"H\" , \"type\" : \"text\" } ] }, \"stepType\" : \"replace\" , \"timestamp\" : 1576503628 , \"to\" : 1 , \"version\" : 1 }", "title": "Example (JSON in CouchDB)"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#iocozynotestelepointers", "text": "This doctype is not persisted, it is sent by the clients to the stack, and the stack send them to the other clients via the realtime websockets. Its attributes are: sessionID : {string} a random string used to identify the user that made the change type : {string} the type of the telepointer, as defined by prosemirror anchor , head : data that can be interpreted by prosemirror.", "title": "io.cozy.notes.telepointers"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#example-json-api-format_1", "text": "{ \"data\" : { \"type\" : \"io.cozy.notes.telepointers\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"anchor\" : 7 , \"head\" : 12 , \"type\" : \"textSelection\" } } }", "title": "Example (JSON-API format)"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#iocozynotesevents", "text": "This doctype is only used for sending the events related to a note in the realtime websockets. The client subscribes to a note, and the server send events on this note, that can be a change on the note title, its content, or a telepointer update.", "title": "io.cozy.notes.events"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#example", "text": "client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.notes.events\", \"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.documents\", \"sessionID\": \"543781490137\", \"title\": \"this is the new title of this note\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.steps\", \"sessionID\": \"543781490137\", \"version\": 6, \"stepType\": \"replace\", \"from\": 1, \"to\": 1, \"slice\": {\"content\": [{\"type\": \"text\", \"text\": \"H\"}]}}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.telepointers\", \"sessionID\": \"543781490137\", \"anchor\": 7, \"head\": 12, \"type\": \"textSelection\"}}}", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#iocozynotesimages", "text": "This doctype is used to keep track of images added to a note. Its attributes are: name : {string} The image name mime : {string} The image mime-type width : {number} The image width height : {number} The image height willBeResized : {boolean} Set by the stack to determine if the image is too large to be contained in the note and a thumbnail needs to be computed. willBeRemoved : {boolean} Set by the stack to indicate the image needs to be later removed. This is used to give some time to the user to cancel the deletion of an image.", "title": "io.cozy.notes.images"}, {"location": "cozy-doctypes/docs/io.cozy.notes/#example-json-in-couchdb_1", "text": "{ \"_id\" : \"7690fa7c64f9fa512531319e3df9f472/dd1776a3-6abe-47dc-b0d9-6c0e345b2679\" , \"name\" : \"clisk.png\" , \"mime\" : \"image/svg+xml\" , \"width\" : 341 , \"height\" : 512 }", "title": "Example (JSON in CouchDB)"}, {"location": "cozy-doctypes/docs/io.cozy.notifications/", "text": "Table of contents Cozy Notifications doctype \u00b6 io.cozy.notifications \u00b6 Applications can notify the cozy owner. They will appear in the cozy-bar, the mobile app, and a summary can be sent by email. source : {id} the id of the application/konnector that has made the notification reference : {string} a reference for the application (it can be used to hide other notifications like this one, or to update a count in a notification) title : {string} a title to explain the notification content : {string} more context about the notification icon : {image} an icon to display with the notification actions : [{text, intent}] an array of objects with a text and an intent. Each action can be seen as a link, the text being what is shown and the intent what happens when clicking on the link. created_at : {timestamp} the date of the creation. See also the notification documentation for more informations.", "title": "Notifications"}, {"location": "cozy-doctypes/docs/io.cozy.notifications/#cozy-notifications-doctype", "text": "", "title": "Cozy Notifications doctype"}, {"location": "cozy-doctypes/docs/io.cozy.notifications/#iocozynotifications", "text": "Applications can notify the cozy owner. They will appear in the cozy-bar, the mobile app, and a summary can be sent by email. source : {id} the id of the application/konnector that has made the notification reference : {string} a reference for the application (it can be used to hide other notifications like this one, or to update a count in a notification) title : {string} a title to explain the notification content : {string} more context about the notification icon : {image} an icon to display with the notification actions : [{text, intent}] an array of objects with a text and an intent. Each action can be seen as a link, the text being what is shown and the intent what happens when clicking on the link. created_at : {timestamp} the date of the creation. See also the notification documentation for more informations.", "title": "io.cozy.notifications"}, {"location": "cozy-doctypes/docs/io.cozy.oauth.access_codes/", "text": "Cozy OAuth access codes doctype io.cozy.oauth.access_codes Cozy OAuth access codes doctype \u00b6 io.cozy.oauth.access_codes \u00b6 The io.cozy.oauth.access_codes doctype contain the OAuth access codes used in the OAuth2 flow. code {string}: The access code issued_at {timestamp}: When the access code has been issued scope {string}: Scope allowed for this access code ( see here ) More informations are available on the official documentation", "title": "OAuth Access Codes"}, {"location": "cozy-doctypes/docs/io.cozy.oauth.access_codes/#cozy-oauth-access-codes-doctype", "text": "", "title": "Cozy OAuth access codes doctype"}, {"location": "cozy-doctypes/docs/io.cozy.oauth.access_codes/#iocozyoauthaccess_codes", "text": "The io.cozy.oauth.access_codes doctype contain the OAuth access codes used in the OAuth2 flow. code {string}: The access code issued_at {timestamp}: When the access code has been issued scope {string}: Scope allowed for this access code ( see here ) More informations are available on the official documentation", "title": "io.cozy.oauth.access_codes"}, {"location": "cozy-doctypes/docs/io.cozy.oauth.clients/", "text": "Cozy OAuth clients doctype io.cozy.oauth.clients Cozy OAuth clients doctype \u00b6 io.cozy.oauth.clients \u00b6 The io.cozy.oauth.clients doctype contain the OAuth clients informations used in the OAuth2 flow. client_id {string}: ClientID, part of the official OAuth Standard client_secret {string}: ClientSecret, part of the official OAuth Standard, generated by the cozy-stack client_secret_expires_at : {timestamp}: When the client secret will expire and will not be usable anymore. By default, it won\u2019t expire registration_access_token {string}: Token used for the web instance onboarding allow_login_scope {bool}: Allow (or not) a login scope generation redirect_uris {[]string}: List of URIs used for redirection after login, declared by the client. Part of the official OAuth Standard grant_types {[]string}: Kind of grant for the client ( authorization_code or refresh_token ). Part of the official OAuth Standard response_types {[]string}: Kind of responses ( code ). Part of the official OAuth Standard client_name {string}: Client name client_kind {string}: Client kind (mobile, browser, desktop, \u2026). Optional. client_uri {string}: Client URI. Optional. logo_uri {string}: Client logo URI. Optional policy_uri {string}: Client policy URI. Optional software_id {string}: Client software identifier software_version {string}: Client software version. Optional notifications {object}: Notifications parameters for the client. notifications_platform {string}: Notification platform (android, iOS, \u2026). Optional, declared by the client notifications_device_token : {string}: Token for the notifications. Optional, declared by the client. client_os : {string}: The Operating System of the client, inferred from the user-agent. synchronized_at : {date}: Date of the last synchronization. Used by settings. last_refreshed_at : {date}: Date of the last time an access_token has been given for this client (from an authorization_code or a refresh_token). onboarding_* {string}: onboarding_secret , onboarding_app , onboarding_permissions & onboarding_state are used for an onboarding straight on the mobile. The official documentation give a more in-depth overview of the OAuth client authorization workflow.", "title": "OAuth Clients"}, {"location": "cozy-doctypes/docs/io.cozy.oauth.clients/#cozy-oauth-clients-doctype", "text": "", "title": "Cozy OAuth clients doctype"}, {"location": "cozy-doctypes/docs/io.cozy.oauth.clients/#iocozyoauthclients", "text": "The io.cozy.oauth.clients doctype contain the OAuth clients informations used in the OAuth2 flow. client_id {string}: ClientID, part of the official OAuth Standard client_secret {string}: ClientSecret, part of the official OAuth Standard, generated by the cozy-stack client_secret_expires_at : {timestamp}: When the client secret will expire and will not be usable anymore. By default, it won\u2019t expire registration_access_token {string}: Token used for the web instance onboarding allow_login_scope {bool}: Allow (or not) a login scope generation redirect_uris {[]string}: List of URIs used for redirection after login, declared by the client. Part of the official OAuth Standard grant_types {[]string}: Kind of grant for the client ( authorization_code or refresh_token ). Part of the official OAuth Standard response_types {[]string}: Kind of responses ( code ). Part of the official OAuth Standard client_name {string}: Client name client_kind {string}: Client kind (mobile, browser, desktop, \u2026). Optional. client_uri {string}: Client URI. Optional. logo_uri {string}: Client logo URI. Optional policy_uri {string}: Client policy URI. Optional software_id {string}: Client software identifier software_version {string}: Client software version. Optional notifications {object}: Notifications parameters for the client. notifications_platform {string}: Notification platform (android, iOS, \u2026). Optional, declared by the client notifications_device_token : {string}: Token for the notifications. Optional, declared by the client. client_os : {string}: The Operating System of the client, inferred from the user-agent. synchronized_at : {date}: Date of the last synchronization. Used by settings. last_refreshed_at : {date}: Date of the last time an access_token has been given for this client (from an authorization_code or a refresh_token). onboarding_* {string}: onboarding_secret , onboarding_app , onboarding_permissions & onboarding_state are used for an onboarding straight on the mobile. The official documentation give a more in-depth overview of the OAuth client authorization workflow.", "title": "io.cozy.oauth.clients"}, {"location": "cozy-doctypes/docs/io.cozy.permissions/", "text": "Cozy permissions doctype io.cozy.permissions Cozy permissions doctype \u00b6 io.cozy.permissions \u00b6 The io.cozy.permissions doctype is used for a owner of the cozy instance to control the access of his data. type {string}: Permission type register : temporary permissions allowed by registerToken app : permissions for an application konnector : permissions for a konnector oauth : permissions for an oauth cli : permissions for commandline share : permissions for a share by link share-preview permissions for a preview in cozy-to-cozy sharing source_id {string}: Source of the permission. Can be used to reference a parent permissions permissions {object}: Set of rules to allow/disallow actions on data see here expires_at {timestamp}: When the permission expires codes {map[string]string}: Contains a list of the members (email or instance name) of a permission shortcodes {map[string]string}: Like codes, but contains a shorter code (12 chars) instead of a token See also the official documentation for additional informations", "title": "Permissions"}, {"location": "cozy-doctypes/docs/io.cozy.permissions/#cozy-permissions-doctype", "text": "", "title": "Cozy permissions doctype"}, {"location": "cozy-doctypes/docs/io.cozy.permissions/#iocozypermissions", "text": "The io.cozy.permissions doctype is used for a owner of the cozy instance to control the access of his data. type {string}: Permission type register : temporary permissions allowed by registerToken app : permissions for an application konnector : permissions for a konnector oauth : permissions for an oauth cli : permissions for commandline share : permissions for a share by link share-preview permissions for a preview in cozy-to-cozy sharing source_id {string}: Source of the permission. Can be used to reference a parent permissions permissions {object}: Set of rules to allow/disallow actions on data see here expires_at {timestamp}: When the permission expires codes {map[string]string}: Contains a list of the members (email or instance name) of a permission shortcodes {map[string]string}: Like codes, but contains a shorter code (12 chars) instead of a token See also the official documentation for additional informations", "title": "io.cozy.permissions"}, {"location": "cozy-doctypes/docs/io.cozy.photos/", "text": "Table of contents Cozy Photos doctype \u00b6 io.cozy.photos.albums \u00b6 This doctype is used both for manual albums and for clusters. name : {string} the name of the album. It is the date of the oldest photo for a cluster. auto : {bool} true if the album was automatically computed, and is therefore a cluster. period : {object} if cluster, the temporal period of the album. start : {date} the date of the oldest photo. end : {date} the date of the newest photo. The photos in an album are files (with the class image ) that are referenced by the album document. io.cozy.photos.settings \u00b6 This doctype is used to store settings for photos, useful for the clustering. type : {string} the type of settings, e.g. clustering . Clustering settings \u00b6 lastDate : {date} the date of the last clustered photo. It is the value of the cozyMetadata.createdAt saved in the io.cozy.files of the photo. jobStatus : {string} the execution status, can be running if the service is running, postponed if an execution is planned later, or empty. evaluationCount : {number} indicates the number of photos clustered since the last parameters evaluation. If this number is greater than a threshold, it triggers a new parameter evaluation and reset this number to 0. runs : {number} number of all clustering runs, it is incremented at each new successful execution. parameters : {array} a list of parameters for the clustering with the following attributes: period : {object} the temporal period of the clustered photos for this set of parameters. start : {date} the start of the period. end : {date} the end of the period. modes : {array} a list of granularity modes parameters, with the following attributes: name : {string} the name of the mode, e.g. default or macro . eps_temporal : {number} the temporal epsilon parameter. eps_spatial : {number} the spatial epsilon parameter. evaluation : {object} the evaluation period on which the parameters have been computed. start : {date} the start of the period. end : {date} the end of the period. defaultEvaluation : {bool} if the current evaluation use default parameters because there was not enough photos.", "title": "Photos"}, {"location": "cozy-doctypes/docs/io.cozy.photos/#cozy-photos-doctype", "text": "", "title": "Cozy Photos doctype"}, {"location": "cozy-doctypes/docs/io.cozy.photos/#iocozyphotosalbums", "text": "This doctype is used both for manual albums and for clusters. name : {string} the name of the album. It is the date of the oldest photo for a cluster. auto : {bool} true if the album was automatically computed, and is therefore a cluster. period : {object} if cluster, the temporal period of the album. start : {date} the date of the oldest photo. end : {date} the date of the newest photo. The photos in an album are files (with the class image ) that are referenced by the album document.", "title": "io.cozy.photos.albums"}, {"location": "cozy-doctypes/docs/io.cozy.photos/#iocozyphotossettings", "text": "This doctype is used to store settings for photos, useful for the clustering. type : {string} the type of settings, e.g. clustering .", "title": "io.cozy.photos.settings"}, {"location": "cozy-doctypes/docs/io.cozy.photos/#clustering-settings", "text": "lastDate : {date} the date of the last clustered photo. It is the value of the cozyMetadata.createdAt saved in the io.cozy.files of the photo. jobStatus : {string} the execution status, can be running if the service is running, postponed if an execution is planned later, or empty. evaluationCount : {number} indicates the number of photos clustered since the last parameters evaluation. If this number is greater than a threshold, it triggers a new parameter evaluation and reset this number to 0. runs : {number} number of all clustering runs, it is incremented at each new successful execution. parameters : {array} a list of parameters for the clustering with the following attributes: period : {object} the temporal period of the clustered photos for this set of parameters. start : {date} the start of the period. end : {date} the end of the period. modes : {array} a list of granularity modes parameters, with the following attributes: name : {string} the name of the mode, e.g. default or macro . eps_temporal : {number} the temporal epsilon parameter. eps_spatial : {number} the spatial epsilon parameter. evaluation : {object} the evaluation period on which the parameters have been computed. start : {date} the start of the period. end : {date} the end of the period. defaultEvaluation : {bool} if the current evaluation use default parameters because there was not enough photos.", "title": "Clustering settings"}, {"location": "cozy-doctypes/docs/io.cozy.procedures/", "text": "Table of contents Cozy Administrative Procedures doctype \u00b6 io.cozy.procedures.administratives \u00b6 The io.cozy.procedures.administratives doctype represents the administrative procedures. An administrative procedure is composed by the informations about the procedure, the personal information of the person that origins the procedure and the relations to the documents required for the procedure. The template referred to describes the data we need for this type of procedure ( e.g the documents, personal informations, etc). Those templates are not CouchDB documents for now. procedureData : {object} the data about the procedure ( e.g amount, duration, etc ). personalData : {object} the personal data associated to the procedure ( e.g email, phone number, etc ). templateId : {string} the template\u2019s identifier templateVersion : {number} the template\u2019s version relationships : {object} links between documents files : {object} attachments data : {array} list of files _id : {string} id of the io.cozy.files document _type : {string} doctype \u201cio.cozy.files\u201d templateDocumentId : {string} the id of the document in the template", "title": "Procedures"}, {"location": "cozy-doctypes/docs/io.cozy.procedures/#cozy-administrative-procedures-doctype", "text": "", "title": "Cozy Administrative Procedures doctype"}, {"location": "cozy-doctypes/docs/io.cozy.procedures/#iocozyproceduresadministratives", "text": "The io.cozy.procedures.administratives doctype represents the administrative procedures. An administrative procedure is composed by the informations about the procedure, the personal information of the person that origins the procedure and the relations to the documents required for the procedure. The template referred to describes the data we need for this type of procedure ( e.g the documents, personal informations, etc). Those templates are not CouchDB documents for now. procedureData : {object} the data about the procedure ( e.g amount, duration, etc ). personalData : {object} the personal data associated to the procedure ( e.g email, phone number, etc ). templateId : {string} the template\u2019s identifier templateVersion : {number} the template\u2019s version relationships : {object} links between documents files : {object} attachments data : {array} list of files _id : {string} id of the io.cozy.files document _type : {string} doctype \u201cio.cozy.files\u201d templateDocumentId : {string} the id of the document in the template", "title": "io.cozy.procedures.administratives"}, {"location": "cozy-doctypes/docs/io.cozy.remote.nextcloud.files/", "text": "Table of contents NextCloud files doctype \u00b6 io.cozy.remote.nextcloud.files \u00b6 Description \u00b6 The nextcloud konnector can be used to create an io.cozy.account for a NextCloud. Then, the stack can be used as a client for this NextCloud account. It supports files operations via WebDAV, with the io.cozy.remote.nextcloud.files doctype. Attributes \u00b6 type {string} - file or directory name {string} - The name of this file or directory size {number} - The size of the file in bytes mime {string} - The mime-type of the file class {string} - A class in the list: ['image', 'document', 'audio', 'video', 'text', 'binary', 'pdf', 'files', 'code', 'slide', 'spreadsheet', 'text', 'zip', 'shortcut'] updated_at {date} - The date of the last update of this file etag {string} - An ETag which can be used to know when the content change (given by NextCloud) Example (JSON-API format) \u00b6 { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"208937\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"BugBounty.pdf\" , \"size\" : 2947 , \"mime\" : \"application/pdf\" , \"class\" : \"pdf\" , \"updated_at\" : \"Mon, 14 Jan 2019 08:22:21 GMT\" , \"etag\" : \"\\\"dd1a602431671325b7c1538f829248d9\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/208937?dir=/Documents\" } }", "title": "Remote NextCloud files"}, {"location": "cozy-doctypes/docs/io.cozy.remote.nextcloud.files/#nextcloud-files-doctype", "text": "", "title": "NextCloud files doctype"}, {"location": "cozy-doctypes/docs/io.cozy.remote.nextcloud.files/#iocozyremotenextcloudfiles", "text": "", "title": "io.cozy.remote.nextcloud.files"}, {"location": "cozy-doctypes/docs/io.cozy.remote.nextcloud.files/#description", "text": "The nextcloud konnector can be used to create an io.cozy.account for a NextCloud. Then, the stack can be used as a client for this NextCloud account. It supports files operations via WebDAV, with the io.cozy.remote.nextcloud.files doctype.", "title": "Description"}, {"location": "cozy-doctypes/docs/io.cozy.remote.nextcloud.files/#attributes", "text": "type {string} - file or directory name {string} - The name of this file or directory size {number} - The size of the file in bytes mime {string} - The mime-type of the file class {string} - A class in the list: ['image', 'document', 'audio', 'video', 'text', 'binary', 'pdf', 'files', 'code', 'slide', 'spreadsheet', 'text', 'zip', 'shortcut'] updated_at {date} - The date of the last update of this file etag {string} - An ETag which can be used to know when the content change (given by NextCloud)", "title": "Attributes"}, {"location": "cozy-doctypes/docs/io.cozy.remote.nextcloud.files/#example-json-api-format", "text": "{ \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"208937\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"BugBounty.pdf\" , \"size\" : 2947 , \"mime\" : \"application/pdf\" , \"class\" : \"pdf\" , \"updated_at\" : \"Mon, 14 Jan 2019 08:22:21 GMT\" , \"etag\" : \"\\\"dd1a602431671325b7c1538f829248d9\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/208937?dir=/Documents\" } }", "title": "Example (JSON-API format)"}, {"location": "cozy-doctypes/docs/io.cozy.remote.requests/", "text": "Table of contents Logs of the requests via the remote doctypes \u00b6 io.cozy.remote.requests \u00b6 doctype : the remote doctype used in the request (example: org.wikidata.entity ) verb : the HTTP verb used for the request ( GET or POST ) url : the URL of the remote website, with variables injected in it response_code : the HTTP response code, (often 200 ) content_type : the content-type of the response (example: application/json ) variables : the key->value map of the variables sent to the stack, including the \u201ccomments\u201d (variables that are not sent to the remote website, but can be useful for the people reading the logs). created_at : the date/time of the request", "title": "Remote requests"}, {"location": "cozy-doctypes/docs/io.cozy.remote.requests/#logs-of-the-requests-via-the-remote-doctypes", "text": "", "title": "Logs of the requests via the remote doctypes"}, {"location": "cozy-doctypes/docs/io.cozy.remote.requests/#iocozyremoterequests", "text": "doctype : the remote doctype used in the request (example: org.wikidata.entity ) verb : the HTTP verb used for the request ( GET or POST ) url : the URL of the remote website, with variables injected in it response_code : the HTTP response code, (often 200 ) content_type : the content-type of the response (example: application/json ) variables : the key->value map of the variables sent to the stack, including the \u201ccomments\u201d (variables that are not sent to the remote website, but can be useful for the people reading the logs). created_at : the date/time of the request", "title": "io.cozy.remote.requests"}, {"location": "cozy-doctypes/docs/io.cozy.sessions.logins/", "text": "Table of contents Session login entry \u00b6 io.cozy.sessions.logins \u00b6 This doctype represent an entry in the session history: ip : {string} the ip used to login city : {string} the city from where the user has logged in (estimated from IP) country : {string} the country from where the user has logged in (estimated from IP) user_agent : {string} the full useragent string used to login os : {string} the os used to login browser : {string} the browser used to login created_at : {string} the login date", "title": "Sessions Logins"}, {"location": "cozy-doctypes/docs/io.cozy.sessions.logins/#session-login-entry", "text": "", "title": "Session login entry"}, {"location": "cozy-doctypes/docs/io.cozy.sessions.logins/#iocozysessionslogins", "text": "This doctype represent an entry in the session history: ip : {string} the ip used to login city : {string} the city from where the user has logged in (estimated from IP) country : {string} the country from where the user has logged in (estimated from IP) user_agent : {string} the full useragent string used to login os : {string} the os used to login browser : {string} the browser used to login created_at : {string} the login date", "title": "io.cozy.sessions.logins"}, {"location": "cozy-doctypes/docs/io.cozy.sessions/", "text": "Cozy sessions doctype io.cozy.sessions Example Cozy sessions doctype \u00b6 io.cozy.sessions \u00b6 The io.cozy.sessions doctype holds the web sessions informations. created_at {timestamp}: When the session has been created last_seen {timestamp}: When the user has been seen for the last time long_run {bool}: Either the session is a long run one or not (used for cookies) Example \u00b6 { \"_id\" : \"add3ca2ca5532c0323df0ec7fc04ea6f\" , \"_rev\" : \"3-a01838aee2211b84df392381461362ed\" , \"created_at\" : \"2019-05-10T17:01:12.150074836+02:00\" , \"last_seen\" : \"2019-05-14T10:21:47.961429238+02:00\" , \"long_run\" : false }", "title": "Sessions"}, {"location": "cozy-doctypes/docs/io.cozy.sessions/#cozy-sessions-doctype", "text": "", "title": "Cozy sessions doctype"}, {"location": "cozy-doctypes/docs/io.cozy.sessions/#iocozysessions", "text": "The io.cozy.sessions doctype holds the web sessions informations. created_at {timestamp}: When the session has been created last_seen {timestamp}: When the user has been seen for the last time long_run {bool}: Either the session is a long run one or not (used for cookies)", "title": "io.cozy.sessions"}, {"location": "cozy-doctypes/docs/io.cozy.sessions/#example", "text": "{ \"_id\" : \"add3ca2ca5532c0323df0ec7fc04ea6f\" , \"_rev\" : \"3-a01838aee2211b84df392381461362ed\" , \"created_at\" : \"2019-05-10T17:01:12.150074836+02:00\" , \"last_seen\" : \"2019-05-14T10:21:47.961429238+02:00\" , \"long_run\" : false }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.settings/", "text": "Cozy settings doctype io.cozy.settings Cozy settings doctype \u00b6 io.cozy.settings \u00b6 The io.cozy.settings doctype contains some documents. The most important one is the stack instance-related settings. Instance settings document \u00b6 _id : io.cozy.settings.instance tz : {string} Timezone of the instance (ex: Europe/Paris ) email : {string} Email of the instance public_name : {string} Public displayed name of the instance default_redirection : {string} Redirect to an app after login (ex: drive/#/folder ) colorScheme : {\u2018light\u2019|\u2019dark\u2019|\u2019auto} Used to manage the appearance of an app Bitwarden settings document \u00b6 There is also a document with the stuff related to authentication and Bitwarden: _id : io.cozy.settings.bitwarden passphrase_kdf : {int} the type of KDF (0 for PBKDF2 with SHA256) passphrase_kdf_iterations : {int} the number of iterations to derive the master key from the password passphrase_hint : {string} a message displayed in bitwarden clients to help the user finding again their password security_stamp : {string} a value changed when the password is modified, to ensure that bitwarden clients don\u2019t send ciphers encrypted with the old password key : {string} the key used to encrypt ciphers, itself encrypted with the master key public_key : {string} the public key of the user for the cozy organization private_key : {string} the private key of the user for the cozy organization (encrypted) encrypted_organization_key : {string} the key to encrypt/decrypt the ciphers in the Cozy organization (encrypted) organization_id : {string} the identifier of the Cozy organization collection_id : {string} the identifier of the collection for the Cozy organization equivalent_domains : {array} an array with lists of equivalent domains global_equivalent_domains : {array} an array of integers used by bitwarden clients Display settings document \u00b6 Deprecated because there is no direct stack route to use it. _id : io.cozy.settings.display pushBanners : {object} Relative attributes to push banners hideFlagshipApp : {bool} Hide the push banner for Flagship App hidePassMobile : {bool} Hide the push banner for Pass Mobile App", "title": "Settings"}, {"location": "cozy-doctypes/docs/io.cozy.settings/#cozy-settings-doctype", "text": "", "title": "Cozy settings doctype"}, {"location": "cozy-doctypes/docs/io.cozy.settings/#iocozysettings", "text": "The io.cozy.settings doctype contains some documents. The most important one is the stack instance-related settings.", "title": "io.cozy.settings"}, {"location": "cozy-doctypes/docs/io.cozy.settings/#instance-settings-document", "text": "_id : io.cozy.settings.instance tz : {string} Timezone of the instance (ex: Europe/Paris ) email : {string} Email of the instance public_name : {string} Public displayed name of the instance default_redirection : {string} Redirect to an app after login (ex: drive/#/folder ) colorScheme : {\u2018light\u2019|\u2019dark\u2019|\u2019auto} Used to manage the appearance of an app", "title": "Instance settings document"}, {"location": "cozy-doctypes/docs/io.cozy.settings/#bitwarden-settings-document", "text": "There is also a document with the stuff related to authentication and Bitwarden: _id : io.cozy.settings.bitwarden passphrase_kdf : {int} the type of KDF (0 for PBKDF2 with SHA256) passphrase_kdf_iterations : {int} the number of iterations to derive the master key from the password passphrase_hint : {string} a message displayed in bitwarden clients to help the user finding again their password security_stamp : {string} a value changed when the password is modified, to ensure that bitwarden clients don\u2019t send ciphers encrypted with the old password key : {string} the key used to encrypt ciphers, itself encrypted with the master key public_key : {string} the public key of the user for the cozy organization private_key : {string} the private key of the user for the cozy organization (encrypted) encrypted_organization_key : {string} the key to encrypt/decrypt the ciphers in the Cozy organization (encrypted) organization_id : {string} the identifier of the Cozy organization collection_id : {string} the identifier of the collection for the Cozy organization equivalent_domains : {array} an array with lists of equivalent domains global_equivalent_domains : {array} an array of integers used by bitwarden clients", "title": "Bitwarden settings document"}, {"location": "cozy-doctypes/docs/io.cozy.settings/#display-settings-document", "text": "Deprecated because there is no direct stack route to use it. _id : io.cozy.settings.display pushBanners : {object} Relative attributes to push banners hideFlagshipApp : {bool} Hide the push banner for Flagship App hidePassMobile : {bool} Hide the push banner for Pass Mobile App", "title": "Display settings document"}, {"location": "cozy-doctypes/docs/io.cozy.shared/", "text": "Cozy shared doctype io.cozy.shared Cozy shared doctype \u00b6 io.cozy.shared \u00b6 The io.cozy.shared doctype is related to the sharing part of the stack. It tracks the sharings and its references, its infos & revisions across the stack. revisions {object}: Tree of revisions of a sharing infos {map[string]object}: Infos of the sharing rule {int}: Index of the rule inside the sharing rules removed {bool}: Either the document has been deleted, the file is trashed, or the document does no longer match the sharing rule binary {bool}: Only true if the sharing is a file and has not been trashed For more informations, see the official documentation", "title": "Shared"}, {"location": "cozy-doctypes/docs/io.cozy.shared/#cozy-shared-doctype", "text": "", "title": "Cozy shared doctype"}, {"location": "cozy-doctypes/docs/io.cozy.shared/#iocozyshared", "text": "The io.cozy.shared doctype is related to the sharing part of the stack. It tracks the sharings and its references, its infos & revisions across the stack. revisions {object}: Tree of revisions of a sharing infos {map[string]object}: Infos of the sharing rule {int}: Index of the rule inside the sharing rules removed {bool}: Either the document has been deleted, the file is trashed, or the document does no longer match the sharing rule binary {bool}: Only true if the sharing is a file and has not been trashed For more informations, see the official documentation", "title": "io.cozy.shared"}, {"location": "cozy-doctypes/docs/io.cozy.sharings/", "text": "Table of contents io.cozy.sharings \u00b6 This doctype describes a sharing, ie an action made by some user to share some documents and files from her cozy instance to other people. An identifier (the same for all members of the sharing) A list of members . The first one is the owner. For each member, we have the URL of the cozy, a public name, an email, a status and some credentials to authorize the transfer of data between the owner and the recipients. The status can be: owner for the member that has created the sharing mail-not-sent for a member that has been added, but its invitation has not yet been sent (often, this status is used only for a few seconds) pending for a member with an invitation sent, but who has not clicked on the link seen for a member that has clicked on the invitation link, but has not setup the Cozy to Cozy replication for the sharing ready for a member where the Cozy to Cozy replication has been set up revoked for a member who is on longer in the sharing A list of groups , with for each one: id , the identifier of the io.cozy.contacts.groups name , the name of the group addedBy , the index of the member that has added the group read_only , a flag to tell if the group is restricted to read-only mode revoked , a flag set to true when the group is revoked from the sharing A description (one sentence that will help people understand what is shared and why) a flag active that says if the sharing is currently active for at least one member a flag owner , true for the document on the cozy of the sharer, and absent on the other cozy instance a flag open_sharing : true if any member of the sharing can add a new recipient false if only the owner can add a new recipient Some technical data ( created_at , updated_at , app_slug , preview_path , triggers , credentials ) A flag initial_sync present only when the initial replication is still running A number of files to synchronize for the initial sync, initial_number_of_files_to_sync (if there is no file to sync or the initial replication has finished, the field won\u2019t be here) A shortcut_id with the identifier of the shortcut file (when the recipient doesn\u2019t want to synchronize the documents on their Cozy instance) A list of sharing rules , each rule being composed of: a title , that will be displayed to the recipients before they accept the sharing the doctype a selector (by default, it\u2019s the id ) and values (one identifier, a list of identifiers, files and folders inside a folder, files that are referenced by the same document, documents bound to a previous sharing rule) local : by default false , but it can false true for documents that are useful for the preview page but doesn\u2019t need to be send to the recipients (e.g. a setting document of the application) add : What to do when a new document matches this rule (the document is created, or it was a document that didn\u2019t match the rule and is modified and the new version matches the rule). Can be: none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member are propagated to the other members update : What to do when a document matched by this rule is modified. Can be: none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member are propagated to the other members remove : What to do when a document no longer matches this rule (the document is deleted, or it was a document that matched the rule, and is modified and the new version doesn\u2019t match the rule): none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member are propagated to the other members revoke : the sharing is revoked. Example \u00b6 { \"_id\" : \"fffe04ebbec335405161f19133a0cd5c\" , \"_rev\" : \"7-bb721ae29e74ff2d776d8cbabf1a0bf5\" , \"triggers\" : { \"track_id\" : \"fffe04ebbec335405161f19133a0fab5\" , \"replicate_id\" : \"fffe04ebbec335405161f19133a1172a\" , \"upload_id\" : \"fffe04ebbec335405161f19133a133bd\" }, \"active\" : true , \"owner\" : true , \"description\" : \"Let's work together!\" , \"app_slug\" : \"\" , \"created_at\" : \"2018-06-01T16:54:32.677789079+02:00\" , \"updated_at\" : \"2018-06-01T16:54:32.677789079+02:00\" , \"rules\" : [ { \"title\" : \"labore_adipisci\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"fffe04ebbec335405161f19133a0b7b1\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ], \"members\" : [ { \"status\" : \"owner\" , \"name\" : \"Alice\" , \"email\" : \"alice+test@cozy.tools\" , \"instance\" : \"http://alice.test.cozy.tools:8081\" }, { \"status\" : \"ready\" , \"name\" : \"Benjamin Denis\" , \"email\" : \"denis@borer.org\" , \"instance\" : \"http://bob.test.cozy.tools:8082\" } ], \"credentials\" : [ { \"state\" : \"OyPayIajZQUUX_KsZY2yaQ\" , \"client\" : { \"client_id\" : \"fffe04ebbec335405161f19133a0e286\" , \"client_secret\" : \"JeOuBosC329bnz1rFK3Yenw8_8TleOa2\" , \"client_secret_expires_at\" : 0 , \"registration_access_token\" : \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyZWdpc3RyYXRpb24iLCJpYXQiOjE1Mjc4NjQ4ODQsImlzcyI6ImJvYi50ZXN0LmNvenkudG9vbHM6ODA4MiIsInN1YiI6ImZmZmUwNGViYmVjMzM1NDA1MTYxZjE5MTMzYTBlMjg2In0.WsNnnFnnf_vgf2OQyGSaj9XyK2elkaGHyl2vFpjzlCxEfj7ZoE7B2b6_GtRIdmhh42VSawoyGLAXsPh-ml10GQ\" , \"redirect_uris\" : [ \"http://alice.test.cozy.tools:8081/sharings/answer\" ], \"client_name\" : \"Sharing Alice\" , \"client_kind\" : \"sharing\" , \"client_uri\" : \"http://alice.test.cozy.tools:8081/\" , \"software_id\" : \"github.com/cozy/cozy-stack\" }, \"access_token\" : { \"token_type\" : \"bearer\" , \"access_token\" : \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhY2Nlc3MiLCJpYXQiOjE1Mjc4NjQ4ODQsImlzcyI6ImJvYi50ZXN0LmNvenkudG9vbHM6ODA4MiIsInN1YiI6ImZmZmUwNGViYmVjMzM1NDA1MTYxZjE5MTMzYTBlMjg2Iiwic2NvcGUiOiJpby5jb3p5LnNoYXJpbmdzOkFMTDpmZmZlMDRlYmJlYzMzNTQwNTE2MWYxOTEzM2EwY2Q1YyJ9.ZS0r9KpjrctckigRIELJQryzHrFGo-1dQvRplSNj8N0jyJE1LPgnYuiDedQ8EQN5-1ffeLUf3h_Rygz2ozQvPA\" , \"refresh_token\" : \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyZWZyZXNoIiwiaWF0IjoxNTI3ODY0ODg0LCJpc3MiOiJib2IudGVzdC5jb3p5LnRvb2xzOjgwODIiLCJzdWIiOiJmZmZlMDRlYmJlYzMzNTQwNTE2MWYxOTEzM2EwZTI4NiIsInNjb3BlIjoiaW8uY296eS5zaGFyaW5nczpBTEw6ZmZmZTA0ZWJiZWMzMzU0MDUxNjFmMTkxMzNhMGNkNWMifQ.cnH-COVwBIY8zOK51BBkLhb8vRbA96mRJ_W-i3Gg_qZoAISUjmzM3IH69DPQzD99OFnyeGWPhuIkCyWZX7ULQA\" , \"scope\" : \"io.cozy.sharings:ALL:fffe04ebbec335405161f19133a0cd5c\" }, \"xor_key\" : \"CAMHBgkAAgEMCAkMAgsIAw==\" , \"inbound_client_id\" : \"fffe04ebbec335405161f19133a0ecc2\" } ] } io.cozy.shared \u00b6 This doctype is an internal one for the stack. It is used to track what documents are shared, and to replicate changes from one Cozy to the others. _id : its identifier is the doctype and id of the referenced objet, separated by a / (e.g. io.cozy.contacts/c1f5dae4-0d87-11e8-b91b-1f41c005768b ) _rev : the CouchDB default revision for this document (not very meaningful, it\u2019s here to avoid concurrency issues) revisions : a tree with the last known _rev s of the referenced object infos , a map of sharing ids \u2192 {rule, removed, binary} rule says which rule from the sharing must be applied for this document removed will be true for a deleted document, a trashed file, or if the document does no longer match the sharing rule binary is a boolean flag that is true only for files (and not even folders) with removed: false Example \u00b6 { \"_id\" : \"io.cozy.files/becbd072f742f5444f5d7837b2f4e323\" , \"_rev\" : \"1-af3192a67f2bf69e011aa1bda39e6c72\" , \"revisions\" : { \"rev\" : \"4-4135d4994981c0041e3c89a681542307\" }, \"infos\" : { \"fffe04ebbec335405161f19133a0cd5c\" : { \"rule\" : 0 , \"binary\" : true } } }", "title": "Sharings"}, {"location": "cozy-doctypes/docs/io.cozy.sharings/#iocozysharings", "text": "This doctype describes a sharing, ie an action made by some user to share some documents and files from her cozy instance to other people. An identifier (the same for all members of the sharing) A list of members . The first one is the owner. For each member, we have the URL of the cozy, a public name, an email, a status and some credentials to authorize the transfer of data between the owner and the recipients. The status can be: owner for the member that has created the sharing mail-not-sent for a member that has been added, but its invitation has not yet been sent (often, this status is used only for a few seconds) pending for a member with an invitation sent, but who has not clicked on the link seen for a member that has clicked on the invitation link, but has not setup the Cozy to Cozy replication for the sharing ready for a member where the Cozy to Cozy replication has been set up revoked for a member who is on longer in the sharing A list of groups , with for each one: id , the identifier of the io.cozy.contacts.groups name , the name of the group addedBy , the index of the member that has added the group read_only , a flag to tell if the group is restricted to read-only mode revoked , a flag set to true when the group is revoked from the sharing A description (one sentence that will help people understand what is shared and why) a flag active that says if the sharing is currently active for at least one member a flag owner , true for the document on the cozy of the sharer, and absent on the other cozy instance a flag open_sharing : true if any member of the sharing can add a new recipient false if only the owner can add a new recipient Some technical data ( created_at , updated_at , app_slug , preview_path , triggers , credentials ) A flag initial_sync present only when the initial replication is still running A number of files to synchronize for the initial sync, initial_number_of_files_to_sync (if there is no file to sync or the initial replication has finished, the field won\u2019t be here) A shortcut_id with the identifier of the shortcut file (when the recipient doesn\u2019t want to synchronize the documents on their Cozy instance) A list of sharing rules , each rule being composed of: a title , that will be displayed to the recipients before they accept the sharing the doctype a selector (by default, it\u2019s the id ) and values (one identifier, a list of identifiers, files and folders inside a folder, files that are referenced by the same document, documents bound to a previous sharing rule) local : by default false , but it can false true for documents that are useful for the preview page but doesn\u2019t need to be send to the recipients (e.g. a setting document of the application) add : What to do when a new document matches this rule (the document is created, or it was a document that didn\u2019t match the rule and is modified and the new version matches the rule). Can be: none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member are propagated to the other members update : What to do when a document matched by this rule is modified. Can be: none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member are propagated to the other members remove : What to do when a document no longer matches this rule (the document is deleted, or it was a document that matched the rule, and is modified and the new version doesn\u2019t match the rule): none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member are propagated to the other members revoke : the sharing is revoked.", "title": "io.cozy.sharings"}, {"location": "cozy-doctypes/docs/io.cozy.sharings/#example", "text": "{ \"_id\" : \"fffe04ebbec335405161f19133a0cd5c\" , \"_rev\" : \"7-bb721ae29e74ff2d776d8cbabf1a0bf5\" , \"triggers\" : { \"track_id\" : \"fffe04ebbec335405161f19133a0fab5\" , \"replicate_id\" : \"fffe04ebbec335405161f19133a1172a\" , \"upload_id\" : \"fffe04ebbec335405161f19133a133bd\" }, \"active\" : true , \"owner\" : true , \"description\" : \"Let's work together!\" , \"app_slug\" : \"\" , \"created_at\" : \"2018-06-01T16:54:32.677789079+02:00\" , \"updated_at\" : \"2018-06-01T16:54:32.677789079+02:00\" , \"rules\" : [ { \"title\" : \"labore_adipisci\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"fffe04ebbec335405161f19133a0b7b1\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ], \"members\" : [ { \"status\" : \"owner\" , \"name\" : \"Alice\" , \"email\" : \"alice+test@cozy.tools\" , \"instance\" : \"http://alice.test.cozy.tools:8081\" }, { \"status\" : \"ready\" , \"name\" : \"Benjamin Denis\" , \"email\" : \"denis@borer.org\" , \"instance\" : \"http://bob.test.cozy.tools:8082\" } ], \"credentials\" : [ { \"state\" : \"OyPayIajZQUUX_KsZY2yaQ\" , \"client\" : { \"client_id\" : \"fffe04ebbec335405161f19133a0e286\" , \"client_secret\" : \"JeOuBosC329bnz1rFK3Yenw8_8TleOa2\" , \"client_secret_expires_at\" : 0 , \"registration_access_token\" : \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyZWdpc3RyYXRpb24iLCJpYXQiOjE1Mjc4NjQ4ODQsImlzcyI6ImJvYi50ZXN0LmNvenkudG9vbHM6ODA4MiIsInN1YiI6ImZmZmUwNGViYmVjMzM1NDA1MTYxZjE5MTMzYTBlMjg2In0.WsNnnFnnf_vgf2OQyGSaj9XyK2elkaGHyl2vFpjzlCxEfj7ZoE7B2b6_GtRIdmhh42VSawoyGLAXsPh-ml10GQ\" , \"redirect_uris\" : [ \"http://alice.test.cozy.tools:8081/sharings/answer\" ], \"client_name\" : \"Sharing Alice\" , \"client_kind\" : \"sharing\" , \"client_uri\" : \"http://alice.test.cozy.tools:8081/\" , \"software_id\" : \"github.com/cozy/cozy-stack\" }, \"access_token\" : { \"token_type\" : \"bearer\" , \"access_token\" : \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhY2Nlc3MiLCJpYXQiOjE1Mjc4NjQ4ODQsImlzcyI6ImJvYi50ZXN0LmNvenkudG9vbHM6ODA4MiIsInN1YiI6ImZmZmUwNGViYmVjMzM1NDA1MTYxZjE5MTMzYTBlMjg2Iiwic2NvcGUiOiJpby5jb3p5LnNoYXJpbmdzOkFMTDpmZmZlMDRlYmJlYzMzNTQwNTE2MWYxOTEzM2EwY2Q1YyJ9.ZS0r9KpjrctckigRIELJQryzHrFGo-1dQvRplSNj8N0jyJE1LPgnYuiDedQ8EQN5-1ffeLUf3h_Rygz2ozQvPA\" , \"refresh_token\" : \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyZWZyZXNoIiwiaWF0IjoxNTI3ODY0ODg0LCJpc3MiOiJib2IudGVzdC5jb3p5LnRvb2xzOjgwODIiLCJzdWIiOiJmZmZlMDRlYmJlYzMzNTQwNTE2MWYxOTEzM2EwZTI4NiIsInNjb3BlIjoiaW8uY296eS5zaGFyaW5nczpBTEw6ZmZmZTA0ZWJiZWMzMzU0MDUxNjFmMTkxMzNhMGNkNWMifQ.cnH-COVwBIY8zOK51BBkLhb8vRbA96mRJ_W-i3Gg_qZoAISUjmzM3IH69DPQzD99OFnyeGWPhuIkCyWZX7ULQA\" , \"scope\" : \"io.cozy.sharings:ALL:fffe04ebbec335405161f19133a0cd5c\" }, \"xor_key\" : \"CAMHBgkAAgEMCAkMAgsIAw==\" , \"inbound_client_id\" : \"fffe04ebbec335405161f19133a0ecc2\" } ] }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.sharings/#iocozyshared", "text": "This doctype is an internal one for the stack. It is used to track what documents are shared, and to replicate changes from one Cozy to the others. _id : its identifier is the doctype and id of the referenced objet, separated by a / (e.g. io.cozy.contacts/c1f5dae4-0d87-11e8-b91b-1f41c005768b ) _rev : the CouchDB default revision for this document (not very meaningful, it\u2019s here to avoid concurrency issues) revisions : a tree with the last known _rev s of the referenced object infos , a map of sharing ids \u2192 {rule, removed, binary} rule says which rule from the sharing must be applied for this document removed will be true for a deleted document, a trashed file, or if the document does no longer match the sharing rule binary is a boolean flag that is true only for files (and not even folders) with removed: false", "title": "io.cozy.shared"}, {"location": "cozy-doctypes/docs/io.cozy.sharings/#example_1", "text": "{ \"_id\" : \"io.cozy.files/becbd072f742f5444f5d7837b2f4e323\" , \"_rev\" : \"1-af3192a67f2bf69e011aa1bda39e6c72\" , \"revisions\" : { \"rev\" : \"4-4135d4994981c0041e3c89a681542307\" }, \"infos\" : { \"fffe04ebbec335405161f19133a0cd5c\" : { \"rule\" : 0 , \"binary\" : true } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.tags/", "text": "Table of contents Cozy Tags doctype \u00b6 io.cozy.tags \u00b6 The io.cozy.tags doctype is used to represent tags. A tag is used to add information to a document. Any document from another doctype can use a tag. label : {string} the label of the tag.", "title": "Tags"}, {"location": "cozy-doctypes/docs/io.cozy.tags/#cozy-tags-doctype", "text": "", "title": "Cozy Tags doctype"}, {"location": "cozy-doctypes/docs/io.cozy.tags/#iocozytags", "text": "The io.cozy.tags doctype is used to represent tags. A tag is used to add information to a document. Any document from another doctype can use a tag. label : {string} the label of the tag.", "title": "io.cozy.tags"}, {"location": "cozy-doctypes/docs/io.cozy.terms/", "text": "Table of contents Cozy Terms doctype \u00b6 io.cozy.terms \u00b6 The io.cozy.terms doctype can be used to store some (application related or not) terms seen by the user inside the Cozy. A terms must be unique if this is the same id and the same version (the url can changed), if the id or the version changes, a new document must be created. accepted : (Boolean) The fact that the terms has been accepted by the Cozy user or not acceptedAt : (Date) The date when the Cozy user accepted these terms termsId : the id of the terms url : The url of the terms (to redirect the Cozy user to if needed) version : The version of these terms", "title": "Terms"}, {"location": "cozy-doctypes/docs/io.cozy.terms/#cozy-terms-doctype", "text": "", "title": "Cozy Terms doctype"}, {"location": "cozy-doctypes/docs/io.cozy.terms/#iocozyterms", "text": "The io.cozy.terms doctype can be used to store some (application related or not) terms seen by the user inside the Cozy. A terms must be unique if this is the same id and the same version (the url can changed), if the id or the version changes, a new document must be created. accepted : (Boolean) The fact that the terms has been accepted by the Cozy user or not acceptedAt : (Date) The date when the Cozy user accepted these terms termsId : the id of the terms url : The url of the terms (to redirect the Cozy user to if needed) version : The version of these terms", "title": "io.cozy.terms"}, {"location": "cozy-doctypes/docs/io.cozy.timeseries/", "text": "Table of contents Cozy Time Series doctype \u00b6 io.cozy.timeseries.* \u00b6 The io.cozy.timeseries.* doctype is used to represent time series. The type of the time series is specified in the last part of the doctype, e.g. io.cozy.timeseries.geojson . Any type of time series must follow the same common structure: startDate : {date} the starting date of the time series. endDate : {date} the ending date of the time series. title : {string} the title of the time serie. source : {string} the data source, e.g. \u201cstrava.com\u201d. theme : {string} a theme is used to group several types of time series into a common theme, e.g. \u201cactivity\u201d. series : {Array} the actual time series. The array contains objects and the format of each object depends on the data type of the time series. io.cozy.timeseries.geojson \u00b6 These time series follow the GeoJSON format. See here for a complete example of this doctype. Example \u00b6 { \"startDate\" : \"2021-02-17T17:37:17\" , \"endDate\" : \"2021-02-17T17:54:50\" , \"source\" : \"my-trips.com\" , \"theme\" : \"timeline\" , \"series\" : [ { \"type\" : \"Feature\" , \"geometry\" : { \"type\" : \"Point\" , \"coordinates\" : [ 48.85 , 2.29 ] }, \"properties\" : { \"name\" : \"Eiffel Tower\" } } ] }", "title": "Time series"}, {"location": "cozy-doctypes/docs/io.cozy.timeseries/#cozy-time-series-doctype", "text": "", "title": "Cozy Time Series doctype"}, {"location": "cozy-doctypes/docs/io.cozy.timeseries/#iocozytimeseries", "text": "The io.cozy.timeseries.* doctype is used to represent time series. The type of the time series is specified in the last part of the doctype, e.g. io.cozy.timeseries.geojson . Any type of time series must follow the same common structure: startDate : {date} the starting date of the time series. endDate : {date} the ending date of the time series. title : {string} the title of the time serie. source : {string} the data source, e.g. \u201cstrava.com\u201d. theme : {string} a theme is used to group several types of time series into a common theme, e.g. \u201cactivity\u201d. series : {Array} the actual time series. The array contains objects and the format of each object depends on the data type of the time series.", "title": "io.cozy.timeseries.*"}, {"location": "cozy-doctypes/docs/io.cozy.timeseries/#iocozytimeseriesgeojson", "text": "These time series follow the GeoJSON format. See here for a complete example of this doctype.", "title": "io.cozy.timeseries.geojson"}, {"location": "cozy-doctypes/docs/io.cozy.timeseries/#example", "text": "{ \"startDate\" : \"2021-02-17T17:37:17\" , \"endDate\" : \"2021-02-17T17:54:50\" , \"source\" : \"my-trips.com\" , \"theme\" : \"timeline\" , \"series\" : [ { \"type\" : \"Feature\" , \"geometry\" : { \"type\" : \"Point\" , \"coordinates\" : [ 48.85 , 2.29 ] }, \"properties\" : { \"name\" : \"Eiffel Tower\" } } ] }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.todos/", "text": "Table of contents Cozy Todos doctypes \u00b6 io.cozy.todos.list \u00b6 This doctype represents a todo list: title : {string} - The list title description : {string} - The list description limitDate : {date} - The limit date to complete all the items. Relationships \u00b6 items : {object} - The list items Example \u00b6 { \"_id\" : \"2165d9a310deadbeeffc08d54c45102\" , \"title\" : \"Create a loan file\" , \"description\" : \"Loan money to buy a house.\" , \"limitDate\" : \"2020-02-01T23:59:59Z\" , \"relationships\" : { \"items\" : { \"data\" : [ { \"_id\" : \"8bffbc24e67716b63e08c71bd0059fea\" , \"_type\" : \"io.cozy.todos.item\" }, { \"_id\" : \"68a74e03722f02b1a6fc6a4508015de0\" , \"_type\" : \"io.cozy.todos.item\" } ] } } } io.cozy.todos.item \u00b6 This doctype represents a todo item: label : {string} - The label of the todo item, e.g. \u201cDo stuff\u201d. description : {string} - A description of the item. done : {bool} - Whether the item is done or not. limitDate : {date} - The limit date to complete this item. completionDate : {date} - The actual completion date of the item. Relationships \u00b6 files : {object} - Files linked to the todo item. contacts : {object} - Contacts linked to the todo item. docrules : {object} - The rules used to match documents from other relationships, e.g. a rule used to match specific files, such as payslips. See below or in the docrules doctype for more details. DocRules \u00b6 When a document has been linked to a todo through the use of a rule, the rule that was used to find the document is saved in the metadata of the relationship. metadata : {object} docrules : {object} matchedBy : {string} : The rule ID {...} : additional fields used as rule parameters, e.g. limit , date , etc. In the example below, a docrule is targeting the last 3 files payslips from a given date. Example \u00b6 { \"_id\" : \"8bffbc24e67716b63e08c71bd0059fea\" , \"label\" : \"Get the last 3 payslips\" , \"description\" : \"This is required to prove the income\" , \"done\" : false , \"limitDate\" : \"2020-01-31T23:59:59Z\" , \"completionDate\" : null , \"relationships\" : { \"files\" : { \"data\" : [ { \"_id\" : \"8bffbc24e67716b63e08c71bd0059fea\" , \"_type\" : \"io.cozy.files\" , \"metadata\" : { \"docrules\" : { \"matchedBy\" : \"io.cozy.docrules/payslip\" , \"date\" : \"2020-01-01T23:59:59Z\" , \"limit\" : 3 } } }, { \"_id\" : \"8bffbc24e67716b63e08c71bd0068f52\" , \"_type\" : \"io.cozy.files\" , \"metadata\" : { \"docrules\" : { \"matchedBy\" : \"io.cozy.docrules/payslip\" , \"date\" : \"2020-01-01T23:59:59Z\" , \"limit\" : 3 } } } ] }, \"contacts\" : { \"data\" : [ { \"_id\" : \"d5fb210882d78ab30dd991fb021ae450\" , \"_type\" : \"io.cozy.contacts\" } ] }, \"docrules\" : { \"data\" : [ { \"_id\" : \"io.cozy.docrules/payslips\" , \"_type\" : \"io.cozy.docrules\" } ] } } }", "title": "Todos"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#cozy-todos-doctypes", "text": "", "title": "Cozy Todos doctypes"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#iocozytodoslist", "text": "This doctype represents a todo list: title : {string} - The list title description : {string} - The list description limitDate : {date} - The limit date to complete all the items.", "title": "io.cozy.todos.list"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#relationships", "text": "items : {object} - The list items", "title": "Relationships"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#example", "text": "{ \"_id\" : \"2165d9a310deadbeeffc08d54c45102\" , \"title\" : \"Create a loan file\" , \"description\" : \"Loan money to buy a house.\" , \"limitDate\" : \"2020-02-01T23:59:59Z\" , \"relationships\" : { \"items\" : { \"data\" : [ { \"_id\" : \"8bffbc24e67716b63e08c71bd0059fea\" , \"_type\" : \"io.cozy.todos.item\" }, { \"_id\" : \"68a74e03722f02b1a6fc6a4508015de0\" , \"_type\" : \"io.cozy.todos.item\" } ] } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#iocozytodositem", "text": "This doctype represents a todo item: label : {string} - The label of the todo item, e.g. \u201cDo stuff\u201d. description : {string} - A description of the item. done : {bool} - Whether the item is done or not. limitDate : {date} - The limit date to complete this item. completionDate : {date} - The actual completion date of the item.", "title": "io.cozy.todos.item"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#relationships_1", "text": "files : {object} - Files linked to the todo item. contacts : {object} - Contacts linked to the todo item. docrules : {object} - The rules used to match documents from other relationships, e.g. a rule used to match specific files, such as payslips. See below or in the docrules doctype for more details.", "title": "Relationships"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#docrules", "text": "When a document has been linked to a todo through the use of a rule, the rule that was used to find the document is saved in the metadata of the relationship. metadata : {object} docrules : {object} matchedBy : {string} : The rule ID {...} : additional fields used as rule parameters, e.g. limit , date , etc. In the example below, a docrule is targeting the last 3 files payslips from a given date.", "title": "DocRules"}, {"location": "cozy-doctypes/docs/io.cozy.todos/#example_1", "text": "{ \"_id\" : \"8bffbc24e67716b63e08c71bd0059fea\" , \"label\" : \"Get the last 3 payslips\" , \"description\" : \"This is required to prove the income\" , \"done\" : false , \"limitDate\" : \"2020-01-31T23:59:59Z\" , \"completionDate\" : null , \"relationships\" : { \"files\" : { \"data\" : [ { \"_id\" : \"8bffbc24e67716b63e08c71bd0059fea\" , \"_type\" : \"io.cozy.files\" , \"metadata\" : { \"docrules\" : { \"matchedBy\" : \"io.cozy.docrules/payslip\" , \"date\" : \"2020-01-01T23:59:59Z\" , \"limit\" : 3 } } }, { \"_id\" : \"8bffbc24e67716b63e08c71bd0068f52\" , \"_type\" : \"io.cozy.files\" , \"metadata\" : { \"docrules\" : { \"matchedBy\" : \"io.cozy.docrules/payslip\" , \"date\" : \"2020-01-01T23:59:59Z\" , \"limit\" : 3 } } } ] }, \"contacts\" : { \"data\" : [ { \"_id\" : \"d5fb210882d78ab30dd991fb021ae450\" , \"_type\" : \"io.cozy.contacts\" } ] }, \"docrules\" : { \"data\" : [ { \"_id\" : \"io.cozy.docrules/payslips\" , \"_type\" : \"io.cozy.docrules\" } ] } } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.triggers/", "text": "Table of contents Triggers doctype \u00b6 io.cozy.triggers documents are used by the stack to configure how and when a job should be runned . This is a special doctype which can only be created from an app. We are using it in Cozy-Home to manage konnectors scheduling. Attributes \u00b6 Attribute Role arguments Arguments related to the type attribute. For example it\u2019s a cron configuration when the type is set to @cron . debounce The debounce parameter can be used to limit the number of jobs created in a burst. It delays the creation of the job on the first input by the given time argument, and if the trigger has its condition matched again during this period, it won\u2019t create another job. Its syntax is the one understood by go\u2019s time.ParseDuration message Parameters to pass to the the worker. For example, when the worker is set to konnector , message contains the related konnector and the related account. options Parameters related to the job. type Type of trigger. Can be @at , @cron , @event , @every , @in and @webhook . See the stack documentation for more informations. worker Type of worker. Can be konnector or sendmail . Example \u00b6 Trigger configured to run the konnector Debug with the io.cozy.accounts document having the id 53fe4d0e4f6d3be99ba7a5d2580081a8 . { \"type\" : \"@cron\" , \"worker\" : \"konnector\" , \"arguments\" : \"0 45 4 * * 3\" , \"debounce\" : \"\" , \"options\" : null , \"message\" : { \"konnector\" : \"debug\" , \"account\" : \"53fe4d0e4f6d3be99ba7a5d2580081a8\" } }", "title": "Triggers"}, {"location": "cozy-doctypes/docs/io.cozy.triggers/#triggers-doctype", "text": "io.cozy.triggers documents are used by the stack to configure how and when a job should be runned . This is a special doctype which can only be created from an app. We are using it in Cozy-Home to manage konnectors scheduling.", "title": "Triggers doctype"}, {"location": "cozy-doctypes/docs/io.cozy.triggers/#attributes", "text": "Attribute Role arguments Arguments related to the type attribute. For example it\u2019s a cron configuration when the type is set to @cron . debounce The debounce parameter can be used to limit the number of jobs created in a burst. It delays the creation of the job on the first input by the given time argument, and if the trigger has its condition matched again during this period, it won\u2019t create another job. Its syntax is the one understood by go\u2019s time.ParseDuration message Parameters to pass to the the worker. For example, when the worker is set to konnector , message contains the related konnector and the related account. options Parameters related to the job. type Type of trigger. Can be @at , @cron , @event , @every , @in and @webhook . See the stack documentation for more informations. worker Type of worker. Can be konnector or sendmail .", "title": "Attributes"}, {"location": "cozy-doctypes/docs/io.cozy.triggers/#example", "text": "Trigger configured to run the konnector Debug with the io.cozy.accounts document having the id 53fe4d0e4f6d3be99ba7a5d2580081a8 . { \"type\" : \"@cron\" , \"worker\" : \"konnector\" , \"arguments\" : \"0 45 4 * * 3\" , \"debounce\" : \"\" , \"options\" : null , \"message\" : { \"konnector\" : \"debug\" , \"account\" : \"53fe4d0e4f6d3be99ba7a5d2580081a8\" } }", "title": "Example"}, {"location": "cozy-doctypes/docs/io.cozy.triggers.state/", "text": "Cozy triggers state doctype io.cozy.triggers.state Cozy triggers state doctype \u00b6 Note: This doctype is only virtual. It is computed each time by agggregating informations about a trigger based on its jobs io.cozy.triggers.state \u00b6 The io.cozy.triggers.state doctype gather the data of a trigger from its jobs status {string}: Global status of the trigger ( queued , running , done , errored ) last_success {timestamp}: Date of the last job in success last_successful_job_id {string}: ID of the last job in success last_execution {timestamp}: Date of the last executed job last_executed_job_id {string}: ID of the last executed job last_failure {timestamp}: Date of the last job in failure last_failed_job_id {string}: ID of the last job in failure last_manual_execution {timestamp}: Date of the last job manually executed last_manual_job_id {string}: ID of the last job manually executed last_error {string}: Content of the last error", "title": "Triggers state"}, {"location": "cozy-doctypes/docs/io.cozy.triggers.state/#cozy-triggers-state-doctype", "text": "Note: This doctype is only virtual. It is computed each time by agggregating informations about a trigger based on its jobs", "title": "Cozy triggers state doctype"}, {"location": "cozy-doctypes/docs/io.cozy.triggers.state/#iocozytriggersstate", "text": "The io.cozy.triggers.state doctype gather the data of a trigger from its jobs status {string}: Global status of the trigger ( queued , running , done , errored ) last_success {timestamp}: Date of the last job in success last_successful_job_id {string}: ID of the last job in success last_execution {timestamp}: Date of the last executed job last_executed_job_id {string}: ID of the last executed job last_failure {timestamp}: Date of the last job in failure last_failed_job_id {string}: ID of the last job in failure last_manual_execution {timestamp}: Date of the last job manually executed last_manual_job_id {string}: ID of the last job manually executed last_error {string}: Content of the last error", "title": "io.cozy.triggers.state"}, {"location": "cozy-flags/", "text": "Flags \u00b6 Use and manage cozy feature flags. Flags can be toggled for a cozy instance, a context or globally. See the stack documentation on flags for more information. \u2705 jQuery like API for getter/setter \u2705 Devtool component to set/unset flags Installation \u00b6 npm install --save cozy-flags # or yarn add cozy-flags A CozyClient plugin is exported that initializes flags on client\u2019s login resets them on client\u2019s logout import flag from 'cozy-flags' client . registerPlugin ( flag . plugin ) \u2139\ufe0f It will fetch server flags for consumption by the app either from DOM data (if data-cozy={{ .CozyData }} or data-flags={{ .Flags }} , on web or by fetching data from the server (on mobile) Usage \u00b6 \u26a0\ufe0f Make sure you have registered the flag plugin before using the flags. import flag from 'cozy-flags' if ( flag ( 'my-feature' )) { enableMyFeature () } The FlagSwitcher shows all flags in use and displays all flags in use. import flag from 'cozy-flags' import FlagSwitcher from 'cozy-flags/dist/FlagSwitcher' if ( process . env . NODE_ENV !== 'production' && flag ( 'switcher' ) === null ) { flag ( 'switcher' , true ) // set default flag in dev mode } const App = () => { return ( < div > { flag ( 'switcher' ) && < FlagSwitcher /> } < MyApp /> ) } Demo \u00b6 The FlagSwitcher component helps toggling the flags. Flags enabled at build time \u00b6 It is possible to handle flags enabled at build time. Your app should just provide a global __ENABLED_FLAGS__ array with flag names that should be enabled. If such a global exists, cozy-flags will iterate on the array and enable all the flags it contains when it is imported.", "title": "Flags"}, {"location": "cozy-flags/#flags", "text": "Use and manage cozy feature flags. Flags can be toggled for a cozy instance, a context or globally. See the stack documentation on flags for more information. \u2705 jQuery like API for getter/setter \u2705 Devtool component to set/unset flags", "title": "Flags"}, {"location": "cozy-flags/#installation", "text": "npm install --save cozy-flags # or yarn add cozy-flags A CozyClient plugin is exported that initializes flags on client\u2019s login resets them on client\u2019s logout import flag from 'cozy-flags' client . registerPlugin ( flag . plugin ) \u2139\ufe0f It will fetch server flags for consumption by the app either from DOM data (if data-cozy={{ .CozyData }} or data-flags={{ .Flags }} , on web or by fetching data from the server (on mobile)", "title": "Installation"}, {"location": "cozy-flags/#usage", "text": "\u26a0\ufe0f Make sure you have registered the flag plugin before using the flags. import flag from 'cozy-flags' if ( flag ( 'my-feature' )) { enableMyFeature () } The FlagSwitcher shows all flags in use and displays all flags in use. import flag from 'cozy-flags' import FlagSwitcher from 'cozy-flags/dist/FlagSwitcher' if ( process . env . NODE_ENV !== 'production' && flag ( 'switcher' ) === null ) { flag ( 'switcher' , true ) // set default flag in dev mode } const App = () => { return ( < div > { flag ( 'switcher' ) && < FlagSwitcher /> } < MyApp /> ) }", "title": "Usage"}, {"location": "cozy-flags/#demo", "text": "The FlagSwitcher component helps toggling the flags.", "title": "Demo"}, {"location": "cozy-flags/#flags-enabled-at-build-time", "text": "It is possible to handle flags enabled at build time. Your app should just provide a global __ENABLED_FLAGS__ array with flag names that should be enabled. If such a global exists, cozy-flags will iterate on the array and enable all the flags it contains when it is imported.", "title": "Flags enabled at build time"}, {"location": "cozy-flags/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 4.0.0 (2024-07-11) \u00b6 Features \u00b6 Add types to flag ( 2539957 ) sharing: Upgrade cozy-ui 105.3.1 to 106.8.0 ( b731089 ) BREAKING CHANGES \u00b6 sharing: you must have cozy-ui >= 106.8.0 3.2.2 (2024-01-05) \u00b6 Bug Fixes \u00b6 Fix types of CozyClient on cozy-flags ( add0637 ) 3.2.1 (2024-01-05) \u00b6 Note: Version bump only for package cozy-flags 3.2.0 (2023-12-20) \u00b6 Bug Fixes \u00b6 cozy-flags: Add declaration dir in options ( faa5b5c ) Features \u00b6 mespapiers: Replace spinner by skeletons on papers list ( 2303501 ) 3.1.0 (2023-10-31) \u00b6 Features \u00b6 cozy-flags: Output types in dist ( cd5e2b0 ) 3.0.1 (2023-04-13) \u00b6 Bug Fixes \u00b6 Cozy-Flags lint issues ( ee26c09 ) 3.0.0 (2023-04-05) \u00b6 Bug Fixes \u00b6 Use io.cozy.settings.flags and io.cozy.settings.context id ( c27806f ) Features \u00b6 mespapiers: Update cozy-ui from 82.4.0 to 82.5.1 ( d016608 ) BREAKING CHANGES \u00b6 mespapiers: you must have cozy-ui >= 82.5.1 2.12.0 (2023-03-21) \u00b6 Features \u00b6 flag: Find value from parameter with nested part into JSON content ( 7836d84 ) 2.11.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 2.10.2 (2022-10-03) \u00b6 Note: Version bump only for package cozy-flags 2.10.1 (2022-08-01) \u00b6 Note: Version bump only for package cozy-flags 2.10.0 (2022-07-05) \u00b6 Features \u00b6 All oauth methods to handle reconection case ( b1a6033 ) flags: Upgrade devDep cozy-client ( 8870271 ) 2.9.0 (2022-06-03) \u00b6 Bug Fixes \u00b6 bump jest-localstorage-mock from 2.4.19 to 2.4.21 ( 9792e2e ) Features \u00b6 harvest: HandleOAuthResponse can deal with cozy-data from DOM ( 7c6ac1a ) 2.8.7 (2022-03-21) \u00b6 Bug Fixes \u00b6 deps: update dependency jest-localstorage-mock to v2.4.19 ( 361279c ) 2.8.6 (2022-03-01) \u00b6 Bug Fixes \u00b6 flags: Don\u2019t log when flags.enable called with empty array ( 96ea387 ) 2.8.5 (2022-02-18) \u00b6 Bug Fixes \u00b6 deps: pin dependencies ( e53d065 ) 2.8.4 (2022-02-01) \u00b6 Bug Fixes \u00b6 deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 ) 2.8.3 (2021-12-20) \u00b6 Note: Version bump only for package cozy-flags 2.8.2 (2021-12-02) \u00b6 Note: Version bump only for package cozy-flags 2.8.1 (2021-11-24) \u00b6 Bug Fixes \u00b6 Informations on readme ( ea517de ) 2.8.0 (2021-10-22) \u00b6 Features \u00b6 Remove drive from homeHref ( 97010d3 ) 2.7.2 (2021-05-12) \u00b6 Bug Fixes \u00b6 Revert change on removal of browser ( cd77604 ) 2.7.1 (2021-04-21) \u00b6 Bug Fixes \u00b6 Don\u2019t import Q from cozy-client ( 0be2442 ) Flags should install cozy-client ( b1ca8e6 ) 2.7.0 (2021-04-09) \u00b6 Features \u00b6 Use animated SVG ( a0856a5 ) 2.6.0 (2021-03-08) \u00b6 Bug Fixes \u00b6 Import in FlagSwitcher ( 5ccc780 ) Remove useless block for node ( fb15094 ) Features \u00b6 Use import/export to benefit from tree shaking ( 1a72770 ) 2.5.4 (2021-03-05) \u00b6 Bug Fixes \u00b6 Don\u2019t require react in a node context ( bba9d41 ) 2.5.3 (2021-02-12) \u00b6 Note: Version bump only for package cozy-flags 2.5.2 (2021-02-11) \u00b6 Bug Fixes \u00b6 Do not use deprecated client.get ( 078369e ) 2.5.1 (2021-02-02) \u00b6 Note: Version bump only for package cozy-flags 2.5.0 (2020-11-23) \u00b6 Features \u00b6 All babel cli at 7.12.1 ( 387a24a ) 2.4.1 (2020-10-16) \u00b6 Note: Version bump only for package cozy-flags 2.4.0 (2020-10-01) \u00b6 Features \u00b6 Add refresh method on plugin ( f9fb8ef ) 2.3.5 (2020-10-01) \u00b6 Note: Version bump only for package cozy-flags 2.3.4 (2020-09-15) \u00b6 Note: Version bump only for package cozy-flags 2.3.3 (2020-08-03) \u00b6 Note: Version bump only for package cozy-flags 2.3.2 (2020-07-16) \u00b6 Note: Version bump only for package cozy-flags 2.3.1 (2020-07-08) \u00b6 Bug Fixes \u00b6 Make sure the initializing promise is reset on logout ( 673029b ) 2.3.0 (2020-07-08) \u00b6 Features \u00b6 Emit events when plugins are ready ( 5fc182c ) 2.2.5 (2020-06-09) \u00b6 Bug Fixes \u00b6 Remove initialization of flag did not work ( d743e09 ) 2.2.4 (2020-02-27) \u00b6 Note: Version bump only for package cozy-flags 2.2.3 (2020-02-25) \u00b6 Note: Version bump only for package cozy-flags 2.2.2 (2020-02-24) \u00b6 Bug Fixes \u00b6 Init flags when client is already logged in ( ff4d3ed ) 2.2.1 (2020-02-24) \u00b6 Bug Fixes \u00b6 Load flags from legacy DOM ( #968 ) ( 6f54cc7 ) 2.2.0 (2020-02-06) \u00b6 Bug Fixes \u00b6 Use useEffect to clean up event handlers on unmount ( 3cdf5be ) Features \u00b6 Add CozyClient plugin for automatic flag initialisation ( 0959c8b ) Deprecate flags.enable with an array ( 85000f5 ) Expose only 1 method to initialize flags ( f5a65ec ) Initialize flags from DOM ( d822f68 ) Initialize from remote endpoint ( 1383590 ) Use data-cozy-flags attribute instead of data-flags ( 4254a8b ) 2.1.0 (2020-01-24) \u00b6 Features \u00b6 Add notes folder ( 94fa863 ) Adds a useFlag react hook ( 4c3df09 ) 2.0.0 (2019-12-09) \u00b6 Features \u00b6 Use conventional display name for HOC ( 350e3c3 ) BREAKING CHANGES \u00b6 Components wrapped in withFlags HOC now have a different displayName , that is more in coherence with other HOC in our codebase. This will require a snapshots update. Ex: flag_WrappedComponent becomes withFlags(WrappedComponent) 1.11.0 (2019-11-04) \u00b6 Bug Fixes \u00b6 Add account link ( 9745b34 ) Features \u00b6 Sort flags ( b60e44c ) 1.10.0 (2019-09-05) \u00b6 Features \u00b6 Add account route ( 7986708 ) 1.9.3 (2019-07-19) \u00b6 Note: Version bump only for package cozy-flags 1.9.2 (2019-07-19) \u00b6 Note: Version bump only for package cozy-flags 1.9.1 (2019-07-11) \u00b6 Note: Version bump only for package cozy-flags 1.9.0 (2019-07-04) \u00b6 Bug Fixes \u00b6 Do not remove import with no specifiers (side-effect imports) ( 4d0ad6c ) Topbar back button ( 100ffb9 ) Features \u00b6 Count JSX as React identifier ( f573490 ) 1.8.0 (2019-06-10) \u00b6 Features \u00b6 Add codemod for flags accessible via \u201ccozy-flags apply\u201d ( 9327f24 ) Remove unused imports after removing flags ( af43da1 ) 1.7.0 (2019-05-23) \u00b6 Features \u00b6 Flag automatically backs up to localStorage if present ( 24bcd04 ) 1.6.1 (2019-05-03) \u00b6 Bug Fixes \u00b6 Expose FlagSwitcher only in browser context ( f2fafa7 ), closes #402 Fix cozy-mjml with nsjail ( #392 ) ( 300a4e6 ) 1.6.0 (2019-03-29) \u00b6 Features \u00b6 Flag hoc to connect to store ( 98130a9 ) Store flags in an object to avoid querying localStorage ( 1f46ad1 ) 1.5.9 (2019-03-18) \u00b6 Note: Version bump only for package cozy-flags 1.5.8 (2019-03-12) \u00b6 Note: Version bump only for package cozy-flags 1.5.7 (2019-03-12) \u00b6 Note: Version bump only for package cozy-flags 1.5.6 (2019-03-12) \u00b6 Note: Version bump only for package cozy-flags 1.5.5 (2019-02-12) \u00b6 Note: Version bump only for package cozy-flags 1.5.4 (2019-02-11) \u00b6 Note: Version bump only for package cozy-flags 1.5.3 (2019-01-30) \u00b6 Note: Version bump only for package cozy-flags 1.5.2 (2019-01-29) \u00b6 Note: Version bump only for package cozy-flags 1.5.1 (2019-01-11) \u00b6 Note: Version bump only for package cozy-flags 1.5.0 (2019-01-04) \u00b6 Bug Fixes \u00b6 flags: Handle case where ENABLED_FLAGS is undefined properly ( c771ff8 ) Features \u00b6 flags: Export enableFlags under flag namespace ( 56a136f ) 1.4.0 (2019-01-03) \u00b6 Features \u00b6 flags: Handle flags enabled at build time ( 87de30a ) 1.3.7 (2018-12-28) \u00b6 Note: Version bump only for package cozy-flags 1.3.6 (2018-12-26) \u00b6 Note: Version bump only for package cozy-flags 1.3.5 (2018-12-17) \u00b6 Note: Version bump only for package cozy-flags 1.3.4 (2018-12-11) \u00b6 Bug Fixes \u00b6 flags: Use detect-node dep ( 8bdf522 ) 1.3.3 (2018-12-10) \u00b6 Note: Version bump only for package cozy-flags 1.3.2 (2018-12-10) \u00b6 Bug Fixes \u00b6 flags: Node and browser detection ( 0b3c4d7 ) 1.3.1 (2018-12-06) \u00b6 Bug Fixes \u00b6 flags: Add default property to require ( 94a4465 ) 1.3.0 (2018-12-06) \u00b6 Features \u00b6 flags: Add node implementation ( a2aeb6c ) 1.2.12 (2018-12-06) \u00b6 Note: Version bump only for package cozy-flags 1.2.11 (2018-10-30) \u00b6 Bug Fixes \u00b6 Update homepage link ( 728a850 ) 1.2.10 (2018-10-02) \u00b6 Note: Version bump only for package cozy-flags 1.2.9 (2018-09-25) \u00b6 Note: Version bump only for package cozy-flags 1.2.8 (2018-09-25) \u00b6 Note: Version bump only for package cozy-flags 1.2.7 (2018-09-24) \u00b6 Note: Version bump only for package cozy-flags 1.2.6 (2018-09-21) \u00b6 Note: Version bump only for package cozy-flags 1.2.5 (2018-09-11) \u00b6 Bug Fixes \u00b6 flags: Return null if flag doesn\u2019t exist ( 54096a7 ) 1.2.4 (2018-08-30) \u00b6 Note: Version bump only for package cozy-flags 1.2.3 (2018-08-22) \u00b6 Note: Version bump only for package cozy-flags 1.2.2 (2018-08-09) \u00b6 Note: Version bump only for package cozy-flags 1.2.1 (2018-08-08) \u00b6 Note: Version bump only for package cozy-flags 1.2.0 (2018-08-08) \u00b6 Bug Fixes \u00b6 remove unused dependency \ud83d\udd25 ( 5fd7f1e ) Features \u00b6 add flags library \ud83d\ude0e ( d42220b )", "title": "Change Log"}, {"location": "cozy-flags/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "cozy-flags/CHANGELOG/#400-2024-07-11", "text": "", "title": "4.0.0 (2024-07-11)"}, {"location": "cozy-flags/CHANGELOG/#features", "text": "Add types to flag ( 2539957 ) sharing: Upgrade cozy-ui 105.3.1 to 106.8.0 ( b731089 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#breaking-changes", "text": "sharing: you must have cozy-ui >= 106.8.0", "title": "BREAKING CHANGES"}, {"location": "cozy-flags/CHANGELOG/#322-2024-01-05", "text": "", "title": "3.2.2 (2024-01-05)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes", "text": "Fix types of CozyClient on cozy-flags ( add0637 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#321-2024-01-05", "text": "Note: Version bump only for package cozy-flags", "title": "3.2.1 (2024-01-05)"}, {"location": "cozy-flags/CHANGELOG/#320-2023-12-20", "text": "", "title": "3.2.0 (2023-12-20)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_1", "text": "cozy-flags: Add declaration dir in options ( faa5b5c )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_1", "text": "mespapiers: Replace spinner by skeletons on papers list ( 2303501 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#310-2023-10-31", "text": "", "title": "3.1.0 (2023-10-31)"}, {"location": "cozy-flags/CHANGELOG/#features_2", "text": "cozy-flags: Output types in dist ( cd5e2b0 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#301-2023-04-13", "text": "", "title": "3.0.1 (2023-04-13)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_2", "text": "Cozy-Flags lint issues ( ee26c09 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#300-2023-04-05", "text": "", "title": "3.0.0 (2023-04-05)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_3", "text": "Use io.cozy.settings.flags and io.cozy.settings.context id ( c27806f )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_3", "text": "mespapiers: Update cozy-ui from 82.4.0 to 82.5.1 ( d016608 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#breaking-changes_1", "text": "mespapiers: you must have cozy-ui >= 82.5.1", "title": "BREAKING CHANGES"}, {"location": "cozy-flags/CHANGELOG/#2120-2023-03-21", "text": "", "title": "2.12.0 (2023-03-21)"}, {"location": "cozy-flags/CHANGELOG/#features_4", "text": "flag: Find value from parameter with nested part into JSON content ( 7836d84 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#2110-2023-01-31", "text": "", "title": "2.11.0 (2023-01-31)"}, {"location": "cozy-flags/CHANGELOG/#features_5", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#2102-2022-10-03", "text": "Note: Version bump only for package cozy-flags", "title": "2.10.2 (2022-10-03)"}, {"location": "cozy-flags/CHANGELOG/#2101-2022-08-01", "text": "Note: Version bump only for package cozy-flags", "title": "2.10.1 (2022-08-01)"}, {"location": "cozy-flags/CHANGELOG/#2100-2022-07-05", "text": "", "title": "2.10.0 (2022-07-05)"}, {"location": "cozy-flags/CHANGELOG/#features_6", "text": "All oauth methods to handle reconection case ( b1a6033 ) flags: Upgrade devDep cozy-client ( 8870271 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#290-2022-06-03", "text": "", "title": "2.9.0 (2022-06-03)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_4", "text": "bump jest-localstorage-mock from 2.4.19 to 2.4.21 ( 9792e2e )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_7", "text": "harvest: HandleOAuthResponse can deal with cozy-data from DOM ( 7c6ac1a )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#287-2022-03-21", "text": "", "title": "2.8.7 (2022-03-21)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_5", "text": "deps: update dependency jest-localstorage-mock to v2.4.19 ( 361279c )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#286-2022-03-01", "text": "", "title": "2.8.6 (2022-03-01)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_6", "text": "flags: Don\u2019t log when flags.enable called with empty array ( 96ea387 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#285-2022-02-18", "text": "", "title": "2.8.5 (2022-02-18)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_7", "text": "deps: pin dependencies ( e53d065 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#284-2022-02-01", "text": "", "title": "2.8.4 (2022-02-01)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_8", "text": "deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#283-2021-12-20", "text": "Note: Version bump only for package cozy-flags", "title": "2.8.3 (2021-12-20)"}, {"location": "cozy-flags/CHANGELOG/#282-2021-12-02", "text": "Note: Version bump only for package cozy-flags", "title": "2.8.2 (2021-12-02)"}, {"location": "cozy-flags/CHANGELOG/#281-2021-11-24", "text": "", "title": "2.8.1 (2021-11-24)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_9", "text": "Informations on readme ( ea517de )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#280-2021-10-22", "text": "", "title": "2.8.0 (2021-10-22)"}, {"location": "cozy-flags/CHANGELOG/#features_8", "text": "Remove drive from homeHref ( 97010d3 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#272-2021-05-12", "text": "", "title": "2.7.2 (2021-05-12)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_10", "text": "Revert change on removal of browser ( cd77604 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#271-2021-04-21", "text": "", "title": "2.7.1 (2021-04-21)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_11", "text": "Don\u2019t import Q from cozy-client ( 0be2442 ) Flags should install cozy-client ( b1ca8e6 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#270-2021-04-09", "text": "", "title": "2.7.0 (2021-04-09)"}, {"location": "cozy-flags/CHANGELOG/#features_9", "text": "Use animated SVG ( a0856a5 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#260-2021-03-08", "text": "", "title": "2.6.0 (2021-03-08)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_12", "text": "Import in FlagSwitcher ( 5ccc780 ) Remove useless block for node ( fb15094 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_10", "text": "Use import/export to benefit from tree shaking ( 1a72770 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#254-2021-03-05", "text": "", "title": "2.5.4 (2021-03-05)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_13", "text": "Don\u2019t require react in a node context ( bba9d41 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#253-2021-02-12", "text": "Note: Version bump only for package cozy-flags", "title": "2.5.3 (2021-02-12)"}, {"location": "cozy-flags/CHANGELOG/#252-2021-02-11", "text": "", "title": "2.5.2 (2021-02-11)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_14", "text": "Do not use deprecated client.get ( 078369e )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#251-2021-02-02", "text": "Note: Version bump only for package cozy-flags", "title": "2.5.1 (2021-02-02)"}, {"location": "cozy-flags/CHANGELOG/#250-2020-11-23", "text": "", "title": "2.5.0 (2020-11-23)"}, {"location": "cozy-flags/CHANGELOG/#features_11", "text": "All babel cli at 7.12.1 ( 387a24a )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#241-2020-10-16", "text": "Note: Version bump only for package cozy-flags", "title": "2.4.1 (2020-10-16)"}, {"location": "cozy-flags/CHANGELOG/#240-2020-10-01", "text": "", "title": "2.4.0 (2020-10-01)"}, {"location": "cozy-flags/CHANGELOG/#features_12", "text": "Add refresh method on plugin ( f9fb8ef )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#235-2020-10-01", "text": "Note: Version bump only for package cozy-flags", "title": "2.3.5 (2020-10-01)"}, {"location": "cozy-flags/CHANGELOG/#234-2020-09-15", "text": "Note: Version bump only for package cozy-flags", "title": "2.3.4 (2020-09-15)"}, {"location": "cozy-flags/CHANGELOG/#233-2020-08-03", "text": "Note: Version bump only for package cozy-flags", "title": "2.3.3 (2020-08-03)"}, {"location": "cozy-flags/CHANGELOG/#232-2020-07-16", "text": "Note: Version bump only for package cozy-flags", "title": "2.3.2 (2020-07-16)"}, {"location": "cozy-flags/CHANGELOG/#231-2020-07-08", "text": "", "title": "2.3.1 (2020-07-08)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_15", "text": "Make sure the initializing promise is reset on logout ( 673029b )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#230-2020-07-08", "text": "", "title": "2.3.0 (2020-07-08)"}, {"location": "cozy-flags/CHANGELOG/#features_13", "text": "Emit events when plugins are ready ( 5fc182c )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#225-2020-06-09", "text": "", "title": "2.2.5 (2020-06-09)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_16", "text": "Remove initialization of flag did not work ( d743e09 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#224-2020-02-27", "text": "Note: Version bump only for package cozy-flags", "title": "2.2.4 (2020-02-27)"}, {"location": "cozy-flags/CHANGELOG/#223-2020-02-25", "text": "Note: Version bump only for package cozy-flags", "title": "2.2.3 (2020-02-25)"}, {"location": "cozy-flags/CHANGELOG/#222-2020-02-24", "text": "", "title": "2.2.2 (2020-02-24)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_17", "text": "Init flags when client is already logged in ( ff4d3ed )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#221-2020-02-24", "text": "", "title": "2.2.1 (2020-02-24)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_18", "text": "Load flags from legacy DOM ( #968 ) ( 6f54cc7 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#220-2020-02-06", "text": "", "title": "2.2.0 (2020-02-06)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_19", "text": "Use useEffect to clean up event handlers on unmount ( 3cdf5be )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_14", "text": "Add CozyClient plugin for automatic flag initialisation ( 0959c8b ) Deprecate flags.enable with an array ( 85000f5 ) Expose only 1 method to initialize flags ( f5a65ec ) Initialize flags from DOM ( d822f68 ) Initialize from remote endpoint ( 1383590 ) Use data-cozy-flags attribute instead of data-flags ( 4254a8b )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#210-2020-01-24", "text": "", "title": "2.1.0 (2020-01-24)"}, {"location": "cozy-flags/CHANGELOG/#features_15", "text": "Add notes folder ( 94fa863 ) Adds a useFlag react hook ( 4c3df09 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#200-2019-12-09", "text": "", "title": "2.0.0 (2019-12-09)"}, {"location": "cozy-flags/CHANGELOG/#features_16", "text": "Use conventional display name for HOC ( 350e3c3 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#breaking-changes_2", "text": "Components wrapped in withFlags HOC now have a different displayName , that is more in coherence with other HOC in our codebase. This will require a snapshots update. Ex: flag_WrappedComponent becomes withFlags(WrappedComponent)", "title": "BREAKING CHANGES"}, {"location": "cozy-flags/CHANGELOG/#1110-2019-11-04", "text": "", "title": "1.11.0 (2019-11-04)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_20", "text": "Add account link ( 9745b34 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_17", "text": "Sort flags ( b60e44c )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#1100-2019-09-05", "text": "", "title": "1.10.0 (2019-09-05)"}, {"location": "cozy-flags/CHANGELOG/#features_18", "text": "Add account route ( 7986708 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#193-2019-07-19", "text": "Note: Version bump only for package cozy-flags", "title": "1.9.3 (2019-07-19)"}, {"location": "cozy-flags/CHANGELOG/#192-2019-07-19", "text": "Note: Version bump only for package cozy-flags", "title": "1.9.2 (2019-07-19)"}, {"location": "cozy-flags/CHANGELOG/#191-2019-07-11", "text": "Note: Version bump only for package cozy-flags", "title": "1.9.1 (2019-07-11)"}, {"location": "cozy-flags/CHANGELOG/#190-2019-07-04", "text": "", "title": "1.9.0 (2019-07-04)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_21", "text": "Do not remove import with no specifiers (side-effect imports) ( 4d0ad6c ) Topbar back button ( 100ffb9 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_19", "text": "Count JSX as React identifier ( f573490 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#180-2019-06-10", "text": "", "title": "1.8.0 (2019-06-10)"}, {"location": "cozy-flags/CHANGELOG/#features_20", "text": "Add codemod for flags accessible via \u201ccozy-flags apply\u201d ( 9327f24 ) Remove unused imports after removing flags ( af43da1 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#170-2019-05-23", "text": "", "title": "1.7.0 (2019-05-23)"}, {"location": "cozy-flags/CHANGELOG/#features_21", "text": "Flag automatically backs up to localStorage if present ( 24bcd04 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#161-2019-05-03", "text": "", "title": "1.6.1 (2019-05-03)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_22", "text": "Expose FlagSwitcher only in browser context ( f2fafa7 ), closes #402 Fix cozy-mjml with nsjail ( #392 ) ( 300a4e6 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#160-2019-03-29", "text": "", "title": "1.6.0 (2019-03-29)"}, {"location": "cozy-flags/CHANGELOG/#features_22", "text": "Flag hoc to connect to store ( 98130a9 ) Store flags in an object to avoid querying localStorage ( 1f46ad1 )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#159-2019-03-18", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.9 (2019-03-18)"}, {"location": "cozy-flags/CHANGELOG/#158-2019-03-12", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.8 (2019-03-12)"}, {"location": "cozy-flags/CHANGELOG/#157-2019-03-12", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.7 (2019-03-12)"}, {"location": "cozy-flags/CHANGELOG/#156-2019-03-12", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.6 (2019-03-12)"}, {"location": "cozy-flags/CHANGELOG/#155-2019-02-12", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.5 (2019-02-12)"}, {"location": "cozy-flags/CHANGELOG/#154-2019-02-11", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.4 (2019-02-11)"}, {"location": "cozy-flags/CHANGELOG/#153-2019-01-30", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.3 (2019-01-30)"}, {"location": "cozy-flags/CHANGELOG/#152-2019-01-29", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.2 (2019-01-29)"}, {"location": "cozy-flags/CHANGELOG/#151-2019-01-11", "text": "Note: Version bump only for package cozy-flags", "title": "1.5.1 (2019-01-11)"}, {"location": "cozy-flags/CHANGELOG/#150-2019-01-04", "text": "", "title": "1.5.0 (2019-01-04)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_23", "text": "flags: Handle case where ENABLED_FLAGS is undefined properly ( c771ff8 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_23", "text": "flags: Export enableFlags under flag namespace ( 56a136f )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#140-2019-01-03", "text": "", "title": "1.4.0 (2019-01-03)"}, {"location": "cozy-flags/CHANGELOG/#features_24", "text": "flags: Handle flags enabled at build time ( 87de30a )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#137-2018-12-28", "text": "Note: Version bump only for package cozy-flags", "title": "1.3.7 (2018-12-28)"}, {"location": "cozy-flags/CHANGELOG/#136-2018-12-26", "text": "Note: Version bump only for package cozy-flags", "title": "1.3.6 (2018-12-26)"}, {"location": "cozy-flags/CHANGELOG/#135-2018-12-17", "text": "Note: Version bump only for package cozy-flags", "title": "1.3.5 (2018-12-17)"}, {"location": "cozy-flags/CHANGELOG/#134-2018-12-11", "text": "", "title": "1.3.4 (2018-12-11)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_24", "text": "flags: Use detect-node dep ( 8bdf522 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#133-2018-12-10", "text": "Note: Version bump only for package cozy-flags", "title": "1.3.3 (2018-12-10)"}, {"location": "cozy-flags/CHANGELOG/#132-2018-12-10", "text": "", "title": "1.3.2 (2018-12-10)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_25", "text": "flags: Node and browser detection ( 0b3c4d7 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#131-2018-12-06", "text": "", "title": "1.3.1 (2018-12-06)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_26", "text": "flags: Add default property to require ( 94a4465 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#130-2018-12-06", "text": "", "title": "1.3.0 (2018-12-06)"}, {"location": "cozy-flags/CHANGELOG/#features_25", "text": "flags: Add node implementation ( a2aeb6c )", "title": "Features"}, {"location": "cozy-flags/CHANGELOG/#1212-2018-12-06", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.12 (2018-12-06)"}, {"location": "cozy-flags/CHANGELOG/#1211-2018-10-30", "text": "", "title": "1.2.11 (2018-10-30)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_27", "text": "Update homepage link ( 728a850 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#1210-2018-10-02", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.10 (2018-10-02)"}, {"location": "cozy-flags/CHANGELOG/#129-2018-09-25", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.9 (2018-09-25)"}, {"location": "cozy-flags/CHANGELOG/#128-2018-09-25", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.8 (2018-09-25)"}, {"location": "cozy-flags/CHANGELOG/#127-2018-09-24", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.7 (2018-09-24)"}, {"location": "cozy-flags/CHANGELOG/#126-2018-09-21", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.6 (2018-09-21)"}, {"location": "cozy-flags/CHANGELOG/#125-2018-09-11", "text": "", "title": "1.2.5 (2018-09-11)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_28", "text": "flags: Return null if flag doesn\u2019t exist ( 54096a7 )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#124-2018-08-30", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.4 (2018-08-30)"}, {"location": "cozy-flags/CHANGELOG/#123-2018-08-22", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.3 (2018-08-22)"}, {"location": "cozy-flags/CHANGELOG/#122-2018-08-09", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.2 (2018-08-09)"}, {"location": "cozy-flags/CHANGELOG/#121-2018-08-08", "text": "Note: Version bump only for package cozy-flags", "title": "1.2.1 (2018-08-08)"}, {"location": "cozy-flags/CHANGELOG/#120-2018-08-08", "text": "", "title": "1.2.0 (2018-08-08)"}, {"location": "cozy-flags/CHANGELOG/#bug-fixes_29", "text": "remove unused dependency \ud83d\udd25 ( 5fd7f1e )", "title": "Bug Fixes"}, {"location": "cozy-flags/CHANGELOG/#features_26", "text": "add flags library \ud83d\ude0e ( d42220b )", "title": "Features"}, {"location": "cozy-home/", "text": "Cozy Home \u00b6 What\u2019s Cozy? \u00b6 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\u2019s tracking you. What is Home ? \u00b6 An application to configure and runs cozy konnectors. It is the main entrypoint to a Cozy. Lists applications and konnectors Manage konnectors and accounts through Harvest Runs services that take care of synchronizing io.cozy.accounts and io.cozy.ciphers . You can read more: Develop Services Cozy Home is developed by Cozy Cloud and distributed under the AGPL v3 license .", "title": "Index"}, {"location": "cozy-home/#cozy-home", "text": "", "title": "Cozy Home"}, {"location": "cozy-home/#whats-cozy", "text": "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\u2019s tracking you.", "title": "What's Cozy?"}, {"location": "cozy-home/#what-is-home", "text": "An application to configure and runs cozy konnectors. It is the main entrypoint to a Cozy. Lists applications and konnectors Manage konnectors and accounts through Harvest Runs services that take care of synchronizing io.cozy.accounts and io.cozy.ciphers . You can read more: Develop Services Cozy Home is developed by Cozy Cloud and distributed under the AGPL v3 license .", "title": "What is Home ?"}, {"location": "cozy-home/CHANGELOG/", "text": "1.49.0 \u00b6 \u2728 Features \u00b6 Add FAB button on mobile to quickly create new docs Hide fallback category konnectors in maintenance \ud83d\udc1b Bug Fixes \u00b6 Fix interaction freeze that may happen when scrolling the app from iOS \ud83d\udd27 Tech \u00b6 Upgrade cozy-ui to latest (79.3.0) 1.48.0 \u00b6 \u2728 Features \u00b6 Upgrade cozy-harvest-lib from 9.26.10 to 9.32.5 Add independent confirm dialog Use independant OAuth window Follow current trigger jobs even after the first load Popup display after BI connection removal from BI webview Reconnection with BI webviews & webhooks Use BI manage url to update contract synchronization Close Harvest when BI connection is removed in webview Nuke matomo/piwik \ud83d\udc1b Bug Fixes \u00b6 Upgrade cozy-harvest-lib from 9.26.10 to 9.32.5 Prevent createTemporaryToken to updateCache twice at the same time Add konnector slug in fake trigger passed to onLoginSuccess Only update cozy-client store when refreshing contract Use correct button to close CozyConfirmDialog Do not use CozyRealtime.unsubscribeAll anymore Deal with empty and malformed encrypted values Add explicit blocked popup message \ud83d\udd27 Tech \u00b6 Renew Github Token for CI Upgrade to React 18 PR Performance optimizations Upgrade cozy-keys-lib to 4.3.0 PR Do not depend only on konnector.slug for useEffect dependencies Add useEffect dependencies to useOAuthExtraParams hook Upgrade cozy-harvest-lib from 9.26.10 to 9.32.5 Allow to pass custom Properties to OAuthForm wrapper Full Changelog : https://github.com/cozy/cozy-home/compare/1.47.0\u20261.48 1.47.0 \u00b6 \ud83d\udc1b Bug Fixes \u00b6 Fix a bug when creating an OAuth account, no oauth window displayed Fix a bug to hide BIContractActivationWindow behind the bi webview flag 1.46.0 \u00b6 \u2728 Features \u00b6 Update the applications and the connectors displayed on the Home page in realtime. Fix position of background wallpaper image, preventing scroll showing white background inside Cozy\u2019s native application. When displaying cozy-home from Cozy\u2019s native application, the splash screen is now correctly shown during the page loading Display InAppBrowser in flagship app for OAuth connectors cozy-harvest-lib 9.2.1 : Add BI connection creation via BI webview PR cozy-harvest-lib 9.7.0 : Add contract activation/deactivation via BI webview PR cozy-harvest-lib 9.8.0 : Add reconnect to bi Webviews PR cozy-harvest-lib 9.10.1 : Add custom intentsApi prop to TriggerManager PR \ud83d\udc1b Bug Fixes \u00b6 On IOS Safari, the URL and Navigation bar were always displayed Now show the jobs as running after first account configuration in Harvest PR cozy-harvest-lib 8.2.1 : Get correct bi mapping for bnp_es and cic_es PR Fix a bug when opening a konnector from the store is opening briefly the home to redirect to\u2026 the store. Now we redirect to the right place. Fix a bug when configuring a konnector from the intent. The form was empty if a vault was active on the cozy Fix a bug when opening a PDF from Harvest, display was truncated. \ud83d\udd27 Tech \u00b6 Cozy-ui 66.0.0 to remove warning Badge overlap rectangular PR Upgrade cozy-client and cozy-device-helper because of cozy-ui breaking change PR Remove unused demo timeline Unregister any service worker that could have been registered during development Upgrade cozy-flags to remove useless some warnings flag.enable Upgrade cozy-client to get ability to force HTTPs fetches when window.cozy.isSecureProtocol is true Remove the pull request template PR 1.45.0 \u00b6 \u2728 Features \u00b6 Loading App\u2019s icons: Should be faster. We now rely on img src=http directly if we are not in OAuth. Otherwise we do a fetch. cozy-harvest-lib 6.15.0 : get support email according to the contect PR cozy-harvest-lib 7.1.0 : no multi account for client side connectors PR cozy-harvest-lib 7.3.0 : Do not allow multiple accounts with same BI connection ID PR \ud83d\udc1b Bug Fixes \u00b6 fix translation during the loading phase fix spinner position for the ShortcutView during the loading phase cozy-harvest-lib 6.14.4 : change timeout for createTemporaryToken PR \ud83d\udd27 Tech \u00b6 useAppsInMaintenance hook is now moved in cozy client and can be used in other apps Revert to cozy-keys-lib 3.11.0 to avoid a bug with intent cozy-client 27.19.2 : Get Icon Url uses preloaded url when oAuth not needed PR cozy-ui 62.1.3 : Add appData to getIconUrl PR 1.44.0 \u00b6 \u2728 Features \u00b6 \ud83d\udc1b Bug Fixes \u00b6 We had a bug in Harvest which caused a fatal error for OAuth connectors : See this PR \ud83d\udd27 Tech \u00b6 1.43.0 \u00b6 \u2728 Features \u00b6 \ud83d\udc1b Bug Fixes \u00b6 We had a bug in Harvest that when we opened, then closed then opened again the modal,the konnector\u2019s translations were not good \ud83d\udd27 Tech \u00b6 1.42.0 \u00b6 \u2728 Features \u00b6 Display custom shortcuts in the homepage below existing Konnectors Integration of client-side connectors cozy-client 24.2.0 : fetchAppLatestVersion cozy-harvest-lib 6.5.O : client side connectors specificities cozy-harvest-lib 6.6.O : new BI slug for palatine bank new home layout Change matomo url from piwik.cozycloud.cc to matomo.cozycloud.cc New home design \ud83d\udc1b Bug Fixes \u00b6 ignore manifest\u2019s id if any to avoid a crash login and passwords fields do not enforce upercase on first letter anymore when login to a Konnector avoid blur effect when hover icon \ud83d\udd27 Tech \u00b6", "title": "1.49.0"}, {"location": "cozy-home/CHANGELOG/#1490", "text": "", "title": "1.49.0"}, {"location": "cozy-home/CHANGELOG/#features", "text": "Add FAB button on mobile to quickly create new docs Hide fallback category konnectors in maintenance", "title": "\u2728 Features"}, {"location": "cozy-home/CHANGELOG/#bug-fixes", "text": "Fix interaction freeze that may happen when scrolling the app from iOS", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#tech", "text": "Upgrade cozy-ui to latest (79.3.0)", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-home/CHANGELOG/#1480", "text": "", "title": "1.48.0"}, {"location": "cozy-home/CHANGELOG/#features_1", "text": "Upgrade cozy-harvest-lib from 9.26.10 to 9.32.5 Add independent confirm dialog Use independant OAuth window Follow current trigger jobs even after the first load Popup display after BI connection removal from BI webview Reconnection with BI webviews & webhooks Use BI manage url to update contract synchronization Close Harvest when BI connection is removed in webview Nuke matomo/piwik", "title": "\u2728 Features"}, {"location": "cozy-home/CHANGELOG/#bug-fixes_1", "text": "Upgrade cozy-harvest-lib from 9.26.10 to 9.32.5 Prevent createTemporaryToken to updateCache twice at the same time Add konnector slug in fake trigger passed to onLoginSuccess Only update cozy-client store when refreshing contract Use correct button to close CozyConfirmDialog Do not use CozyRealtime.unsubscribeAll anymore Deal with empty and malformed encrypted values Add explicit blocked popup message", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#tech_1", "text": "Renew Github Token for CI Upgrade to React 18 PR Performance optimizations Upgrade cozy-keys-lib to 4.3.0 PR Do not depend only on konnector.slug for useEffect dependencies Add useEffect dependencies to useOAuthExtraParams hook Upgrade cozy-harvest-lib from 9.26.10 to 9.32.5 Allow to pass custom Properties to OAuthForm wrapper Full Changelog : https://github.com/cozy/cozy-home/compare/1.47.0\u20261.48", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-home/CHANGELOG/#1470", "text": "", "title": "1.47.0"}, {"location": "cozy-home/CHANGELOG/#bug-fixes_2", "text": "Fix a bug when creating an OAuth account, no oauth window displayed Fix a bug to hide BIContractActivationWindow behind the bi webview flag", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#1460", "text": "", "title": "1.46.0"}, {"location": "cozy-home/CHANGELOG/#features_2", "text": "Update the applications and the connectors displayed on the Home page in realtime. Fix position of background wallpaper image, preventing scroll showing white background inside Cozy\u2019s native application. When displaying cozy-home from Cozy\u2019s native application, the splash screen is now correctly shown during the page loading Display InAppBrowser in flagship app for OAuth connectors cozy-harvest-lib 9.2.1 : Add BI connection creation via BI webview PR cozy-harvest-lib 9.7.0 : Add contract activation/deactivation via BI webview PR cozy-harvest-lib 9.8.0 : Add reconnect to bi Webviews PR cozy-harvest-lib 9.10.1 : Add custom intentsApi prop to TriggerManager PR", "title": "\u2728 Features"}, {"location": "cozy-home/CHANGELOG/#bug-fixes_3", "text": "On IOS Safari, the URL and Navigation bar were always displayed Now show the jobs as running after first account configuration in Harvest PR cozy-harvest-lib 8.2.1 : Get correct bi mapping for bnp_es and cic_es PR Fix a bug when opening a konnector from the store is opening briefly the home to redirect to\u2026 the store. Now we redirect to the right place. Fix a bug when configuring a konnector from the intent. The form was empty if a vault was active on the cozy Fix a bug when opening a PDF from Harvest, display was truncated.", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#tech_2", "text": "Cozy-ui 66.0.0 to remove warning Badge overlap rectangular PR Upgrade cozy-client and cozy-device-helper because of cozy-ui breaking change PR Remove unused demo timeline Unregister any service worker that could have been registered during development Upgrade cozy-flags to remove useless some warnings flag.enable Upgrade cozy-client to get ability to force HTTPs fetches when window.cozy.isSecureProtocol is true Remove the pull request template PR", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-home/CHANGELOG/#1450", "text": "", "title": "1.45.0"}, {"location": "cozy-home/CHANGELOG/#features_3", "text": "Loading App\u2019s icons: Should be faster. We now rely on img src=http directly if we are not in OAuth. Otherwise we do a fetch. cozy-harvest-lib 6.15.0 : get support email according to the contect PR cozy-harvest-lib 7.1.0 : no multi account for client side connectors PR cozy-harvest-lib 7.3.0 : Do not allow multiple accounts with same BI connection ID PR", "title": "\u2728 Features"}, {"location": "cozy-home/CHANGELOG/#bug-fixes_4", "text": "fix translation during the loading phase fix spinner position for the ShortcutView during the loading phase cozy-harvest-lib 6.14.4 : change timeout for createTemporaryToken PR", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#tech_3", "text": "useAppsInMaintenance hook is now moved in cozy client and can be used in other apps Revert to cozy-keys-lib 3.11.0 to avoid a bug with intent cozy-client 27.19.2 : Get Icon Url uses preloaded url when oAuth not needed PR cozy-ui 62.1.3 : Add appData to getIconUrl PR", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-home/CHANGELOG/#1440", "text": "", "title": "1.44.0"}, {"location": "cozy-home/CHANGELOG/#features_4", "text": "", "title": "\u2728 Features"}, {"location": "cozy-home/CHANGELOG/#bug-fixes_5", "text": "We had a bug in Harvest which caused a fatal error for OAuth connectors : See this PR", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#tech_4", "text": "", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-home/CHANGELOG/#1430", "text": "", "title": "1.43.0"}, {"location": "cozy-home/CHANGELOG/#features_5", "text": "", "title": "\u2728 Features"}, {"location": "cozy-home/CHANGELOG/#bug-fixes_6", "text": "We had a bug in Harvest that when we opened, then closed then opened again the modal,the konnector\u2019s translations were not good", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#tech_5", "text": "", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-home/CHANGELOG/#1420", "text": "", "title": "1.42.0"}, {"location": "cozy-home/CHANGELOG/#features_6", "text": "Display custom shortcuts in the homepage below existing Konnectors Integration of client-side connectors cozy-client 24.2.0 : fetchAppLatestVersion cozy-harvest-lib 6.5.O : client side connectors specificities cozy-harvest-lib 6.6.O : new BI slug for palatine bank new home layout Change matomo url from piwik.cozycloud.cc to matomo.cozycloud.cc New home design", "title": "\u2728 Features"}, {"location": "cozy-home/CHANGELOG/#bug-fixes_7", "text": "ignore manifest\u2019s id if any to avoid a crash login and passwords fields do not enforce upercase on first letter anymore when login to a Konnector avoid blur effect when hover icon", "title": "\ud83d\udc1b Bug Fixes"}, {"location": "cozy-home/CHANGELOG/#tech_6", "text": "", "title": "\ud83d\udd27 Tech"}, {"location": "cozy-home/CONTRIBUTING/", "text": "How to contribute to Cozy Home? \u00b6 Thank you for your interest in contributing to Cozy! There are many ways to contribute, and we appreciate all of them. Security Issues \u00b6 If you discover a security issue, please bring it to our attention right away! Please DO NOT file a public issue, instead send your report privately to security AT cozycloud DOT cc. Security reports are greatly appreciated and we will publicly thank you for it. We currently do not offer a paid security bounty program, but are not ruling it out in the future. Bug Reports \u00b6 While bugs are unfortunate, they\u2019re a reality in software. We can\u2019t fix what we don\u2019t know about, so please report liberally. If you\u2019re not sure if something is a bug or not, feel free to file a bug anyway. Opening an issue is as easy as following this link and filling out the fields. Here are some things you can write about your bug: A short summary What did you try, step by step? What did you expect? What did happen instead? What is the version of the Cozy Drive? Pull Requests \u00b6 Please keep in mind that: Pull-Requests point to the master branch You need to cover your code and feature by tests You may add documentation in the /docs directory to explain your choices if needed We recommend to use [task lists][checkbox] to explain steps / features in your Pull-Request description you do not need to build app to submit a PR you should update the Transifex source locale file if you modify it for your feature needs (see Localization section in README ) Workflow \u00b6 Pull requests are the primary mechanism we use to change Cozy. GitHub itself has some great documentation on using the Pull Request feature. We use the fork and pull model described there. Step 1: Fork \u00b6 Fork the project on GitHub and check out your copy locally . $ git clone github.com/cozy/cozy-home.git $ cd cozy-home $ git remote add fork git://github.com/yourusername/cozy-home.git Step 2: Branch \u00b6 Create a branch and start hacking: $ git checkout -b my-branch origin/master Step 3: Code \u00b6 Well, we think you know how to do that. Just be sure to follow the coding guidelines from the community ( standard JS , comment the code, etc). Step 4: Test \u00b6 Don\u2019t forget to add tests and be sure they are green: $ cd cozy-home $ npm run test Step 5: Commit \u00b6 Writing good commit messages is important. A commit message should describe what changed and why. Step 6: Rebase \u00b6 Use git rebase ( not git merge ) to sync your work from time to time. $ git fetch origin $ git rebase origin/master my-branch Step 7: Push \u00b6 $ git push -u fork my-branch Go to https://github.com/yourusername/cozy-home and select your branch. Click the \u2018Pull Request\u2019 button and fill out the form. Alternatively, you can use hub to open the pull request from your terminal: $ git pull-request -b master -m \"My PR message\" -o Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in a separate commit and push that to your branch. Post a comment in the pull request afterwards; GitHub doesn\u2019t send out notifications when you add commits. Writing documentation \u00b6 Documentation improvements are very welcome. We try to keep a good documentation in the /docs folder. But, you know, we are developers, we can forget to document important stuff that look obvious to us. And documentation can always be improved. Translations \u00b6 Localization and translations are handled by Transifex , which is used by all Cozy\u2019s apps. As a translator , you can login to Transifex (using your Github account) and claim an access to the app repository . Transifex will then create pull request on the repository, and the locales are merged after validating the pull request. This tutorial can help you to learn how to make your first steps here. If you have any question, don\u2019t hesitate to ask us! As a developer , you just have to modify json in /src/locales . New locales will be automatically added to Transifex. If you need to pull or push manually locales, you can use Transifex CLI . If you were using a transifex-client , you must move to Transifex CLI to be compatible with the v3 API. Community \u00b6 You can help us by making our community even more vibrant. For example, you can write a blog post, take some videos, answer the questions on the forum , organize new meetups, and speak about what you like in Cozy!", "title": "How to contribute to Cozy Home?"}, {"location": "cozy-home/CONTRIBUTING/#how-to-contribute-to-cozy-home", "text": "Thank you for your interest in contributing to Cozy! There are many ways to contribute, and we appreciate all of them.", "title": "How to contribute to Cozy Home?"}, {"location": "cozy-home/CONTRIBUTING/#security-issues", "text": "If you discover a security issue, please bring it to our attention right away! Please DO NOT file a public issue, instead send your report privately to security AT cozycloud DOT cc. Security reports are greatly appreciated and we will publicly thank you for it. We currently do not offer a paid security bounty program, but are not ruling it out in the future.", "title": "Security Issues"}, {"location": "cozy-home/CONTRIBUTING/#bug-reports", "text": "While bugs are unfortunate, they\u2019re a reality in software. We can\u2019t fix what we don\u2019t know about, so please report liberally. If you\u2019re not sure if something is a bug or not, feel free to file a bug anyway. Opening an issue is as easy as following this link and filling out the fields. Here are some things you can write about your bug: A short summary What did you try, step by step? What did you expect? What did happen instead? What is the version of the Cozy Drive?", "title": "Bug Reports"}, {"location": "cozy-home/CONTRIBUTING/#pull-requests", "text": "Please keep in mind that: Pull-Requests point to the master branch You need to cover your code and feature by tests You may add documentation in the /docs directory to explain your choices if needed We recommend to use [task lists][checkbox] to explain steps / features in your Pull-Request description you do not need to build app to submit a PR you should update the Transifex source locale file if you modify it for your feature needs (see Localization section in README )", "title": "Pull Requests"}, {"location": "cozy-home/CONTRIBUTING/#workflow", "text": "Pull requests are the primary mechanism we use to change Cozy. GitHub itself has some great documentation on using the Pull Request feature. We use the fork and pull model described there.", "title": "Workflow"}, {"location": "cozy-home/CONTRIBUTING/#step-1-fork", "text": "Fork the project on GitHub and check out your copy locally . $ git clone github.com/cozy/cozy-home.git $ cd cozy-home $ git remote add fork git://github.com/yourusername/cozy-home.git", "title": "Step 1: Fork"}, {"location": "cozy-home/CONTRIBUTING/#step-2-branch", "text": "Create a branch and start hacking: $ git checkout -b my-branch origin/master", "title": "Step 2: Branch"}, {"location": "cozy-home/CONTRIBUTING/#step-3-code", "text": "Well, we think you know how to do that. Just be sure to follow the coding guidelines from the community ( standard JS , comment the code, etc).", "title": "Step 3: Code"}, {"location": "cozy-home/CONTRIBUTING/#step-4-test", "text": "Don\u2019t forget to add tests and be sure they are green: $ cd cozy-home $ npm run test", "title": "Step 4: Test"}, {"location": "cozy-home/CONTRIBUTING/#step-5-commit", "text": "Writing good commit messages is important. A commit message should describe what changed and why.", "title": "Step 5: Commit"}, {"location": "cozy-home/CONTRIBUTING/#step-6-rebase", "text": "Use git rebase ( not git merge ) to sync your work from time to time. $ git fetch origin $ git rebase origin/master my-branch", "title": "Step 6: Rebase"}, {"location": "cozy-home/CONTRIBUTING/#step-7-push", "text": "$ git push -u fork my-branch Go to https://github.com/yourusername/cozy-home and select your branch. Click the \u2018Pull Request\u2019 button and fill out the form. Alternatively, you can use hub to open the pull request from your terminal: $ git pull-request -b master -m \"My PR message\" -o Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in a separate commit and push that to your branch. Post a comment in the pull request afterwards; GitHub doesn\u2019t send out notifications when you add commits.", "title": "Step 7: Push"}, {"location": "cozy-home/CONTRIBUTING/#writing-documentation", "text": "Documentation improvements are very welcome. We try to keep a good documentation in the /docs folder. But, you know, we are developers, we can forget to document important stuff that look obvious to us. And documentation can always be improved.", "title": "Writing documentation"}, {"location": "cozy-home/CONTRIBUTING/#translations", "text": "Localization and translations are handled by Transifex , which is used by all Cozy\u2019s apps. As a translator , you can login to Transifex (using your Github account) and claim an access to the app repository . Transifex will then create pull request on the repository, and the locales are merged after validating the pull request. This tutorial can help you to learn how to make your first steps here. If you have any question, don\u2019t hesitate to ask us! As a developer , you just have to modify json in /src/locales . New locales will be automatically added to Transifex. If you need to pull or push manually locales, you can use Transifex CLI . If you were using a transifex-client , you must move to Transifex CLI to be compatible with the v3 API.", "title": "Translations"}, {"location": "cozy-home/CONTRIBUTING/#community", "text": "You can help us by making our community even more vibrant. For example, you can write a blog post, take some videos, answer the questions on the forum , organize new meetups, and speak about what you like in Cozy!", "title": "Community"}, {"location": "cozy-home/docs/configuration/", "text": "Cozy Home Configuration \u00b6 The main configuration file is /src/config/home.json . Its provides a convenient way to centralize global parameters of Cozy Home. Configuration parameters are: defaultDateFormat \u00b6 If Cozy Home cannot retrieve date format from locales, it will use the format specified for this parameter. defaultTriggerTimeInterval \u00b6 When no time interval is given in a konnector\u2019s manifest, Cozy Home will use the one specified for this parameter. When an account is associated to a trigger, the trigger will need a time to run, for example 3:00PM. A time interval defines the start time and the end time between the trigger launch time will be randomized. For example, for a given time interval [\u00d8, 5] , the trigger launch time will be scheduled between 0:00PM and 5:00AM. It could be for example 2:49AM. It is used to avoid having all the trigger launched at the same time.", "title": "Cozy Home Configuration"}, {"location": "cozy-home/docs/configuration/#cozy-home-configuration", "text": "The main configuration file is /src/config/home.json . Its provides a convenient way to centralize global parameters of Cozy Home. Configuration parameters are:", "title": "Cozy Home Configuration"}, {"location": "cozy-home/docs/configuration/#defaultdateformat", "text": "If Cozy Home cannot retrieve date format from locales, it will use the format specified for this parameter.", "title": "defaultDateFormat"}, {"location": "cozy-home/docs/configuration/#defaulttriggertimeinterval", "text": "When no time interval is given in a konnector\u2019s manifest, Cozy Home will use the one specified for this parameter. When an account is associated to a trigger, the trigger will need a time to run, for example 3:00PM. A time interval defines the start time and the end time between the trigger launch time will be randomized. For example, for a given time interval [\u00d8, 5] , the trigger launch time will be scheduled between 0:00PM and 5:00AM. It could be for example 2:49AM. It is used to avoid having all the trigger launched at the same time.", "title": "defaultTriggerTimeInterval"}, {"location": "cozy-home/docs/connection-state/", "text": "Connection state \u00b6 In this document we\u2019ll gather all information and parameters needed to get the connection state in cozy-home. Some definitions and context \u00b6 Konnector: It means a script available that can be used to connect a service account to the Cozy. We say that the konnector is \u2018installed\u2019 if it\u2019s registered in the Cozy database. If a konnector is not installed by default in the Cozy, it will be just before its very first usage/connection. Account: A document created from the login informations provided by the user in the konnector form or by an OAuth connection. In this account will be stored all informations related to the connected service account but also the frequency or the directory ID if the konnector needs a directory to store some files. Job: When the user connect a new service using a konnector, a job will be created on the stack side. This job corresponds to the konnector script run on the server side by the stack. It can have different status like RUNNING or DONE . KonnectorResult: It corresponds to the last result of a konnector\u2019s job run by the stack. It is used to get the last result of a konnector if an account is connected and not any job (for this konnector) is running. It also has status like ERRORED if an error occured. The account connection state \u00b6 NOT CONNECTED NOT Konnector INSTALLED AND NOT Directory CREATING AND NOT Konnector INSTALLING OR : Konnector INSTALLED AND NOT account RUNNING Directory CREATING OR : Konnector INSTALLING OR : Konnector INSTALLED AND account CREATING OR : Job RUNNING CONNECTED NOT Job RUNNING AND : KonnectorResult AND : KonnectorResult.state DONE ERRORED NOT Job RUNNING AND : KonnectorResult AND : KonnectorResult.state ERRORED OR Konnector INSTALLED AND KonnectorResult.state ERRORED Example of usage : NOT CONNECTED : display nothing as status icon RUNNING : display a loading spinner CONNECTED : display a success icon ERRORED : display an error icon Triggers V2 \u00b6 Triggers v2 is the name of the next implementation of the whole konnector logic. The connection statues will change consequently. KonnectorResults documents will be deprecated and all information about connection will be centralized into Trigger documents. The condition for connection state will be: NOT CONNECTED NOT existing Trigger A new state CREATING may be used, to indicate that he connection is intializing itself, before the trigger is created. CREATING Directory CREATING OR Konnector INSTALLING OR Account CREATING RUNNING Trigger exists AND : Job RUNNING CONNECTED Trigger exists AND Job DONE ERRORED Konnector ERRORED OR Trigger exists AND Job ERRORED", "title": "Connection state"}, {"location": "cozy-home/docs/connection-state/#connection-state", "text": "In this document we\u2019ll gather all information and parameters needed to get the connection state in cozy-home.", "title": "Connection state"}, {"location": "cozy-home/docs/connection-state/#some-definitions-and-context", "text": "Konnector: It means a script available that can be used to connect a service account to the Cozy. We say that the konnector is \u2018installed\u2019 if it\u2019s registered in the Cozy database. If a konnector is not installed by default in the Cozy, it will be just before its very first usage/connection. Account: A document created from the login informations provided by the user in the konnector form or by an OAuth connection. In this account will be stored all informations related to the connected service account but also the frequency or the directory ID if the konnector needs a directory to store some files. Job: When the user connect a new service using a konnector, a job will be created on the stack side. This job corresponds to the konnector script run on the server side by the stack. It can have different status like RUNNING or DONE . KonnectorResult: It corresponds to the last result of a konnector\u2019s job run by the stack. It is used to get the last result of a konnector if an account is connected and not any job (for this konnector) is running. It also has status like ERRORED if an error occured.", "title": "Some definitions and context"}, {"location": "cozy-home/docs/connection-state/#the-account-connection-state", "text": "NOT CONNECTED NOT Konnector INSTALLED AND NOT Directory CREATING AND NOT Konnector INSTALLING OR : Konnector INSTALLED AND NOT account RUNNING Directory CREATING OR : Konnector INSTALLING OR : Konnector INSTALLED AND account CREATING OR : Job RUNNING CONNECTED NOT Job RUNNING AND : KonnectorResult AND : KonnectorResult.state DONE ERRORED NOT Job RUNNING AND : KonnectorResult AND : KonnectorResult.state ERRORED OR Konnector INSTALLED AND KonnectorResult.state ERRORED Example of usage : NOT CONNECTED : display nothing as status icon RUNNING : display a loading spinner CONNECTED : display a success icon ERRORED : display an error icon", "title": "The account connection state"}, {"location": "cozy-home/docs/connection-state/#triggers-v2", "text": "Triggers v2 is the name of the next implementation of the whole konnector logic. The connection statues will change consequently. KonnectorResults documents will be deprecated and all information about connection will be centralized into Trigger documents. The condition for connection state will be: NOT CONNECTED NOT existing Trigger A new state CREATING may be used, to indicate that he connection is intializing itself, before the trigger is created. CREATING Directory CREATING OR Konnector INSTALLING OR Account CREATING RUNNING Trigger exists AND : Job RUNNING CONNECTED Trigger exists AND Job DONE ERRORED Konnector ERRORED OR Trigger exists AND Job ERRORED", "title": "Triggers V2"}, {"location": "cozy-home/docs/develop/", "text": "Develop \u00b6 Install and run in dev mode \u00b6 First, you need setup a dev environment . You can then clone the app repository and install dependencies: $ git clone https://github.com/cozy/cozy-home.git $ cd cozy-home $ yarn install $ yarn start Flagship mode \u00b6 If you want to simulate flagship environment, you can edit the __SIMULATE_FLAGSHIP__ var in the webpack.config.cozy-home.js . It\u2019ll simulate a splashscreen during the loading of the application and simulate a call to hideSplashscreen .", "title": "Develop"}, {"location": "cozy-home/docs/develop/#develop", "text": "", "title": "Develop"}, {"location": "cozy-home/docs/develop/#install-and-run-in-dev-mode", "text": "First, you need setup a dev environment . You can then clone the app repository and install dependencies: $ git clone https://github.com/cozy/cozy-home.git $ cd cozy-home $ yarn install $ yarn start", "title": "Install and run in dev mode"}, {"location": "cozy-home/docs/develop/#flagship-mode", "text": "If you want to simulate flagship environment, you can edit the __SIMULATE_FLAGSHIP__ var in the webpack.config.cozy-home.js . It\u2019ll simulate a splashscreen during the loading of the application and simulate a call to hideSplashscreen .", "title": "Flagship mode"}, {"location": "cozy-home/docs/intents/", "text": "Cozy Home Intents \u00b6 Overview \u00b6 A typical Cozy Cloud runs multiple applications, but most of these applications are focused on one task and interact with one particular type of data. However, Cozy Cloud especially shines when data is combined across apps to provide an integrated experience. This is made difficult by the fact that apps have no dedicated back-end and that they have restricted access to documents. This document outlines the intents available in Cozy Home. See cozy stack intent and cozy client js intent for a full documentation about intents. Glossary \u00b6 Intent : Intents, sometimes also called Activities, is a pattern used in environments where multiple apps with different purposes coexist. The idea is that any app can express the need to do something that it can\u2019t do itself, and an app that can do it will take over from there. Stack : refers to cozy-stack , the server-side part of the Cozy infrastructure. Client : the client is the application that starts an intent. Service : the service is the application that handles an intent started by a client. Intents availables \u00b6 Konnectors accounts \u00b6 The intent show you a konnector or a list of konnectors. Manifest \u00b6 Cozy home allow you to create / update / delete an account on a konnector This is defined in the manifest.webapp \"intents\" : [{ \"action\" : \"CREATE\" , \"type\" : [ \"io.cozy.accounts\" ], \"href\" : \"/services\" }] (See cozy stack intent manifest section for more informations) Intent \u00b6 The intent is started by IntentService.jsx To filter the konnectors you want to show, you have to pass parameters to the intent.create function in the client. action : defined in the manifest docType : the type of data you want to access in your intent data : an object who can take slug or dataType key to filter the Konnectors showed by the intent. See datatypes.json for all available dataTypes See below for a full functionnal exemple in React class Intent extends React . Component { componentDidMount () { const { action , docType , data , closeModal } = this . props cozy . client . intents . create ( 'CREATE' , 'io.cozy.accounts' , { dataType : 'bill' }) . start ( this . intentViewer ) } render () { return ( < div id = \"intentViewer\" className = { classNames ( styles [ 'intentViewer' ])} ref = { intentViewer => ( this . intentViewer = intentViewer )} /> ) } }", "title": "Cozy Home Intents"}, {"location": "cozy-home/docs/intents/#cozy-home-intents", "text": "", "title": "Cozy Home Intents"}, {"location": "cozy-home/docs/intents/#overview", "text": "A typical Cozy Cloud runs multiple applications, but most of these applications are focused on one task and interact with one particular type of data. However, Cozy Cloud especially shines when data is combined across apps to provide an integrated experience. This is made difficult by the fact that apps have no dedicated back-end and that they have restricted access to documents. This document outlines the intents available in Cozy Home. See cozy stack intent and cozy client js intent for a full documentation about intents.", "title": "Overview"}, {"location": "cozy-home/docs/intents/#glossary", "text": "Intent : Intents, sometimes also called Activities, is a pattern used in environments where multiple apps with different purposes coexist. The idea is that any app can express the need to do something that it can\u2019t do itself, and an app that can do it will take over from there. Stack : refers to cozy-stack , the server-side part of the Cozy infrastructure. Client : the client is the application that starts an intent. Service : the service is the application that handles an intent started by a client.", "title": "Glossary"}, {"location": "cozy-home/docs/intents/#intents-availables", "text": "", "title": "Intents availables"}, {"location": "cozy-home/docs/intents/#konnectors-accounts", "text": "The intent show you a konnector or a list of konnectors.", "title": "Konnectors accounts"}, {"location": "cozy-home/docs/intents/#manifest", "text": "Cozy home allow you to create / update / delete an account on a konnector This is defined in the manifest.webapp \"intents\" : [{ \"action\" : \"CREATE\" , \"type\" : [ \"io.cozy.accounts\" ], \"href\" : \"/services\" }] (See cozy stack intent manifest section for more informations)", "title": "Manifest"}, {"location": "cozy-home/docs/intents/#intent", "text": "The intent is started by IntentService.jsx To filter the konnectors you want to show, you have to pass parameters to the intent.create function in the client. action : defined in the manifest docType : the type of data you want to access in your intent data : an object who can take slug or dataType key to filter the Konnectors showed by the intent. See datatypes.json for all available dataTypes See below for a full functionnal exemple in React class Intent extends React . Component { componentDidMount () { const { action , docType , data , closeModal } = this . props cozy . client . intents . create ( 'CREATE' , 'io.cozy.accounts' , { dataType : 'bill' }) . start ( this . intentViewer ) } render () { return ( < div id = \"intentViewer\" className = { classNames ( styles [ 'intentViewer' ])} ref = { intentViewer => ( this . intentViewer = intentViewer )} /> ) } }", "title": "Intent"}, {"location": "cozy-home/docs/services/", "text": "myselfFromIdentities \u00b6 Triggered when an io.cozy.identities is created or updated Will update the \u201cme\u201d io.cozy.contacts by merging io.cozy.identities documents in it updateAccounts \u00b6 Triggered when a com.bitwarden.ciphers is updated Will update io.cozy.accounts with the information from the updated ciphers deleteAccounts \u00b6 Triggered when a com.bitwarden.ciphers is deleted Deletes accounts that are linked to the deleted cipher softDeleteOrRestoreAccounts \u00b6 Triggered when a com.bitwarden.ciphers is updated (unless the updated attribute is deletedDate) This service deals with soft delete and restore from bitwarden routes, used for a trash feature. See https://docs.cozy.io/en/cozy-stack/bitwarden/#put-bitwardenapiciphersiddelete When a cipher is soft deleted, a deletedDate field is added to the cipher. Then, the service removes the encrypted credentials from the referenced account and deletes the associated trigger. When the cipher is restored, the deletedDate is removed: the service recreates the account\u2019s trigger. The account\u2019s credentials are then restored through the updateAccountsFromCipher service.", "title": "Services"}, {"location": "cozy-home/docs/services/#myselffromidentities", "text": "Triggered when an io.cozy.identities is created or updated Will update the \u201cme\u201d io.cozy.contacts by merging io.cozy.identities documents in it", "title": "myselfFromIdentities"}, {"location": "cozy-home/docs/services/#updateaccounts", "text": "Triggered when a com.bitwarden.ciphers is updated Will update io.cozy.accounts with the information from the updated ciphers", "title": "updateAccounts"}, {"location": "cozy-home/docs/services/#deleteaccounts", "text": "Triggered when a com.bitwarden.ciphers is deleted Deletes accounts that are linked to the deleted cipher", "title": "deleteAccounts"}, {"location": "cozy-home/docs/services/#softdeleteorrestoreaccounts", "text": "Triggered when a com.bitwarden.ciphers is updated (unless the updated attribute is deletedDate) This service deals with soft delete and restore from bitwarden routes, used for a trash feature. See https://docs.cozy.io/en/cozy-stack/bitwarden/#put-bitwardenapiciphersiddelete When a cipher is soft deleted, a deletedDate field is added to the cipher. Then, the service removes the encrypted credentials from the referenced account and deletes the associated trigger. When the cipher is restored, the deletedDate is removed: the service recreates the account\u2019s trigger. The account\u2019s credentials are then restored through the updateAccountsFromCipher service.", "title": "softDeleteOrRestoreAccounts"}, {"location": "cozy-konnector-libs/", "text": "cozy-konnector-libs \u00b6 cozy-konnector-libs helps you scrape and save data to your cozy. For an easy introduction to scraping your personal data with Cozy: Read the tutorial . Check out Ameli connector for a real life konnector Read the docs API CLI", "title": "README"}, {"location": "cozy-konnector-libs/#cozy-konnector-libs", "text": "cozy-konnector-libs helps you scrape and save data to your cozy. For an easy introduction to scraping your personal data with Cozy: Read the tutorial . Check out Ameli connector for a real life konnector Read the docs API CLI", "title": "cozy-konnector-libs"}, {"location": "cozy-konnector-libs/api/", "text": "API \u00b6 Modules \u00b6 CozyBrowser Get a javascript simulation of a real browser (jsdom) addData Saves the data into the cozy blindly without check. cozyClient cozy-client-js instance already initialized and ready to use. hydrateAndFilter Filters the passed array from data already present in the cozy so that there is not duplicated data in the Cozy. linkBankOperations Finds links between bills and bank operations. mkdirp normalizeFilename Returns the given name, replacing characters that could be an issue when used in a filename with spaces. saveBills Encapsulates the saving of Bills : saves the files, saves the new data, and associate the files to an existing bank operation saveFiles Saves the given files in the given folder via the Cozy API. saveIdentity Helper to set or merge io.cozy.identities See https://github.com/cozy/cozy-doctypes/blob/master/docs/io.cozy.identities.md signin Provides an handy method to log the user in, on HTML form pages. On success, it resolves to a promise with a parsed body. solveCaptcha Use every possible means to solve a captcha. At the moment, Anticaptcha web service is used if any related secret key is found in COZY_PARAMETERS environment variable. updateOrCreate Creates or updates the given entries according to if they already exist in the cozy or not utils Small utilities helping to develop konnectors. categorization Bank transactions categorization Classes \u00b6 BaseKonnector The class from which all the connectors must inherit. It takes a fetch function in parameter that must return a Promise . You need at least the GET permission on io.cozy.accounts in your manifest to allow it to fetch account information for your connector. Its role is twofold : Make the link between account data and konnector Handle errors \u26a0\ufe0f A promise should be returned from the fetch function otherwise the konnector cannot know that asynchronous code has been called. CookieKonnector Connector base class extending BaseKonnector which handles cookie session in a central way It also handles saving cookie session in the account and automatically restore it for the next connector run. All cozy-konnector-libs tools using request are proposed as methods of this class to force them to use the central cookie which can be saved/restored. You need at least the GET and PUT permissions on io.cozy.accounts in your manifest to allow it to save/restore cookies Document Simple Model for Documents. Allows to specify shouldSave , shouldUpdate as methods. Has useful isEqual method Constants \u00b6 fs Manifest is provided differently in developement that in production. In production, the manifest has been \"merged\" via Webpack via the DefinePlugin In development/test, we simply read the manifest from the fs LOGIN_FAILED : string The konnector could not login NOT_EXISTING_DIRECTORY : string The folder specified as folder_to_save does not exist (checked by BaseKonnector) VENDOR_DOWN : string The vendor's website is down USER_ACTION_NEEDED : string There was an unexpected error, please take a look at the logs to know what happened FILE_DOWNLOAD_FAILED : string There was a problem while downloading a file SAVE_FILE_FAILED : string There was a problem while saving a file DISK_QUOTA_EXCEEDED : string Could not save a file to the cozy because of disk quota exceeded CHALLENGE_ASKED : string It seems that the website requires a second authentification factor that we don\u2019t support yet. LOGIN_FAILED_TOO_MANY_ATTEMPTS : string Temporarily blocked USER_ACTION_NEEDED_OAUTH_OUTDATED : string Access refresh required USER_ACTION_NEEDED_ACCOUNT_REMOVED : string Unavailable account USER_ACTION_NEEDED_CHANGE_PASSWORD : string Unavailable account USER_ACTION_NEEDED_PERMISSIONS_CHANGED : string Password update required USER_ACTION_NEEDED_CGU_FORM : string The user needs to accept a CGU form before accessing the rest of the website CAPTCHA_RESOLUTION_FAILED : string solveCaptcha failed to solve the captcha LOGIN_FAILED_NEEDS_SECRET : string Additionnal information is needed to check your login details MAINTENANCE : string remote website seems to be unavailable TERMS_VERSION_MISMATCH : string User needs to accept new terms UNKNOWN_ERROR : string unkown error UNKNOWN_ERROR_PARTIAL_SYNC : string The synchronization is complete but some elements may be missing USER_ACTION_NEEDED_SCA_REQUIRED : string Renewal of authentication required USER_ACTION_NEEDED_TWOFA_EXPIRED : string Authentication renewal required USER_ACTION_NEEDED_WEBAUTH_REQUIRED : string Authentication on vendor website required USER_ACTION_NEEDED_WRONG_TWOFA_CODE : string Incorrect strong authentication code VENDOR_DOWN_BANK_DOWN : string Unavailable bank website VENDOR_DOWN_LINXO_DOWN : string Unavailable bank website Functions \u00b6 attachProcessEventHandlers(prcs) \u21d2 function Attach event handlers to catch uncaught exceptions/rejections and signals. Log them as critical and exit the process accordingly. If the cleanup function has not been called, calling again the function is a no-op. mkSpec() Declarative scraping. Describe your items attributes and where to find/parse them instead of imperatively building them. Heavily inspired by artoo scraping method. scrape($, specs, [childSelector]) \u21d2 object | Array Scrape a cheerio object for properties CozyBrowser \u00b6 Get a javascript simulation of a real browser (jsdom) CozyBrowser defaultOptions \u21d2 object \u23cf ~addListeners() defaultOptions \u21d2 object \u23cf \u00b6 Get a preconfigured jsdom browser simulator using the zombie npm package See http://zombie.js.org/ for complete documentation The connector has to import the zombie npm package itself. Kind : Exported constant Returns : object - Zombie browser extended class Param Type Description options.userAgent string The user agent string used by the browser Example const Browser = require ( 'cozy-konnector-libs/libs/CozyBrowser' ) const browser = new Browser () await browser . visit ( 'http://quotes.toscrape.com/' ) defaultOptions~addListeners() \u00b6 Add cozy-konnector-libs specific logs to browser events Kind : inner method of defaultOptions addData \u00b6 Saves the data into the cozy blindly without check. addData() \u23cf \u00b6 Saves the data into the cozy blindly without check. You need at least the POST permission for the given doctype in your manifest, to be able to use this function. Parameters: documents : an array of objects corresponding to the data you want to save in the cozy doctype (string): the doctype where you want to save data (ex: \u2018io.cozy.bills\u2019) options (object): option object + sourceAccount (String): id of the source account + sourceAccountIdentifier (String): identifier unique to the account targetted by the connector. It is the login most of the time const documents = [ { name : 'toto' , height : 1.8 }, { name : 'titi' , height : 1.7 } ] return addData ( documents , 'io.cozy.height' ) Kind : Exported function cozyClient \u00b6 cozy-client-js instance already initialized and ready to use. cozyClient \u23cf \u00b6 cozy-client-js instance already initialized and ready to use. If you want to access cozy-client-js directly, this method gives you directly an instance of it, initialized according to COZY_URL and COZY_CREDENTIALS environment variable given by cozy-stack You can refer to the cozy-client-js documentation for more information. Example : const { cozyClient } = require ( 'cozy-konnector-libs' ) cozyClient . data . defineIndex ( 'my.doctype' , [ '_id' ]) Kind : Exported constant hydrateAndFilter \u00b6 Filters the passed array from data already present in the cozy so that there is not duplicated data in the Cozy. hydrateAndFilter hydrateAndFilter() \u23cf ~suitableCall() hydrateAndFilter() \u23cf \u00b6 Filters the passed array from data already present in the cozy so that there is not duplicated data in the Cozy. You need at least the GET permission for the given doctype in your manifest, to be able to use this function. Parameters: documents : an array of objects corresponding to the data you want to save in the cozy doctype (string): the doctype where you want to save data (ex: \u2018io.cozy.bills\u2019) options : - keys (array) : List of keys used to check that two items are the same. By default it is set to ['id']'. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Default is built from the keys }}` to get all the records. const documents = [ { name : 'toto' , height : 1.8 }, { name : 'titi' , height : 1.7 } ] return hydrateAndFilter ( documents , 'io.cozy.height' , { keys : [ 'name' ] }). then ( filteredDocuments => addData ( filteredDocuments , 'io.cozy.height' )) Kind : Exported function hydrateAndFilter~suitableCall() \u00b6 Since we can use methods or basic functions for shouldSave and shouldUpdate we pass the appropriate this and arguments . If funcOrMethod is a method, it will be called with args[0] as this and the rest as arguments Otherwise, this will be null and args will be passed as arguments . Kind : inner method of hydrateAndFilter linkBankOperations \u00b6 Finds links between bills and bank operations. linkBankOperations() \u23cf \u00b6 Will soon move to a dedicated service. You should not use it. Finds links between bills and bank operations. Kind : Exported function mkdirp \u00b6 mkdirp \u23cf \u00b6 Creates a directory and its missing ancestors as needed. Options : ...pathComponents : one or many path components to be joined await mkdirp ( '/foo' ) // Creates /foo await mkdirp ( '/foo' ) // Does nothing as /foo already exists await mkdirp ( '/bar/baz' ) // Creates /bar, then /bar/baz await mkdirp ( '/foo/bar/baz' ) // Creates /foo/bar, then /foo/bar/baz, not /foo await mkdirp ( '/' ) // Does nothing await mkdirp ( '/qux' , 'qux2/qux3' , 'qux4' ) // Creates /qux, then /qux/qux2, // then /qux/qux2/qux3 and // finally /qux/qux2/qux3/qux4 The function will automatically add a leading slash when missing: await mkdirp ( 'foo' , 'bar' ) // Creates /foo, then /foo/bar Kind : Exported constant normalizeFilename \u00b6 Returns the given name, replacing characters that could be an issue when used in a filename with spaces. normalizeFilename() \u23cf \u00b6 Returns the given name, replacing characters that could be an issue when used in a filename with spaces. Replaced characters include: Those forbidden on one or many popular OS or filesystem: <>:\"/\\|?* Those forbidden by the cozy-stack \\0 , \\r and \\n Multiple spaces and/or tabs are replaced with a single space Leading & trailing spaces and/or tabs are removed An exception will be thrown in case there is not any filename-compatible character in the given name. Parameters: basename is whatever string you want to generate the filename from ext is an optional file extension, with or without leading dot const { normalizeFilename } = require ( 'cozy-konnector-libs' ) const filename = normalizeFilename ( '*foo/bar: \\\\\"qux\"\\t???' , '.txt' ) // `filename` === `foo bar baz qux.txt` Kind : Exported function saveBills \u00b6 Encapsulates the saving of Bills : saves the files, saves the new data, and associate the files to an existing bank operation saveBills() \u23cf \u00b6 Combines the features of saveFiles , hydrateAndFilter , addData and linkBankOperations for a common case: bills. Will create io.cozy.bills objects. The default deduplication keys are ['date', 'amount', 'vendor'] . You need the full permission on io.cozy.bills , full permission on io.cozy.files and also full permission on io.cozy.bank.operations in your manifest, to be able to use this function. Parameters: documents is an array of objects with any attributes with some mandatory attributes : amount (Number): the amount of the bill used to match bank operations date (Date): the date of the bill also used to match bank operations vendor (String): the name of the vendor associated to the bill. Ex: \u2018trainline\u2019 currency (String) default: EUR: The ISO currency value (not mandatory since there is a default value. contractId (String): Contract unique identicator used to deduplicate bills contractLabel : (String) User label if define, must be used with contractId matchingCriterias (Object): criterias that can be used by an external service to match bills with bank operations. If not specified but the \u2018banksTransactionRegExp\u2019 attribute is specified in the manifest of the connector, this value is automatically added to the bill You can also pass attributes expected by saveFiles : fileurl, filename, requestOptions and more Please take a look at io.cozy.bills doctype documentation - fields (object) this is the first parameter given to BaseKonnector\u2019s constructor - options is passed directly to saveFiles , hydrateAndFilter , addData and linkBankOperations . Kind : Exported function Example const { BaseKonnector , saveBills } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( function fetch ( fields ) { const documents = [] // some code which fills documents return saveBills ( documents , fields , { identifiers : [ 'vendor' ] }) }) saveFiles \u00b6 Saves the given files in the given folder via the Cozy API. saveFiles(entries, fields, options, [contract]) \u23cf \u00b6 Saves the files given in the fileurl attribute of each entries You need the full permission on io.cozy.files in your manifest to use this function. Kind : Exported function Param Type Description entries Array list of object describing files to save entries.fileurl string The url of the file (can be a function returning the value). Ignored if filestream is given entries.fetchFile function the connector can give it\u2019s own function to fetch the file from the website, which will be run only when necessary (if the corresponding file is missing on the cozy) function returning the stream). This function must return a promise resolved as a stream entries.filestream object | string the stream which will be directly passed to cozyClient.files.create (can also be function returning the stream) entries.requestOptions object The options passed to request to fetch fileurl (can be a function returning the value) entries.filename string The file name of the item written on disk. This attribute is optional and as default value, the file name will be \u201csmartly\u201d guessed by the function. Use this attribute if the guess is not smart enough for you, or if you use filestream (can be a function returning the value). entries.shouldReplaceName string used to migrate filename. If saveFiles finds a file linked to this entry and this file name matches shouldReplaceName , the file is renamed to filename (can be a function returning the value) entries.shouldReplaceFile function use this function to state if the current entry should be forced to be redownloaded and replaced. Usefull if we know the file content can change and we always want the last version. entries.fileAttributes object ex: {created_at: new Date()} sets some additionnal file attributes passed to cozyClient.file.create entries.subPath string A subpath to save all files, will be created if needed. entries.contract object contract object associated to the files entries.contract.id string id of the contract entries.contract.name string name of the contract fields object is the argument given to the main function of your connector by the BaseKonnector. It especially contains a folderPath which is the string path configured by the user in collect/home options object global options options.timeout number timestamp which can be used if your connector needs to fetch a lot of files and if the stack does not give enough time to your connector to fetch it all. It could happen that the connector is stopped right in the middle of the download of the file and the file will be broken. With the timeout option, the saveFiles function will check if the timeout has passed right after downloading each file and then will be sure to be stopped cleanly if the timeout is not too long. And since it is really fast to check that a file has already been downloaded, on the next run of the connector, it will be able to download some more files, and so on. If you want the timeout to be in 10s, do Date.now() + 10*1000 . You can try it in the previous code. options.contentType number | boolean ex: \u2018application/pdf\u2019 used to force the contentType of documents when they are badly recognized by cozy. If \u201ctrue\u201d the content type will be recognized from the file name and forced the same way. options.concurrency number default: 1 sets the maximum number of concurrent downloads options.validateFile function default: do not validate if file is empty or has bad mime type options.validateFileContent boolean | function default false. Also check the content of the file to recognize the mime type options.fileIdAttributes Array array of strings : Describes which attributes of files will be taken as primary key for files to check if they already exist, even if they are moved. If not given, the file path will used for deduplication as before. options.subPath string A subpath to save this file, will be created if needed. [contract] object contract object associated to the file [contract.id] string id of the contract [contract.name] string name of the contract options.fetchFile function the connector can give it\u2019s own function to fetch the file from the website, which will be run only when necessary (if the corresponding file is missing on the cozy) function returning the stream). This function must return a promise resolved as a stream options.verboseFilesLog boolean the connector will send saveFiles result as a warning Example await saveFiles ([{ fileurl : 'https://...' , filename : 'bill1.pdf' }], fields , { fileIdAttributes : [ 'fileurl' ] }) saveIdentity \u00b6 Helper to set or merge io.cozy.identities See https://github.com/cozy/cozy-doctypes/blob/master/docs/io.cozy.identities.md saveIdentity() \u23cf \u00b6 Set or merge a io.cozy.identities You need full permission for the doctype io.cozy.identities in your manifest, to be able to use this function. Parameters: identity (object): the identity to create/update as an io.cozy.identities object accountIdentifier (string): a string that represent the account use, if available fields.login options (object): options which will be given to updateOrCreate directly : + sourceAccount (String): id of the source account + sourceAccountIdentifier (String): identifier unique to the account targetted by the connector. It is the login most of the time const { saveIdentity } = require ( 'cozy-konnector-libs' ) const identity = { contact : { name : 'toto' , email : { 'address' : 'toto@example.com' } } } return saveIdentity ( identity , fields . login ) Kind : Exported function signin \u00b6 Provides an handy method to log the user in, on HTML form pages. On success, it resolves to a promise with a parsed body. signin() \u23cf \u00b6 Provides an handy method to log the user in, on HTML form pages. On success, it resolves to a promise with a parsed body. Errors: LOGIN_FAILED if the validate predicate is false INVALID_FORM if the element matched by formSelector is not a form or has no action attribute UNKNOWN_PARSING_STRATEGY if parse is not one of the accepted values: raw , cheerio , json . VENDOR_DOWN if a request throws a RequestError, or StatusCodeError It does not submit values provided through select tags, except if populated by user with formData . url is the url to access the html form formSelector is used by cheerio to uniquely identify the form in which to log in formData is an object { name: value, \u2026 } . It is used to populate the form, in the proper inputs with the same name as the properties of this object, before submitting it. It can also be a function that returns this object. The page at url would be given as argument, right after having been parsed through cheerio . parse allow the user to resolve signin with a preparsed body. The choice of the strategy for the parsing is one of : raw , json or cheerio . cheerio being the default. validate is a predicate taking three arguments statusCode , parsedBody and fullResponse . If it is false, LOGIN_FAILED is thrown, otherwise the signin resolves with parsedBody value. requestOpts allows to pass eventual options to the signin \u2018s requestFactory . It could be useful for pages using latin1 encoding for instance. Kind : Exported function Example == basic example : == const $ = signin ({ url : `http://quotes.toscrape.com/login` , formSelector : 'form' , formData : { username , password } }) If the behavior of the targeted website is not standard. You can pass a validate function which will allow you to: - detect if the credentials work or not -> LOGIN_FAILED - detect if actions from the user are needed -> USER_ACTION_NEEDED - detect if the targeted website is out -> VENDOR_DOWN Example const $ = signin ({ url : `http://quotes.toscrape.com/login` , formSelector : 'form' , formData : { username , password }, validate : ( statusCode , $ , fullResponse ) { if ( statusCode !== 200 ) return false // LOGIN_FAILED if ( $ ( '.cgu' ). length ) throw new Error ( 'USER_ACTION_NEEDED' ) if ( fullResponse . request . uri . href . includes ( 'error' )) throw new Error ( 'VENDOR_DOWN' ) } }) Do not forget that the use of the signin function is not mandatory in a connector and won\u2019t work if the signin page does not use html forms. Here, a simple POST request may be a lot more simple. solveCaptcha \u00b6 Use every possible means to solve a captcha. At the moment, Anticaptcha web service is used if any related secret key is found in COZY_PARAMETERS environment variable. solveCaptcha() \u23cf \u00b6 Use every possible means to solve a captcha. At the moment, Anticaptcha web service is used if any related secret key is found in COZY_PARAMETERS environment variable. If you do not want to solve the captcha each time the connector is run, please also use CookieKonnector which will help you save the session. Parameters: params is an array of objects with any attributes with some mandatory attributes : type (String): (default recaptcha) type of captcha to solve. can be \u201crecaptcha\u201d or \u201cimage\u201d at the moment timeout (Number): (default 3 minutes after now) time when the solver should stop trying to solve the captcha withFullSolution (Boolean): (default false) Change the return to an object containing full solution websiteKey (String): the key you can find on the targeted website (for recaptcha) websiteURL (String): The URL of the page showing the captcha (for recaptcha) body (String): The base64 encoded image (for image captcha) Returns: Promise with the solved captcha response as a string Kind : Exported function Example const { solveCaptcha } = require ( 'cozy-konnector-libs' ) const solvedKey = await solveCaptcha ({ websiteKey : 'the key in the webpage' , websiteURL : 'http://quotes.toscrape.com/login' , }) // now use the solveKey to submit your form updateOrCreate \u00b6 Creates or updates the given entries according to if they already exist in the cozy or not updateOrCreate() \u23cf \u00b6 Creates or updates the given entries according to if they already exist in the cozy or not You need the full permission for the given doctype in your manifest, to be able to use this function. entries (object array): Documents to save doctype (string): Doctype of the documents matchingAttributes (string array): attributes in each entry used to check if an entry already exists in the Cozy options (object): general option affecting metadata : + sourceAccount (String): id of the source account + sourceAccountIdentifier (String): identifier unique to the account targetted by the connector. It is the login most of the time Kind : Exported function utils \u00b6 Small utilities helping to develop konnectors. utils ~fetchAll() ~queryAll() ~findDuplicates() ~batchUpdateAttributes() ~batchDelete() ~getPdfText() ~formatDate() utils~fetchAll() \u00b6 This function allows to fetch all documents for a given doctype. It is the fastest to get all documents but without filtering possibilities deprecated by the findAll method from cozyClient Parameters: doctype (string): the doctype from which you want to fetch the data Kind : inner method of utils utils~queryAll() \u00b6 This function allows to fetch all documents for a given doctype exceeding the 100 limit. It is slower that fetchAll because it fetches the data 100 by 100 but allows to filter the data with a selector and an index Parameters: doctype (string): the doctype from which you want to fetch the data selector (object): the mango query selector index (object): (optional) the query selector index. If not defined, the function will create it\u2019s own index with the keys specified in the selector const documents = await queryAll ( 'io.cozy.bills' , { vendor : 'Direct Energie' }) Kind : inner method of utils utils~findDuplicates() \u00b6 This function find duplicates in a given doctype, filtered by an optional mango selector Parameters: doctype (string): the doctype from which you want to fetch the data selector (object): (optional) the mango query selector options : - keys (array) : List of keys used to check that two items are the same. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Gets all the records by default Returns an object with the following keys: toKeep : this is the list of unique documents that you should keep in db toRemove : this is the list of documents that can remove from db. If this is io.cozy.bills documents, do not forget to clean linked bank operations const { toKeep , toRemove } = await findDuplicates ( 'io.cozy.bills' , { selector : { vendor : 'Direct Energie' }}) Kind : inner method of utils utils~batchUpdateAttributes() \u00b6 This is a shortcut to update multiple documents in one call Parameters: doctype (string): the doctype from which you want to fetch the data ids (array): array of ids of documents to update transformation (object): attributes to change with their values options : - keys (array) : List of keys used to check that two items are the same. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Gets all the records by default Returns a promise which resolves with all the return values of updateAttributes await batchUpdateAttributes ( 'io.cozy.bills' , [ 1 , 2 , 3 ], { vendor : 'Direct Energie' }) Kind : inner method of utils utils~batchDelete() \u00b6 This is a shortcut to delete multiple documents in one call Parameters: doctype (string): the doctype from which you want to fetch the data documents (array): documents to delete with their ids transformation (object): attributes to change with their values options : - keys (array) : List of keys used to check that two items are the same. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Gets all the records by default Returns a promise which resolves with all the return values of updateAttributes Example to remove all the documents for a given doctype const documents = await fetchAll ( 'io.cozy.marvel' ) await batchDelete ( 'io.cozy.marvel' , documents ) Kind : inner method of utils utils~getPdfText() \u00b6 This function can read the content of a cozy pdf file and output its text Parameters: fileId (string): the id of the file in the cozy options : - pages (array or number) : The list of page you want to interpret You need to add pdfjs-dist package as a dependency to your connector to allow this to work Returns a promise which resolves with an object with the following attributes: - text (string) : The full text of the pdf - 1 : The full pdfjs data for page 1 - n : The full pdfjs data for page n Example: const pdfText = ( await getPdfText ( '887ABCFE87687' )). text Kind : inner method of utils utils~formatDate() \u00b6 This function convert a Date Object to a ISO date string (2018-07-31) Parameters: date (Date): the id of the file in the cozy Returns a string Example: const date = formatFrenchDate ( New Date . now ()) Kind : inner method of utils categorization \u00b6 Bank transactions categorization categorization ~createCategorizer(options) \u21d2 Object ~categorize(transactions, options) \u21d2 Array. ~CreateCategorizerOptions categorization~createCategorizer(options) \u21d2 Object \u00b6 Initialize global and local models and return an object exposing a categorize function that applies both models on an array of transactions The global model is a model specific to hosted Cozy instances. It is not available for self-hosted instances. It will just do nothing in that case. The local model is based on the user manual categorizations. Each model adds two properties to the transactions: The global model adds cozyCategoryId and cozyCategoryProba The local model adds localCategoryId and localCategoryProba In the end, each transaction can have up to four different categories. An application can use these categories to show the most significant for the user. See https://github.com/cozy/cozy-doctypes/blob/master/docs/io.cozy.bank.md#categories for more informations. Kind : inner method of categorization Returns : Object - A method to categorize transactions and the classifiers it uses. Param Type Description options CreateCategorizerOptions Options used to build the categorizer Example const { BaseKonnector , createCategorizer } = require ( 'cozy-konnector-libs' ) class BankingKonnector extends BaseKonnector { async saveTransactions () { const transactions = await this . fetchTransactions () const categorizer = await createCategorizer const categorizedTransactions = await categorizer . categorize ( transactions ) // Save categorizedTransactions } } categorization~categorize(transactions, options) \u21d2 Array. \u00b6 Initialize global and local models and categorize the given array of transactions Kind : inner method of categorization Returns : Array. - the categorized transactions See : createCategorizer for more informations about models initialization Param Type Description transactions Array. The transactions to categorize options CreateCategorizerOptions Options passed to create the categorizer Example const { BaseKonnector , categorize } = require ( 'cozy-konnector-libs' ) class BankingKonnector extends BaseKonnector { async saveTransactions () { const transactions = await this . fetchTransactions () const categorizedTransactions = await categorize ( transactions ) // Save categorizedTransactions } } categorization~CreateCategorizerOptions \u00b6 Kind : inner typedef of categorization Properties Name Type Description useGlobalModel boolean Whether to use the globally trained model customTransactionFetcher function A custom training transaction fetcher pretrainedClassifier object A pretrained instance of a bayes classifier BaseKonnector \u00b6 The class from which all the connectors must inherit. It takes a fetch function in parameter that must return a Promise . You need at least the GET permission on io.cozy.accounts in your manifest to allow it to fetch account information for your connector. Its role is twofold : Make the link between account data and konnector Handle errors \u26a0\ufe0f A promise should be returned from the fetch function otherwise the konnector cannot know that asynchronous code has been called. Kind : global class BaseKonnector new BaseKonnector(fetch) .run() .main() \u21d2 Promise .end() .fail() .readPayload() \u21d2 Object | null .initAttributes() .saveAccountData(data, options) \u21d2 Promise .getAccountData() \u21d2 object .updateAccountAttributes() .setTwoFAState(options) .resetTwoFAState() .waitForTwoFaCode(options) \u21d2 Promise .notifySuccessfulLogin() .deactivateAutoSuccessfulLogin() .saveBills() \u21d2 Promise .saveFiles() \u21d2 Promise .updateOrCreate() \u21d2 Promise .saveIdentity() \u21d2 Promise .signin() \u21d2 Promise .terminate(err) .getCozyMetadata(data) new BaseKonnector(fetch) \u00b6 Constructor Param Type Description fetch function Function to be run automatically after account data is fetched. This function will be binded to the current connector. If not fetch function is given. The connector will have to handle itself it\u2019s own exection and error handling Example const { BaseKonnector } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( function fetch () { // use this to access the instance of the konnector to // store any information that needs to be passed to // different stages of the konnector return request ( 'http://ameli.fr' ) . then ( computeReimbursements ) . then ( saveBills ) }) baseKonnector.run() \u00b6 Entrypoint of the konnector Initializes connector attributes Awaits this.main Ensures errors are handled via this.fail Calls this.end when the main function succeeded Kind : instance method of BaseKonnector baseKonnector.main() \u21d2 Promise \u00b6 Main runs after konnector has been initialized. Errors thrown will be automatically handled. Kind : instance method of BaseKonnector Returns : Promise - - The konnector is considered successful when it resolves baseKonnector.end() \u00b6 Hook called when the connector has ended successfully Kind : instance method of BaseKonnector baseKonnector.fail() \u00b6 Hook called when the connector fails Kind : instance method of BaseKonnector baseKonnector.readPayload() \u21d2 Object | null \u00b6 Read an eventual payload from COZY_PAYLOAD env var, wether it is a JSON string or a reference to a file containing a JSON string Kind : instance method of BaseKonnector Returns : Object | null - Promise<> result of JSON.parse from the JSON string or null if no payload baseKonnector.initAttributes() \u00b6 Initializes konnector attributes that will be used during its lifetime this._account this.fields Kind : instance method of BaseKonnector baseKonnector.saveAccountData(data, options) \u21d2 Promise \u00b6 Saves data to the account that is passed to the konnector. Use it to persist data that needs to be passed to each konnector run. By default, the data is merged to the remote data, use options.merge = false to overwrite the data. The data is saved under the .data attribute of the cozy account. Don\u2019t forget to modify the manifest.konnector file to give the right to write on the io.cozy.accounts doctype. The syntax can be : \"permissions\": {\"accounts\": {\"type\": \"io.cozy.accounts\"}} (here we juste removed the verb GET ) Kind : instance method of BaseKonnector Returns : Promise - : resolved with the modified account Param Type Description data object Attributes to be merged options object { merge: true baseKonnector.getAccountData() \u21d2 object \u00b6 Get the data saved by saveAccountData Kind : instance method of BaseKonnector Returns : object - the account data baseKonnector.updateAccountAttributes() \u00b6 Update account attributes and cache the account Kind : instance method of BaseKonnector baseKonnector.setTwoFAState(options) \u00b6 Sets the 2FA state, according to the type passed. Doing so resets the twoFACode field Typically you should not use that directly, prefer to use waitForTwoFaCode since the wait for user input will be handled for you. It is useful though for the \u201capp\u201d type where no user input (inside Cozy) is needed. Kind : instance method of BaseKonnector Param Type Description options object The list of options options.type string Used by the front to show the right message (email/sms/app/app_code) options.retry boolean Is this function call a retry ? This changes the resulting message to the user baseKonnector.resetTwoFAState() \u00b6 Resets 2FA state when not needed anymore Kind : instance method of BaseKonnector baseKonnector.waitForTwoFaCode(options) \u21d2 Promise \u00b6 Notices that 2FA code is needed and wait for the user to submit it. It uses the account to do the communication with the user. Kind : instance method of BaseKonnector Returns : Promise - Contains twoFa code entered by user Throws : Will throw USER_ACTION_NEEDED.TWOFA_EXPIRED if the konnector job is not run manually (we assume that not run manually means that we do not have a graphic interface to fill the required information) Will throw USER_ACTION_NEEDED.TWOFA_EXPIRED if 2FA is not filled by the user soon enough Param Type Description options object The list of options options.type string (default: \u201cemail\u201d) - Type of the expected 2FA code. The message displayed to the user will depend on it. Possible values: email, sms options.timeout number (default 3 minutes after now) - After this date, the stop will stop waiting and and an error will be shown to the user (deprecated and alias of endTime) options.endTime number (default 3 minutes after now) - After this timestamp, the home will stop waiting and and an error will be shown to the user options.heartBeat number (default: 5000) - How many milliseconds between each code check options.retry boolean (default: false) - Is it a retry. If true, an error message will be displayed to the user Example const { BaseKonnector } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( start ) async function start () { // we detect the need of a 2FA code const code = this . waitForTwoFaCode ({ type : 'email' }) // send the code to the targeted site } baseKonnector.notifySuccessfulLogin() \u00b6 Tells Cozy-Home that we have successfully logged in. Useful when auto-success has been deactivated. See deactivateAutoSuccess Kind : instance method of BaseKonnector baseKonnector.deactivateAutoSuccessfulLogin() \u00b6 By default, cozy-home considers that the konnector has successfully logged in when the konnector has run for more than 8s. This is problematic for 2FA since the konnector can sit idle, just waiting for the 2FA to come back. When this method is called, cozy-home is notified and will not consider the absence of error after 8s to be a success. Afterwards, to notify cozy-home when the user has logged in successfully, for example, after the user has entered 2FA codes, it is necessary to call notifySuccessfulLogin . Does nothing if called more than once. Kind : instance method of BaseKonnector baseKonnector.saveBills() \u21d2 Promise \u00b6 This is saveBills function from cozy-konnector-libs which automatically adds sourceAccount in metadata of each entry Kind : instance method of BaseKonnector Returns : Promise - resolves with entries hydrated with db data baseKonnector.saveFiles() \u21d2 Promise \u00b6 This is saveFiles function from cozy-konnector-libs which automatically adds sourceAccount and sourceAccountIdentifier cozyMetadatas to files Kind : instance method of BaseKonnector Returns : Promise - resolves with the list of entries with file objects baseKonnector.updateOrCreate() \u21d2 Promise \u00b6 This is updateOrCreate function from cozy-konnector-libs which automatically adds sourceAccount in metadata of each entry Kind : instance method of BaseKonnector Returns : Promise - resolves to an array of db objects baseKonnector.saveIdentity() \u21d2 Promise \u00b6 This is saveIdentity function from cozy-konnector-libs which automatically adds sourceAccount in metadata of each entry Kind : instance method of BaseKonnector Returns : Promise - empty promise baseKonnector.signin() \u21d2 Promise \u00b6 This is signin function from cozy-konnector-libs which automatically adds deactivateAutoSuccessfulLogin and notifySuccessfulLogin calls Kind : instance method of BaseKonnector Returns : Promise - resolve with an object containing form data baseKonnector.terminate(err) \u00b6 Send a special error code which is interpreted by the cozy stack to terminate the execution of the connector now Kind : instance method of BaseKonnector Param Type Description err string The error code to be saved as connector result see [docs/ERROR_CODES.md] Example this . terminate ( 'LOGIN_FAILED' ) baseKonnector.getCozyMetadata(data) \u00b6 Get cozyMetaData from the context of the connector Kind : instance method of BaseKonnector Param Type Description data object this data will be merged with cozyMetaData CookieKonnector \u00b6 Connector base class extending BaseKonnector which handles cookie session in a central way It also handles saving cookie session in the account and automatically restore it for the next connector run. All cozy-konnector-libs tools using request are proposed as methods of this class to force them to use the central cookie which can be saved/restored. You need at least the GET and PUT permissions on io.cozy.accounts in your manifest to allow it to save/restore cookies Kind : global class CookieKonnector new CookieKonnector(requestFactoryOptions) .initAttributes() \u21d2 Promise .end() .requestFactory(options) \u21d2 object .resetSession() \u21d2 Promise .initSession() \u21d2 Promise .saveSession() \u21d2 Promise .signin() \u21d2 Promise .saveFiles() \u21d2 Promise .saveBills() \u21d2 Promise new CookieKonnector(requestFactoryOptions) \u00b6 Constructor Param Type Description requestFactoryOptions function Option object passed to requestFactory to initialize this.request. It is still possible to change this.request doing : javascript this.request = this.requestFactory(...) Please not you have to run the connector yourself doing : javascript connector.run() Example const { CookieKonnector } = require ( 'cozy-konnector-libs' ) class MyConnector extends CookieKonnector { async fetch ( fields ) { // the code of your connector await this . request ( 'https://...' ) } async testSession () { const $ = await this . request ( 'https://...' ) return $ ( '' ) } } const connector = new MyKonnector ({ cheerio : true , json : false }) connector . run () cookieKonnector.initAttributes() \u21d2 Promise \u00b6 Initializes the current connector with data coming from the associated account and also the session Kind : instance method of CookieKonnector Returns : Promise - with the fields as an object cookieKonnector.end() \u00b6 Hook called when the connector is ended Kind : instance method of CookieKonnector cookieKonnector.requestFactory(options) \u21d2 object \u00b6 Calls cozy-konnector-libs requestFactory forcing this._jar as the cookie Kind : instance method of CookieKonnector Returns : object - - The resulting request object Param Type Description options object requestFactory option cookieKonnector.resetSession() \u21d2 Promise \u00b6 Reset cookie session with a new empty session and save it to the associated account Kind : instance method of CookieKonnector Returns : Promise - empty promise cookieKonnector.initSession() \u21d2 Promise \u00b6 Get the cookie session from the account if any Kind : instance method of CookieKonnector Returns : Promise - true or false if the session in the account exists or not cookieKonnector.saveSession() \u21d2 Promise \u00b6 Saves the current cookie session to the account Kind : instance method of CookieKonnector Returns : Promise - empty promise cookieKonnector.signin() \u21d2 Promise \u00b6 This is signin function from cozy-konnector-libs which is forced to use the current cookies and current request from CookieKonnector. It also automatically saves the session after signin if it is a success. Kind : instance method of CookieKonnector Returns : Promise - resolve with an object containing form data cookieKonnector.saveFiles() \u21d2 Promise \u00b6 This is saveFiles function from cozy-konnector-libs which is forced to use the current cookies and current request from CookieKonnector. Kind : instance method of CookieKonnector Returns : Promise - resolves with the list of entries with file objects cookieKonnector.saveBills() \u21d2 Promise \u00b6 This is saveBills function from cozy-konnector-libs which is forced to use the current cookies and current request from CookieKonnector. Kind : instance method of CookieKonnector Returns : Promise - resolves with entries hydrated with db data Document \u00b6 Simple Model for Documents. Allows to specify shouldSave , shouldUpdate as methods. Has useful isEqual method Kind : global class document.isEqual() \u00b6 Compares to another document deeply. _id and _rev are by default ignored in the comparison. By default, will compare dates loosely since you often compare existing documents (dates in ISO string) with documents that just have been scraped where dates are Date s. Kind : instance method of Document fs \u00b6 Manifest is provided differently in developement that in production. In production, the manifest has been \u201cmerged\u201d via Webpack via the DefinePlugin In development/test, we simply read the manifest from the fs Kind : global constant LOGIN_FAILED : string \u00b6 The konnector could not login Kind : global constant NOT_EXISTING_DIRECTORY : string \u00b6 The folder specified as folder_to_save does not exist (checked by BaseKonnector) Kind : global constant VENDOR_DOWN : string \u00b6 The vendor\u2019s website is down Kind : global constant USER_ACTION_NEEDED : string \u00b6 There was an unexpected error, please take a look at the logs to know what happened Kind : global constant FILE_DOWNLOAD_FAILED : string \u00b6 There was a problem while downloading a file Kind : global constant SAVE_FILE_FAILED : string \u00b6 There was a problem while saving a file Kind : global constant DISK_QUOTA_EXCEEDED : string \u00b6 Could not save a file to the cozy because of disk quota exceeded Kind : global constant CHALLENGE_ASKED : string \u00b6 It seems that the website requires a second authentification factor that we don\u2019t support yet. Kind : global constant LOGIN_FAILED_TOO_MANY_ATTEMPTS : string \u00b6 Temporarily blocked Kind : global constant USER_ACTION_NEEDED_OAUTH_OUTDATED : string \u00b6 Access refresh required Kind : global constant USER_ACTION_NEEDED_ACCOUNT_REMOVED : string \u00b6 Unavailable account Kind : global constant USER_ACTION_NEEDED_CHANGE_PASSWORD : string \u00b6 Unavailable account Kind : global constant USER_ACTION_NEEDED_PERMISSIONS_CHANGED : string \u00b6 Password update required Kind : global constant USER_ACTION_NEEDED_CGU_FORM : string \u00b6 The user needs to accept a CGU form before accessing the rest of the website Kind : global constant CAPTCHA_RESOLUTION_FAILED : string \u00b6 solveCaptcha failed to solve the captcha Kind : global constant LOGIN_FAILED_NEEDS_SECRET : string \u00b6 Additionnal information is needed to check your login details Kind : global constant MAINTENANCE : string \u00b6 remote website seems to be unavailable Kind : global constant TERMS_VERSION_MISMATCH : string \u00b6 User needs to accept new terms Kind : global constant UNKNOWN_ERROR : string \u00b6 unkown error Kind : global constant UNKNOWN_ERROR_PARTIAL_SYNC : string \u00b6 The synchronization is complete but some elements may be missing Kind : global constant USER_ACTION_NEEDED_SCA_REQUIRED : string \u00b6 Renewal of authentication required Kind : global constant USER_ACTION_NEEDED_TWOFA_EXPIRED : string \u00b6 Authentication renewal required Kind : global constant USER_ACTION_NEEDED_WEBAUTH_REQUIRED : string \u00b6 Authentication on vendor website required Kind : global constant USER_ACTION_NEEDED_WRONG_TWOFA_CODE : string \u00b6 Incorrect strong authentication code Kind : global constant VENDOR_DOWN_BANK_DOWN : string \u00b6 Unavailable bank website Kind : global constant VENDOR_DOWN_LINXO_DOWN : string \u00b6 Unavailable bank website Kind : global constant attachProcessEventHandlers(prcs) \u21d2 function \u00b6 Attach event handlers to catch uncaught exceptions/rejections and signals. Log them as critical and exit the process accordingly. If the cleanup function has not been called, calling again the function is a no-op. Kind : global function Returns : function - When called, removes the signal handlers Param Type Description prcs object Process object, default to current process mkSpec() \u00b6 Declarative scraping. Describe your items attributes and where to find/parse them instead of imperatively building them. Heavily inspired by artoo scraping method. Kind : global function scrape($, specs, [childSelector]) \u21d2 object | Array \u00b6 Scrape a cheerio object for properties Kind : global function Returns : object | Array - - Item(s) scraped Param Type Description $ object Cheerio node which will be scraped specs object | string Options object describing what you want to scrape [childSelector] string If passed, scrape will return an array of items Example scrape can be used to declaratively extract data : For one object : const item = scrape($('#item'), { title: '.title', content: '.content' }) For a list of objects : const items = scrape($('#content'), { title: '.title', content: '.content' }, '.item') For more power, you can use object s for each retriever : const items = scrape($('#content'), { title: '.title', content: '.content', link: { sel: 'a', attr: 'href' }, }, '.item') Here the href attribute of the a inside .item s would have been put into the link attribute of the items returned by scrape . Available options : sel : the CSS selector used to target the HTML node from which data will be scraped attr : the HTML attribute from which to extract data parse : function applied to the value extracted ( { sel: '.price', parse: parseAmount } ) fn : if you need something more complicated than attr , you can use this function, it receives the complete DOM node. { sel: '.person', fn: $node => $node.attr('data-name') + $node.attr('data-firstname') } \u26a0 Permissions \u00b6 Please note that some classes require some permissions: io.cozy.accounts for the BaseKonnector class ( GET only) io.cozy.files to save files io.cozy.bills to save bills io.cozy.bank.operations for linkBankOperations", "title": "API"}, {"location": "cozy-konnector-libs/api/#api", "text": "", "title": "API"}, {"location": "cozy-konnector-libs/api/#modules", "text": "CozyBrowser Get a javascript simulation of a real browser (jsdom) addData Saves the data into the cozy blindly without check. cozyClient cozy-client-js instance already initialized and ready to use. hydrateAndFilter Filters the passed array from data already present in the cozy so that there is not duplicated data in the Cozy. linkBankOperations Finds links between bills and bank operations. mkdirp normalizeFilename Returns the given name, replacing characters that could be an issue when used in a filename with spaces. saveBills Encapsulates the saving of Bills : saves the files, saves the new data, and associate the files to an existing bank operation saveFiles Saves the given files in the given folder via the Cozy API. saveIdentity Helper to set or merge io.cozy.identities See https://github.com/cozy/cozy-doctypes/blob/master/docs/io.cozy.identities.md signin Provides an handy method to log the user in, on HTML form pages. On success, it resolves to a promise with a parsed body. solveCaptcha Use every possible means to solve a captcha. At the moment, Anticaptcha web service is used if any related secret key is found in COZY_PARAMETERS environment variable. updateOrCreate Creates or updates the given entries according to if they already exist in the cozy or not utils Small utilities helping to develop konnectors. categorization Bank transactions categorization", "title": "Modules"}, {"location": "cozy-konnector-libs/api/#classes", "text": "BaseKonnector The class from which all the connectors must inherit. It takes a fetch function in parameter that must return a Promise . You need at least the GET permission on io.cozy.accounts in your manifest to allow it to fetch account information for your connector. Its role is twofold : Make the link between account data and konnector Handle errors \u26a0\ufe0f A promise should be returned from the fetch function otherwise the konnector cannot know that asynchronous code has been called. CookieKonnector Connector base class extending BaseKonnector which handles cookie session in a central way It also handles saving cookie session in the account and automatically restore it for the next connector run. All cozy-konnector-libs tools using request are proposed as methods of this class to force them to use the central cookie which can be saved/restored. You need at least the GET and PUT permissions on io.cozy.accounts in your manifest to allow it to save/restore cookies Document Simple Model for Documents. Allows to specify shouldSave , shouldUpdate as methods. Has useful isEqual method", "title": "Classes"}, {"location": "cozy-konnector-libs/api/#constants", "text": "fs Manifest is provided differently in developement that in production. In production, the manifest has been \"merged\" via Webpack via the DefinePlugin In development/test, we simply read the manifest from the fs LOGIN_FAILED : string The konnector could not login NOT_EXISTING_DIRECTORY : string The folder specified as folder_to_save does not exist (checked by BaseKonnector) VENDOR_DOWN : string The vendor's website is down USER_ACTION_NEEDED : string There was an unexpected error, please take a look at the logs to know what happened FILE_DOWNLOAD_FAILED : string There was a problem while downloading a file SAVE_FILE_FAILED : string There was a problem while saving a file DISK_QUOTA_EXCEEDED : string Could not save a file to the cozy because of disk quota exceeded CHALLENGE_ASKED : string It seems that the website requires a second authentification factor that we don\u2019t support yet. LOGIN_FAILED_TOO_MANY_ATTEMPTS : string Temporarily blocked USER_ACTION_NEEDED_OAUTH_OUTDATED : string Access refresh required USER_ACTION_NEEDED_ACCOUNT_REMOVED : string Unavailable account USER_ACTION_NEEDED_CHANGE_PASSWORD : string Unavailable account USER_ACTION_NEEDED_PERMISSIONS_CHANGED : string Password update required USER_ACTION_NEEDED_CGU_FORM : string The user needs to accept a CGU form before accessing the rest of the website CAPTCHA_RESOLUTION_FAILED : string solveCaptcha failed to solve the captcha LOGIN_FAILED_NEEDS_SECRET : string Additionnal information is needed to check your login details MAINTENANCE : string remote website seems to be unavailable TERMS_VERSION_MISMATCH : string User needs to accept new terms UNKNOWN_ERROR : string unkown error UNKNOWN_ERROR_PARTIAL_SYNC : string The synchronization is complete but some elements may be missing USER_ACTION_NEEDED_SCA_REQUIRED : string Renewal of authentication required USER_ACTION_NEEDED_TWOFA_EXPIRED : string Authentication renewal required USER_ACTION_NEEDED_WEBAUTH_REQUIRED : string Authentication on vendor website required USER_ACTION_NEEDED_WRONG_TWOFA_CODE : string Incorrect strong authentication code VENDOR_DOWN_BANK_DOWN : string Unavailable bank website VENDOR_DOWN_LINXO_DOWN : string Unavailable bank website", "title": "Constants"}, {"location": "cozy-konnector-libs/api/#functions", "text": "attachProcessEventHandlers(prcs) \u21d2 function Attach event handlers to catch uncaught exceptions/rejections and signals. Log them as critical and exit the process accordingly. If the cleanup function has not been called, calling again the function is a no-op. mkSpec() Declarative scraping. Describe your items attributes and where to find/parse them instead of imperatively building them. Heavily inspired by artoo scraping method. scrape($, specs, [childSelector]) \u21d2 object | Array Scrape a cheerio object for properties", "title": "Functions"}, {"location": "cozy-konnector-libs/api/#cozybrowser", "text": "Get a javascript simulation of a real browser (jsdom) CozyBrowser defaultOptions \u21d2 object \u23cf ~addListeners()", "title": "CozyBrowser"}, {"location": "cozy-konnector-libs/api/#defaultoptions-object", "text": "Get a preconfigured jsdom browser simulator using the zombie npm package See http://zombie.js.org/ for complete documentation The connector has to import the zombie npm package itself. Kind : Exported constant Returns : object - Zombie browser extended class Param Type Description options.userAgent string The user agent string used by the browser Example const Browser = require ( 'cozy-konnector-libs/libs/CozyBrowser' ) const browser = new Browser () await browser . visit ( 'http://quotes.toscrape.com/' )", "title": "defaultOptions \u21d2 object \u23cf"}, {"location": "cozy-konnector-libs/api/#defaultoptionsaddlisteners", "text": "Add cozy-konnector-libs specific logs to browser events Kind : inner method of defaultOptions", "title": "defaultOptions~addListeners()"}, {"location": "cozy-konnector-libs/api/#adddata", "text": "Saves the data into the cozy blindly without check.", "title": "addData"}, {"location": "cozy-konnector-libs/api/#adddata_1", "text": "Saves the data into the cozy blindly without check. You need at least the POST permission for the given doctype in your manifest, to be able to use this function. Parameters: documents : an array of objects corresponding to the data you want to save in the cozy doctype (string): the doctype where you want to save data (ex: \u2018io.cozy.bills\u2019) options (object): option object + sourceAccount (String): id of the source account + sourceAccountIdentifier (String): identifier unique to the account targetted by the connector. It is the login most of the time const documents = [ { name : 'toto' , height : 1.8 }, { name : 'titi' , height : 1.7 } ] return addData ( documents , 'io.cozy.height' ) Kind : Exported function", "title": "addData() \u23cf"}, {"location": "cozy-konnector-libs/api/#cozyclient", "text": "cozy-client-js instance already initialized and ready to use.", "title": "cozyClient"}, {"location": "cozy-konnector-libs/api/#cozyclient_1", "text": "cozy-client-js instance already initialized and ready to use. If you want to access cozy-client-js directly, this method gives you directly an instance of it, initialized according to COZY_URL and COZY_CREDENTIALS environment variable given by cozy-stack You can refer to the cozy-client-js documentation for more information. Example : const { cozyClient } = require ( 'cozy-konnector-libs' ) cozyClient . data . defineIndex ( 'my.doctype' , [ '_id' ]) Kind : Exported constant", "title": "cozyClient \u23cf"}, {"location": "cozy-konnector-libs/api/#hydrateandfilter", "text": "Filters the passed array from data already present in the cozy so that there is not duplicated data in the Cozy. hydrateAndFilter hydrateAndFilter() \u23cf ~suitableCall()", "title": "hydrateAndFilter"}, {"location": "cozy-konnector-libs/api/#hydrateandfilter_1", "text": "Filters the passed array from data already present in the cozy so that there is not duplicated data in the Cozy. You need at least the GET permission for the given doctype in your manifest, to be able to use this function. Parameters: documents : an array of objects corresponding to the data you want to save in the cozy doctype (string): the doctype where you want to save data (ex: \u2018io.cozy.bills\u2019) options : - keys (array) : List of keys used to check that two items are the same. By default it is set to ['id']'. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Default is built from the keys }}` to get all the records. const documents = [ { name : 'toto' , height : 1.8 }, { name : 'titi' , height : 1.7 } ] return hydrateAndFilter ( documents , 'io.cozy.height' , { keys : [ 'name' ] }). then ( filteredDocuments => addData ( filteredDocuments , 'io.cozy.height' )) Kind : Exported function", "title": "hydrateAndFilter() \u23cf"}, {"location": "cozy-konnector-libs/api/#hydrateandfiltersuitablecall", "text": "Since we can use methods or basic functions for shouldSave and shouldUpdate we pass the appropriate this and arguments . If funcOrMethod is a method, it will be called with args[0] as this and the rest as arguments Otherwise, this will be null and args will be passed as arguments . Kind : inner method of hydrateAndFilter", "title": "hydrateAndFilter~suitableCall()"}, {"location": "cozy-konnector-libs/api/#linkbankoperations", "text": "Finds links between bills and bank operations.", "title": "linkBankOperations"}, {"location": "cozy-konnector-libs/api/#linkbankoperations_1", "text": "Will soon move to a dedicated service. You should not use it. Finds links between bills and bank operations. Kind : Exported function", "title": "linkBankOperations() \u23cf"}, {"location": "cozy-konnector-libs/api/#mkdirp", "text": "", "title": "mkdirp"}, {"location": "cozy-konnector-libs/api/#mkdirp_1", "text": "Creates a directory and its missing ancestors as needed. Options : ...pathComponents : one or many path components to be joined await mkdirp ( '/foo' ) // Creates /foo await mkdirp ( '/foo' ) // Does nothing as /foo already exists await mkdirp ( '/bar/baz' ) // Creates /bar, then /bar/baz await mkdirp ( '/foo/bar/baz' ) // Creates /foo/bar, then /foo/bar/baz, not /foo await mkdirp ( '/' ) // Does nothing await mkdirp ( '/qux' , 'qux2/qux3' , 'qux4' ) // Creates /qux, then /qux/qux2, // then /qux/qux2/qux3 and // finally /qux/qux2/qux3/qux4 The function will automatically add a leading slash when missing: await mkdirp ( 'foo' , 'bar' ) // Creates /foo, then /foo/bar Kind : Exported constant", "title": "mkdirp \u23cf"}, {"location": "cozy-konnector-libs/api/#normalizefilename", "text": "Returns the given name, replacing characters that could be an issue when used in a filename with spaces.", "title": "normalizeFilename"}, {"location": "cozy-konnector-libs/api/#normalizefilename_1", "text": "Returns the given name, replacing characters that could be an issue when used in a filename with spaces. Replaced characters include: Those forbidden on one or many popular OS or filesystem: <>:\"/\\|?* Those forbidden by the cozy-stack \\0 , \\r and \\n Multiple spaces and/or tabs are replaced with a single space Leading & trailing spaces and/or tabs are removed An exception will be thrown in case there is not any filename-compatible character in the given name. Parameters: basename is whatever string you want to generate the filename from ext is an optional file extension, with or without leading dot const { normalizeFilename } = require ( 'cozy-konnector-libs' ) const filename = normalizeFilename ( '*foo/bar: \\\\\"qux\"\\t???' , '.txt' ) // `filename` === `foo bar baz qux.txt` Kind : Exported function", "title": "normalizeFilename() \u23cf"}, {"location": "cozy-konnector-libs/api/#savebills", "text": "Encapsulates the saving of Bills : saves the files, saves the new data, and associate the files to an existing bank operation", "title": "saveBills"}, {"location": "cozy-konnector-libs/api/#savebills_1", "text": "Combines the features of saveFiles , hydrateAndFilter , addData and linkBankOperations for a common case: bills. Will create io.cozy.bills objects. The default deduplication keys are ['date', 'amount', 'vendor'] . You need the full permission on io.cozy.bills , full permission on io.cozy.files and also full permission on io.cozy.bank.operations in your manifest, to be able to use this function. Parameters: documents is an array of objects with any attributes with some mandatory attributes : amount (Number): the amount of the bill used to match bank operations date (Date): the date of the bill also used to match bank operations vendor (String): the name of the vendor associated to the bill. Ex: \u2018trainline\u2019 currency (String) default: EUR: The ISO currency value (not mandatory since there is a default value. contractId (String): Contract unique identicator used to deduplicate bills contractLabel : (String) User label if define, must be used with contractId matchingCriterias (Object): criterias that can be used by an external service to match bills with bank operations. If not specified but the \u2018banksTransactionRegExp\u2019 attribute is specified in the manifest of the connector, this value is automatically added to the bill You can also pass attributes expected by saveFiles : fileurl, filename, requestOptions and more Please take a look at io.cozy.bills doctype documentation - fields (object) this is the first parameter given to BaseKonnector\u2019s constructor - options is passed directly to saveFiles , hydrateAndFilter , addData and linkBankOperations . Kind : Exported function Example const { BaseKonnector , saveBills } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( function fetch ( fields ) { const documents = [] // some code which fills documents return saveBills ( documents , fields , { identifiers : [ 'vendor' ] }) })", "title": "saveBills() \u23cf"}, {"location": "cozy-konnector-libs/api/#savefiles", "text": "Saves the given files in the given folder via the Cozy API.", "title": "saveFiles"}, {"location": "cozy-konnector-libs/api/#savefilesentries-fields-options-contract", "text": "Saves the files given in the fileurl attribute of each entries You need the full permission on io.cozy.files in your manifest to use this function. Kind : Exported function Param Type Description entries Array list of object describing files to save entries.fileurl string The url of the file (can be a function returning the value). Ignored if filestream is given entries.fetchFile function the connector can give it\u2019s own function to fetch the file from the website, which will be run only when necessary (if the corresponding file is missing on the cozy) function returning the stream). This function must return a promise resolved as a stream entries.filestream object | string the stream which will be directly passed to cozyClient.files.create (can also be function returning the stream) entries.requestOptions object The options passed to request to fetch fileurl (can be a function returning the value) entries.filename string The file name of the item written on disk. This attribute is optional and as default value, the file name will be \u201csmartly\u201d guessed by the function. Use this attribute if the guess is not smart enough for you, or if you use filestream (can be a function returning the value). entries.shouldReplaceName string used to migrate filename. If saveFiles finds a file linked to this entry and this file name matches shouldReplaceName , the file is renamed to filename (can be a function returning the value) entries.shouldReplaceFile function use this function to state if the current entry should be forced to be redownloaded and replaced. Usefull if we know the file content can change and we always want the last version. entries.fileAttributes object ex: {created_at: new Date()} sets some additionnal file attributes passed to cozyClient.file.create entries.subPath string A subpath to save all files, will be created if needed. entries.contract object contract object associated to the files entries.contract.id string id of the contract entries.contract.name string name of the contract fields object is the argument given to the main function of your connector by the BaseKonnector. It especially contains a folderPath which is the string path configured by the user in collect/home options object global options options.timeout number timestamp which can be used if your connector needs to fetch a lot of files and if the stack does not give enough time to your connector to fetch it all. It could happen that the connector is stopped right in the middle of the download of the file and the file will be broken. With the timeout option, the saveFiles function will check if the timeout has passed right after downloading each file and then will be sure to be stopped cleanly if the timeout is not too long. And since it is really fast to check that a file has already been downloaded, on the next run of the connector, it will be able to download some more files, and so on. If you want the timeout to be in 10s, do Date.now() + 10*1000 . You can try it in the previous code. options.contentType number | boolean ex: \u2018application/pdf\u2019 used to force the contentType of documents when they are badly recognized by cozy. If \u201ctrue\u201d the content type will be recognized from the file name and forced the same way. options.concurrency number default: 1 sets the maximum number of concurrent downloads options.validateFile function default: do not validate if file is empty or has bad mime type options.validateFileContent boolean | function default false. Also check the content of the file to recognize the mime type options.fileIdAttributes Array array of strings : Describes which attributes of files will be taken as primary key for files to check if they already exist, even if they are moved. If not given, the file path will used for deduplication as before. options.subPath string A subpath to save this file, will be created if needed. [contract] object contract object associated to the file [contract.id] string id of the contract [contract.name] string name of the contract options.fetchFile function the connector can give it\u2019s own function to fetch the file from the website, which will be run only when necessary (if the corresponding file is missing on the cozy) function returning the stream). This function must return a promise resolved as a stream options.verboseFilesLog boolean the connector will send saveFiles result as a warning Example await saveFiles ([{ fileurl : 'https://...' , filename : 'bill1.pdf' }], fields , { fileIdAttributes : [ 'fileurl' ] })", "title": "saveFiles(entries, fields, options, [contract]) \u23cf"}, {"location": "cozy-konnector-libs/api/#saveidentity", "text": "Helper to set or merge io.cozy.identities See https://github.com/cozy/cozy-doctypes/blob/master/docs/io.cozy.identities.md", "title": "saveIdentity"}, {"location": "cozy-konnector-libs/api/#saveidentity_1", "text": "Set or merge a io.cozy.identities You need full permission for the doctype io.cozy.identities in your manifest, to be able to use this function. Parameters: identity (object): the identity to create/update as an io.cozy.identities object accountIdentifier (string): a string that represent the account use, if available fields.login options (object): options which will be given to updateOrCreate directly : + sourceAccount (String): id of the source account + sourceAccountIdentifier (String): identifier unique to the account targetted by the connector. It is the login most of the time const { saveIdentity } = require ( 'cozy-konnector-libs' ) const identity = { contact : { name : 'toto' , email : { 'address' : 'toto@example.com' } } } return saveIdentity ( identity , fields . login ) Kind : Exported function", "title": "saveIdentity() \u23cf"}, {"location": "cozy-konnector-libs/api/#signin", "text": "Provides an handy method to log the user in, on HTML form pages. On success, it resolves to a promise with a parsed body.", "title": "signin"}, {"location": "cozy-konnector-libs/api/#signin_1", "text": "Provides an handy method to log the user in, on HTML form pages. On success, it resolves to a promise with a parsed body. Errors: LOGIN_FAILED if the validate predicate is false INVALID_FORM if the element matched by formSelector is not a form or has no action attribute UNKNOWN_PARSING_STRATEGY if parse is not one of the accepted values: raw , cheerio , json . VENDOR_DOWN if a request throws a RequestError, or StatusCodeError It does not submit values provided through select tags, except if populated by user with formData . url is the url to access the html form formSelector is used by cheerio to uniquely identify the form in which to log in formData is an object { name: value, \u2026 } . It is used to populate the form, in the proper inputs with the same name as the properties of this object, before submitting it. It can also be a function that returns this object. The page at url would be given as argument, right after having been parsed through cheerio . parse allow the user to resolve signin with a preparsed body. The choice of the strategy for the parsing is one of : raw , json or cheerio . cheerio being the default. validate is a predicate taking three arguments statusCode , parsedBody and fullResponse . If it is false, LOGIN_FAILED is thrown, otherwise the signin resolves with parsedBody value. requestOpts allows to pass eventual options to the signin \u2018s requestFactory . It could be useful for pages using latin1 encoding for instance. Kind : Exported function Example == basic example : == const $ = signin ({ url : `http://quotes.toscrape.com/login` , formSelector : 'form' , formData : { username , password } }) If the behavior of the targeted website is not standard. You can pass a validate function which will allow you to: - detect if the credentials work or not -> LOGIN_FAILED - detect if actions from the user are needed -> USER_ACTION_NEEDED - detect if the targeted website is out -> VENDOR_DOWN Example const $ = signin ({ url : `http://quotes.toscrape.com/login` , formSelector : 'form' , formData : { username , password }, validate : ( statusCode , $ , fullResponse ) { if ( statusCode !== 200 ) return false // LOGIN_FAILED if ( $ ( '.cgu' ). length ) throw new Error ( 'USER_ACTION_NEEDED' ) if ( fullResponse . request . uri . href . includes ( 'error' )) throw new Error ( 'VENDOR_DOWN' ) } }) Do not forget that the use of the signin function is not mandatory in a connector and won\u2019t work if the signin page does not use html forms. Here, a simple POST request may be a lot more simple.", "title": "signin() \u23cf"}, {"location": "cozy-konnector-libs/api/#solvecaptcha", "text": "Use every possible means to solve a captcha. At the moment, Anticaptcha web service is used if any related secret key is found in COZY_PARAMETERS environment variable.", "title": "solveCaptcha"}, {"location": "cozy-konnector-libs/api/#solvecaptcha_1", "text": "Use every possible means to solve a captcha. At the moment, Anticaptcha web service is used if any related secret key is found in COZY_PARAMETERS environment variable. If you do not want to solve the captcha each time the connector is run, please also use CookieKonnector which will help you save the session. Parameters: params is an array of objects with any attributes with some mandatory attributes : type (String): (default recaptcha) type of captcha to solve. can be \u201crecaptcha\u201d or \u201cimage\u201d at the moment timeout (Number): (default 3 minutes after now) time when the solver should stop trying to solve the captcha withFullSolution (Boolean): (default false) Change the return to an object containing full solution websiteKey (String): the key you can find on the targeted website (for recaptcha) websiteURL (String): The URL of the page showing the captcha (for recaptcha) body (String): The base64 encoded image (for image captcha) Returns: Promise with the solved captcha response as a string Kind : Exported function Example const { solveCaptcha } = require ( 'cozy-konnector-libs' ) const solvedKey = await solveCaptcha ({ websiteKey : 'the key in the webpage' , websiteURL : 'http://quotes.toscrape.com/login' , }) // now use the solveKey to submit your form", "title": "solveCaptcha() \u23cf"}, {"location": "cozy-konnector-libs/api/#updateorcreate", "text": "Creates or updates the given entries according to if they already exist in the cozy or not", "title": "updateOrCreate"}, {"location": "cozy-konnector-libs/api/#updateorcreate_1", "text": "Creates or updates the given entries according to if they already exist in the cozy or not You need the full permission for the given doctype in your manifest, to be able to use this function. entries (object array): Documents to save doctype (string): Doctype of the documents matchingAttributes (string array): attributes in each entry used to check if an entry already exists in the Cozy options (object): general option affecting metadata : + sourceAccount (String): id of the source account + sourceAccountIdentifier (String): identifier unique to the account targetted by the connector. It is the login most of the time Kind : Exported function", "title": "updateOrCreate() \u23cf"}, {"location": "cozy-konnector-libs/api/#utils", "text": "Small utilities helping to develop konnectors. utils ~fetchAll() ~queryAll() ~findDuplicates() ~batchUpdateAttributes() ~batchDelete() ~getPdfText() ~formatDate()", "title": "utils"}, {"location": "cozy-konnector-libs/api/#utilsfetchall", "text": "This function allows to fetch all documents for a given doctype. It is the fastest to get all documents but without filtering possibilities deprecated by the findAll method from cozyClient Parameters: doctype (string): the doctype from which you want to fetch the data Kind : inner method of utils", "title": "utils~fetchAll()"}, {"location": "cozy-konnector-libs/api/#utilsqueryall", "text": "This function allows to fetch all documents for a given doctype exceeding the 100 limit. It is slower that fetchAll because it fetches the data 100 by 100 but allows to filter the data with a selector and an index Parameters: doctype (string): the doctype from which you want to fetch the data selector (object): the mango query selector index (object): (optional) the query selector index. If not defined, the function will create it\u2019s own index with the keys specified in the selector const documents = await queryAll ( 'io.cozy.bills' , { vendor : 'Direct Energie' }) Kind : inner method of utils", "title": "utils~queryAll()"}, {"location": "cozy-konnector-libs/api/#utilsfindduplicates", "text": "This function find duplicates in a given doctype, filtered by an optional mango selector Parameters: doctype (string): the doctype from which you want to fetch the data selector (object): (optional) the mango query selector options : - keys (array) : List of keys used to check that two items are the same. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Gets all the records by default Returns an object with the following keys: toKeep : this is the list of unique documents that you should keep in db toRemove : this is the list of documents that can remove from db. If this is io.cozy.bills documents, do not forget to clean linked bank operations const { toKeep , toRemove } = await findDuplicates ( 'io.cozy.bills' , { selector : { vendor : 'Direct Energie' }}) Kind : inner method of utils", "title": "utils~findDuplicates()"}, {"location": "cozy-konnector-libs/api/#utilsbatchupdateattributes", "text": "This is a shortcut to update multiple documents in one call Parameters: doctype (string): the doctype from which you want to fetch the data ids (array): array of ids of documents to update transformation (object): attributes to change with their values options : - keys (array) : List of keys used to check that two items are the same. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Gets all the records by default Returns a promise which resolves with all the return values of updateAttributes await batchUpdateAttributes ( 'io.cozy.bills' , [ 1 , 2 , 3 ], { vendor : 'Direct Energie' }) Kind : inner method of utils", "title": "utils~batchUpdateAttributes()"}, {"location": "cozy-konnector-libs/api/#utilsbatchdelete", "text": "This is a shortcut to delete multiple documents in one call Parameters: doctype (string): the doctype from which you want to fetch the data documents (array): documents to delete with their ids transformation (object): attributes to change with their values options : - keys (array) : List of keys used to check that two items are the same. - index (optionnal) : Return value returned by cozy.data.defineIndex , the default will correspond to all documents of the selected doctype. - selector (optionnal object) : Mango request to get records. Gets all the records by default Returns a promise which resolves with all the return values of updateAttributes Example to remove all the documents for a given doctype const documents = await fetchAll ( 'io.cozy.marvel' ) await batchDelete ( 'io.cozy.marvel' , documents ) Kind : inner method of utils", "title": "utils~batchDelete()"}, {"location": "cozy-konnector-libs/api/#utilsgetpdftext", "text": "This function can read the content of a cozy pdf file and output its text Parameters: fileId (string): the id of the file in the cozy options : - pages (array or number) : The list of page you want to interpret You need to add pdfjs-dist package as a dependency to your connector to allow this to work Returns a promise which resolves with an object with the following attributes: - text (string) : The full text of the pdf - 1 : The full pdfjs data for page 1 - n : The full pdfjs data for page n Example: const pdfText = ( await getPdfText ( '887ABCFE87687' )). text Kind : inner method of utils", "title": "utils~getPdfText()"}, {"location": "cozy-konnector-libs/api/#utilsformatdate", "text": "This function convert a Date Object to a ISO date string (2018-07-31) Parameters: date (Date): the id of the file in the cozy Returns a string Example: const date = formatFrenchDate ( New Date . now ()) Kind : inner method of utils", "title": "utils~formatDate()"}, {"location": "cozy-konnector-libs/api/#categorization", "text": "Bank transactions categorization categorization ~createCategorizer(options) \u21d2 Object ~categorize(transactions, options) \u21d2 Array. ~CreateCategorizerOptions", "title": "categorization"}, {"location": "cozy-konnector-libs/api/#categorizationcreatecategorizeroptions-object", "text": "Initialize global and local models and return an object exposing a categorize function that applies both models on an array of transactions The global model is a model specific to hosted Cozy instances. It is not available for self-hosted instances. It will just do nothing in that case. The local model is based on the user manual categorizations. Each model adds two properties to the transactions: The global model adds cozyCategoryId and cozyCategoryProba The local model adds localCategoryId and localCategoryProba In the end, each transaction can have up to four different categories. An application can use these categories to show the most significant for the user. See https://github.com/cozy/cozy-doctypes/blob/master/docs/io.cozy.bank.md#categories for more informations. Kind : inner method of categorization Returns : Object - A method to categorize transactions and the classifiers it uses. Param Type Description options CreateCategorizerOptions Options used to build the categorizer Example const { BaseKonnector , createCategorizer } = require ( 'cozy-konnector-libs' ) class BankingKonnector extends BaseKonnector { async saveTransactions () { const transactions = await this . fetchTransactions () const categorizer = await createCategorizer const categorizedTransactions = await categorizer . categorize ( transactions ) // Save categorizedTransactions } }", "title": "categorization~createCategorizer(options) \u21d2 Object"}, {"location": "cozy-konnector-libs/api/#categorizationcategorizetransactions-options-arrayobject", "text": "Initialize global and local models and categorize the given array of transactions Kind : inner method of categorization Returns : Array. - the categorized transactions See : createCategorizer for more informations about models initialization Param Type Description transactions Array. The transactions to categorize options CreateCategorizerOptions Options passed to create the categorizer Example const { BaseKonnector , categorize } = require ( 'cozy-konnector-libs' ) class BankingKonnector extends BaseKonnector { async saveTransactions () { const transactions = await this . fetchTransactions () const categorizedTransactions = await categorize ( transactions ) // Save categorizedTransactions } }", "title": "categorization~categorize(transactions, options) \u21d2 Array.<object>"}, {"location": "cozy-konnector-libs/api/#categorizationcreatecategorizeroptions", "text": "Kind : inner typedef of categorization Properties Name Type Description useGlobalModel boolean Whether to use the globally trained model customTransactionFetcher function A custom training transaction fetcher pretrainedClassifier object A pretrained instance of a bayes classifier", "title": "categorization~CreateCategorizerOptions"}, {"location": "cozy-konnector-libs/api/#basekonnector", "text": "The class from which all the connectors must inherit. It takes a fetch function in parameter that must return a Promise . You need at least the GET permission on io.cozy.accounts in your manifest to allow it to fetch account information for your connector. Its role is twofold : Make the link between account data and konnector Handle errors \u26a0\ufe0f A promise should be returned from the fetch function otherwise the konnector cannot know that asynchronous code has been called. Kind : global class BaseKonnector new BaseKonnector(fetch) .run() .main() \u21d2 Promise .end() .fail() .readPayload() \u21d2 Object | null .initAttributes() .saveAccountData(data, options) \u21d2 Promise .getAccountData() \u21d2 object .updateAccountAttributes() .setTwoFAState(options) .resetTwoFAState() .waitForTwoFaCode(options) \u21d2 Promise .notifySuccessfulLogin() .deactivateAutoSuccessfulLogin() .saveBills() \u21d2 Promise .saveFiles() \u21d2 Promise .updateOrCreate() \u21d2 Promise .saveIdentity() \u21d2 Promise .signin() \u21d2 Promise .terminate(err) .getCozyMetadata(data)", "title": "BaseKonnector"}, {"location": "cozy-konnector-libs/api/#new-basekonnectorfetch", "text": "Constructor Param Type Description fetch function Function to be run automatically after account data is fetched. This function will be binded to the current connector. If not fetch function is given. The connector will have to handle itself it\u2019s own exection and error handling Example const { BaseKonnector } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( function fetch () { // use this to access the instance of the konnector to // store any information that needs to be passed to // different stages of the konnector return request ( 'http://ameli.fr' ) . then ( computeReimbursements ) . then ( saveBills ) })", "title": "new BaseKonnector(fetch)"}, {"location": "cozy-konnector-libs/api/#basekonnectorrun", "text": "Entrypoint of the konnector Initializes connector attributes Awaits this.main Ensures errors are handled via this.fail Calls this.end when the main function succeeded Kind : instance method of BaseKonnector", "title": "baseKonnector.run()"}, {"location": "cozy-konnector-libs/api/#basekonnectormain-promise", "text": "Main runs after konnector has been initialized. Errors thrown will be automatically handled. Kind : instance method of BaseKonnector Returns : Promise - - The konnector is considered successful when it resolves", "title": "baseKonnector.main() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectorend", "text": "Hook called when the connector has ended successfully Kind : instance method of BaseKonnector", "title": "baseKonnector.end()"}, {"location": "cozy-konnector-libs/api/#basekonnectorfail", "text": "Hook called when the connector fails Kind : instance method of BaseKonnector", "title": "baseKonnector.fail()"}, {"location": "cozy-konnector-libs/api/#basekonnectorreadpayload-object-null", "text": "Read an eventual payload from COZY_PAYLOAD env var, wether it is a JSON string or a reference to a file containing a JSON string Kind : instance method of BaseKonnector Returns : Object | null - Promise<> result of JSON.parse from the JSON string or null if no payload", "title": "baseKonnector.readPayload() \u21d2 Object | null"}, {"location": "cozy-konnector-libs/api/#basekonnectorinitattributes", "text": "Initializes konnector attributes that will be used during its lifetime this._account this.fields Kind : instance method of BaseKonnector", "title": "baseKonnector.initAttributes()"}, {"location": "cozy-konnector-libs/api/#basekonnectorsaveaccountdatadata-options-promise", "text": "Saves data to the account that is passed to the konnector. Use it to persist data that needs to be passed to each konnector run. By default, the data is merged to the remote data, use options.merge = false to overwrite the data. The data is saved under the .data attribute of the cozy account. Don\u2019t forget to modify the manifest.konnector file to give the right to write on the io.cozy.accounts doctype. The syntax can be : \"permissions\": {\"accounts\": {\"type\": \"io.cozy.accounts\"}} (here we juste removed the verb GET ) Kind : instance method of BaseKonnector Returns : Promise - : resolved with the modified account Param Type Description data object Attributes to be merged options object { merge: true", "title": "baseKonnector.saveAccountData(data, options) \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectorgetaccountdata-object", "text": "Get the data saved by saveAccountData Kind : instance method of BaseKonnector Returns : object - the account data", "title": "baseKonnector.getAccountData() \u21d2 object"}, {"location": "cozy-konnector-libs/api/#basekonnectorupdateaccountattributes", "text": "Update account attributes and cache the account Kind : instance method of BaseKonnector", "title": "baseKonnector.updateAccountAttributes()"}, {"location": "cozy-konnector-libs/api/#basekonnectorsettwofastateoptions", "text": "Sets the 2FA state, according to the type passed. Doing so resets the twoFACode field Typically you should not use that directly, prefer to use waitForTwoFaCode since the wait for user input will be handled for you. It is useful though for the \u201capp\u201d type where no user input (inside Cozy) is needed. Kind : instance method of BaseKonnector Param Type Description options object The list of options options.type string Used by the front to show the right message (email/sms/app/app_code) options.retry boolean Is this function call a retry ? This changes the resulting message to the user", "title": "baseKonnector.setTwoFAState(options)"}, {"location": "cozy-konnector-libs/api/#basekonnectorresettwofastate", "text": "Resets 2FA state when not needed anymore Kind : instance method of BaseKonnector", "title": "baseKonnector.resetTwoFAState()"}, {"location": "cozy-konnector-libs/api/#basekonnectorwaitfortwofacodeoptions-promise", "text": "Notices that 2FA code is needed and wait for the user to submit it. It uses the account to do the communication with the user. Kind : instance method of BaseKonnector Returns : Promise - Contains twoFa code entered by user Throws : Will throw USER_ACTION_NEEDED.TWOFA_EXPIRED if the konnector job is not run manually (we assume that not run manually means that we do not have a graphic interface to fill the required information) Will throw USER_ACTION_NEEDED.TWOFA_EXPIRED if 2FA is not filled by the user soon enough Param Type Description options object The list of options options.type string (default: \u201cemail\u201d) - Type of the expected 2FA code. The message displayed to the user will depend on it. Possible values: email, sms options.timeout number (default 3 minutes after now) - After this date, the stop will stop waiting and and an error will be shown to the user (deprecated and alias of endTime) options.endTime number (default 3 minutes after now) - After this timestamp, the home will stop waiting and and an error will be shown to the user options.heartBeat number (default: 5000) - How many milliseconds between each code check options.retry boolean (default: false) - Is it a retry. If true, an error message will be displayed to the user Example const { BaseKonnector } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( start ) async function start () { // we detect the need of a 2FA code const code = this . waitForTwoFaCode ({ type : 'email' }) // send the code to the targeted site }", "title": "baseKonnector.waitForTwoFaCode(options) \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectornotifysuccessfullogin", "text": "Tells Cozy-Home that we have successfully logged in. Useful when auto-success has been deactivated. See deactivateAutoSuccess Kind : instance method of BaseKonnector", "title": "baseKonnector.notifySuccessfulLogin()"}, {"location": "cozy-konnector-libs/api/#basekonnectordeactivateautosuccessfullogin", "text": "By default, cozy-home considers that the konnector has successfully logged in when the konnector has run for more than 8s. This is problematic for 2FA since the konnector can sit idle, just waiting for the 2FA to come back. When this method is called, cozy-home is notified and will not consider the absence of error after 8s to be a success. Afterwards, to notify cozy-home when the user has logged in successfully, for example, after the user has entered 2FA codes, it is necessary to call notifySuccessfulLogin . Does nothing if called more than once. Kind : instance method of BaseKonnector", "title": "baseKonnector.deactivateAutoSuccessfulLogin()"}, {"location": "cozy-konnector-libs/api/#basekonnectorsavebills-promise", "text": "This is saveBills function from cozy-konnector-libs which automatically adds sourceAccount in metadata of each entry Kind : instance method of BaseKonnector Returns : Promise - resolves with entries hydrated with db data", "title": "baseKonnector.saveBills() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectorsavefiles-promise", "text": "This is saveFiles function from cozy-konnector-libs which automatically adds sourceAccount and sourceAccountIdentifier cozyMetadatas to files Kind : instance method of BaseKonnector Returns : Promise - resolves with the list of entries with file objects", "title": "baseKonnector.saveFiles() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectorupdateorcreate-promise", "text": "This is updateOrCreate function from cozy-konnector-libs which automatically adds sourceAccount in metadata of each entry Kind : instance method of BaseKonnector Returns : Promise - resolves to an array of db objects", "title": "baseKonnector.updateOrCreate() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectorsaveidentity-promise", "text": "This is saveIdentity function from cozy-konnector-libs which automatically adds sourceAccount in metadata of each entry Kind : instance method of BaseKonnector Returns : Promise - empty promise", "title": "baseKonnector.saveIdentity() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectorsignin-promise", "text": "This is signin function from cozy-konnector-libs which automatically adds deactivateAutoSuccessfulLogin and notifySuccessfulLogin calls Kind : instance method of BaseKonnector Returns : Promise - resolve with an object containing form data", "title": "baseKonnector.signin() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#basekonnectorterminateerr", "text": "Send a special error code which is interpreted by the cozy stack to terminate the execution of the connector now Kind : instance method of BaseKonnector Param Type Description err string The error code to be saved as connector result see [docs/ERROR_CODES.md] Example this . terminate ( 'LOGIN_FAILED' )", "title": "baseKonnector.terminate(err)"}, {"location": "cozy-konnector-libs/api/#basekonnectorgetcozymetadatadata", "text": "Get cozyMetaData from the context of the connector Kind : instance method of BaseKonnector Param Type Description data object this data will be merged with cozyMetaData", "title": "baseKonnector.getCozyMetadata(data)"}, {"location": "cozy-konnector-libs/api/#cookiekonnector", "text": "Connector base class extending BaseKonnector which handles cookie session in a central way It also handles saving cookie session in the account and automatically restore it for the next connector run. All cozy-konnector-libs tools using request are proposed as methods of this class to force them to use the central cookie which can be saved/restored. You need at least the GET and PUT permissions on io.cozy.accounts in your manifest to allow it to save/restore cookies Kind : global class CookieKonnector new CookieKonnector(requestFactoryOptions) .initAttributes() \u21d2 Promise .end() .requestFactory(options) \u21d2 object .resetSession() \u21d2 Promise .initSession() \u21d2 Promise .saveSession() \u21d2 Promise .signin() \u21d2 Promise .saveFiles() \u21d2 Promise .saveBills() \u21d2 Promise", "title": "CookieKonnector"}, {"location": "cozy-konnector-libs/api/#new-cookiekonnectorrequestfactoryoptions", "text": "Constructor Param Type Description requestFactoryOptions function Option object passed to requestFactory to initialize this.request. It is still possible to change this.request doing : javascript this.request = this.requestFactory(...) Please not you have to run the connector yourself doing : javascript connector.run() Example const { CookieKonnector } = require ( 'cozy-konnector-libs' ) class MyConnector extends CookieKonnector { async fetch ( fields ) { // the code of your connector await this . request ( 'https://...' ) } async testSession () { const $ = await this . request ( 'https://...' ) return $ ( '' ) } } const connector = new MyKonnector ({ cheerio : true , json : false }) connector . run ()", "title": "new CookieKonnector(requestFactoryOptions)"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorinitattributes-promise", "text": "Initializes the current connector with data coming from the associated account and also the session Kind : instance method of CookieKonnector Returns : Promise - with the fields as an object", "title": "cookieKonnector.initAttributes() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorend", "text": "Hook called when the connector is ended Kind : instance method of CookieKonnector", "title": "cookieKonnector.end()"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorrequestfactoryoptions-object", "text": "Calls cozy-konnector-libs requestFactory forcing this._jar as the cookie Kind : instance method of CookieKonnector Returns : object - - The resulting request object Param Type Description options object requestFactory option", "title": "cookieKonnector.requestFactory(options) \u21d2 object"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorresetsession-promise", "text": "Reset cookie session with a new empty session and save it to the associated account Kind : instance method of CookieKonnector Returns : Promise - empty promise", "title": "cookieKonnector.resetSession() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorinitsession-promise", "text": "Get the cookie session from the account if any Kind : instance method of CookieKonnector Returns : Promise - true or false if the session in the account exists or not", "title": "cookieKonnector.initSession() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorsavesession-promise", "text": "Saves the current cookie session to the account Kind : instance method of CookieKonnector Returns : Promise - empty promise", "title": "cookieKonnector.saveSession() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorsignin-promise", "text": "This is signin function from cozy-konnector-libs which is forced to use the current cookies and current request from CookieKonnector. It also automatically saves the session after signin if it is a success. Kind : instance method of CookieKonnector Returns : Promise - resolve with an object containing form data", "title": "cookieKonnector.signin() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorsavefiles-promise", "text": "This is saveFiles function from cozy-konnector-libs which is forced to use the current cookies and current request from CookieKonnector. Kind : instance method of CookieKonnector Returns : Promise - resolves with the list of entries with file objects", "title": "cookieKonnector.saveFiles() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#cookiekonnectorsavebills-promise", "text": "This is saveBills function from cozy-konnector-libs which is forced to use the current cookies and current request from CookieKonnector. Kind : instance method of CookieKonnector Returns : Promise - resolves with entries hydrated with db data", "title": "cookieKonnector.saveBills() \u21d2 Promise"}, {"location": "cozy-konnector-libs/api/#document", "text": "Simple Model for Documents. Allows to specify shouldSave , shouldUpdate as methods. Has useful isEqual method Kind : global class", "title": "Document"}, {"location": "cozy-konnector-libs/api/#documentisequal", "text": "Compares to another document deeply. _id and _rev are by default ignored in the comparison. By default, will compare dates loosely since you often compare existing documents (dates in ISO string) with documents that just have been scraped where dates are Date s. Kind : instance method of Document", "title": "document.isEqual()"}, {"location": "cozy-konnector-libs/api/#fs", "text": "Manifest is provided differently in developement that in production. In production, the manifest has been \u201cmerged\u201d via Webpack via the DefinePlugin In development/test, we simply read the manifest from the fs Kind : global constant", "title": "fs"}, {"location": "cozy-konnector-libs/api/#login_failed-string", "text": "The konnector could not login Kind : global constant", "title": "LOGIN_FAILED : string"}, {"location": "cozy-konnector-libs/api/#not_existing_directory-string", "text": "The folder specified as folder_to_save does not exist (checked by BaseKonnector) Kind : global constant", "title": "NOT_EXISTING_DIRECTORY : string"}, {"location": "cozy-konnector-libs/api/#vendor_down-string", "text": "The vendor\u2019s website is down Kind : global constant", "title": "VENDOR_DOWN : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed-string", "text": "There was an unexpected error, please take a look at the logs to know what happened Kind : global constant", "title": "USER_ACTION_NEEDED : string"}, {"location": "cozy-konnector-libs/api/#file_download_failed-string", "text": "There was a problem while downloading a file Kind : global constant", "title": "FILE_DOWNLOAD_FAILED : string"}, {"location": "cozy-konnector-libs/api/#save_file_failed-string", "text": "There was a problem while saving a file Kind : global constant", "title": "SAVE_FILE_FAILED : string"}, {"location": "cozy-konnector-libs/api/#disk_quota_exceeded-string", "text": "Could not save a file to the cozy because of disk quota exceeded Kind : global constant", "title": "DISK_QUOTA_EXCEEDED : string"}, {"location": "cozy-konnector-libs/api/#challenge_asked-string", "text": "It seems that the website requires a second authentification factor that we don\u2019t support yet. Kind : global constant", "title": "CHALLENGE_ASKED : string"}, {"location": "cozy-konnector-libs/api/#login_failed_too_many_attempts-string", "text": "Temporarily blocked Kind : global constant", "title": "LOGIN_FAILED_TOO_MANY_ATTEMPTS : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_oauth_outdated-string", "text": "Access refresh required Kind : global constant", "title": "USER_ACTION_NEEDED_OAUTH_OUTDATED : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_account_removed-string", "text": "Unavailable account Kind : global constant", "title": "USER_ACTION_NEEDED_ACCOUNT_REMOVED : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_change_password-string", "text": "Unavailable account Kind : global constant", "title": "USER_ACTION_NEEDED_CHANGE_PASSWORD : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_permissions_changed-string", "text": "Password update required Kind : global constant", "title": "USER_ACTION_NEEDED_PERMISSIONS_CHANGED : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_cgu_form-string", "text": "The user needs to accept a CGU form before accessing the rest of the website Kind : global constant", "title": "USER_ACTION_NEEDED_CGU_FORM : string"}, {"location": "cozy-konnector-libs/api/#captcha_resolution_failed-string", "text": "solveCaptcha failed to solve the captcha Kind : global constant", "title": "CAPTCHA_RESOLUTION_FAILED : string"}, {"location": "cozy-konnector-libs/api/#login_failed_needs_secret-string", "text": "Additionnal information is needed to check your login details Kind : global constant", "title": "LOGIN_FAILED_NEEDS_SECRET : string"}, {"location": "cozy-konnector-libs/api/#maintenance-string", "text": "remote website seems to be unavailable Kind : global constant", "title": "MAINTENANCE : string"}, {"location": "cozy-konnector-libs/api/#terms_version_mismatch-string", "text": "User needs to accept new terms Kind : global constant", "title": "TERMS_VERSION_MISMATCH : string"}, {"location": "cozy-konnector-libs/api/#unknown_error-string", "text": "unkown error Kind : global constant", "title": "UNKNOWN_ERROR : string"}, {"location": "cozy-konnector-libs/api/#unknown_error_partial_sync-string", "text": "The synchronization is complete but some elements may be missing Kind : global constant", "title": "UNKNOWN_ERROR_PARTIAL_SYNC : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_sca_required-string", "text": "Renewal of authentication required Kind : global constant", "title": "USER_ACTION_NEEDED_SCA_REQUIRED : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_twofa_expired-string", "text": "Authentication renewal required Kind : global constant", "title": "USER_ACTION_NEEDED_TWOFA_EXPIRED : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_webauth_required-string", "text": "Authentication on vendor website required Kind : global constant", "title": "USER_ACTION_NEEDED_WEBAUTH_REQUIRED : string"}, {"location": "cozy-konnector-libs/api/#user_action_needed_wrong_twofa_code-string", "text": "Incorrect strong authentication code Kind : global constant", "title": "USER_ACTION_NEEDED_WRONG_TWOFA_CODE : string"}, {"location": "cozy-konnector-libs/api/#vendor_down_bank_down-string", "text": "Unavailable bank website Kind : global constant", "title": "VENDOR_DOWN_BANK_DOWN : string"}, {"location": "cozy-konnector-libs/api/#vendor_down_linxo_down-string", "text": "Unavailable bank website Kind : global constant", "title": "VENDOR_DOWN_LINXO_DOWN : string"}, {"location": "cozy-konnector-libs/api/#attachprocesseventhandlersprcs-function", "text": "Attach event handlers to catch uncaught exceptions/rejections and signals. Log them as critical and exit the process accordingly. If the cleanup function has not been called, calling again the function is a no-op. Kind : global function Returns : function - When called, removes the signal handlers Param Type Description prcs object Process object, default to current process", "title": "attachProcessEventHandlers(prcs) \u21d2 function"}, {"location": "cozy-konnector-libs/api/#mkspec", "text": "Declarative scraping. Describe your items attributes and where to find/parse them instead of imperatively building them. Heavily inspired by artoo scraping method. Kind : global function", "title": "mkSpec()"}, {"location": "cozy-konnector-libs/api/#scrape-specs-childselector-object-array", "text": "Scrape a cheerio object for properties Kind : global function Returns : object | Array - - Item(s) scraped Param Type Description $ object Cheerio node which will be scraped specs object | string Options object describing what you want to scrape [childSelector] string If passed, scrape will return an array of items Example scrape can be used to declaratively extract data : For one object : const item = scrape($('#item'), { title: '.title', content: '.content' }) For a list of objects : const items = scrape($('#content'), { title: '.title', content: '.content' }, '.item') For more power, you can use object s for each retriever : const items = scrape($('#content'), { title: '.title', content: '.content', link: { sel: 'a', attr: 'href' }, }, '.item') Here the href attribute of the a inside .item s would have been put into the link attribute of the items returned by scrape . Available options : sel : the CSS selector used to target the HTML node from which data will be scraped attr : the HTML attribute from which to extract data parse : function applied to the value extracted ( { sel: '.price', parse: parseAmount } ) fn : if you need something more complicated than attr , you can use this function, it receives the complete DOM node. { sel: '.person', fn: $node => $node.attr('data-name') + $node.attr('data-firstname') }", "title": "scrape($, specs, [childSelector]) \u21d2 object | Array"}, {"location": "cozy-konnector-libs/api/#permissions", "text": "Please note that some classes require some permissions: io.cozy.accounts for the BaseKonnector class ( GET only) io.cozy.files to save files io.cozy.bills to save bills io.cozy.bank.operations for linkBankOperations", "title": "\u26a0 Permissions"}, {"location": "cozy-konnector-libs/categorization-dashboard/", "text": "Categorization dashboard \u00b6 To check that the banking categorization works well, we have tests that generate a dashboard showing global and local models performances based on sanitized datasets. Download and decrypt data \u00b6 Since these tests are executed on real data, it is kept encrypted. To be able to run the tests, you first have to decrypt it (you need the encryption passphrase): yarn decrypt-banking-tests You now have two new directories in the dashboard: fixtures : the actual operations with the categories information. __snapshots__ : snapshot of the categorization results. The global categorization model tests also needs the current and latest model parameters. These parameters should be downloaded: yarn download-banking-tests Now you have everything to run the tests. Run the tests \u00b6 There are two tests files : services-global-fixtures.spec.js : only test the global model. services-fixtures.spec.js : test both the global and local models. Each test will categorize all the operations and check if it matches the snapshot. To run it: env BACKUP_DIR=/path/to/dir LOG_LEVEL=error yarn jest src/libs/categorization/dashboard/services-fixtures.spec.js BACKUP_DIR environment variable is the path to the directory in which you want to write the result of the tes. Default is /tmp LOG_LEVEL environment variable is the log level used by cozy-logger . As the tests can be quite verbose, using the error level avoids unecessary information. You can add --watch to run the tests in watch mode to avoid running everything each time. Adding IT_IS_A_TEST=true will run the tests on a reduced dataset, as the whole tests can take a long time to complete. Update the tests \u00b6 To update the snapshots of the tests: yarn jest src/libs/categorization/dashboard/ -u Then, to save the results with a new encrypted archive (you need the encryption passphrase): yarn encrypt-banking-tests", "title": "Categorization dashboard"}, {"location": "cozy-konnector-libs/categorization-dashboard/#categorization-dashboard", "text": "To check that the banking categorization works well, we have tests that generate a dashboard showing global and local models performances based on sanitized datasets.", "title": "Categorization dashboard"}, {"location": "cozy-konnector-libs/categorization-dashboard/#download-and-decrypt-data", "text": "Since these tests are executed on real data, it is kept encrypted. To be able to run the tests, you first have to decrypt it (you need the encryption passphrase): yarn decrypt-banking-tests You now have two new directories in the dashboard: fixtures : the actual operations with the categories information. __snapshots__ : snapshot of the categorization results. The global categorization model tests also needs the current and latest model parameters. These parameters should be downloaded: yarn download-banking-tests Now you have everything to run the tests.", "title": "Download and decrypt data"}, {"location": "cozy-konnector-libs/categorization-dashboard/#run-the-tests", "text": "There are two tests files : services-global-fixtures.spec.js : only test the global model. services-fixtures.spec.js : test both the global and local models. Each test will categorize all the operations and check if it matches the snapshot. To run it: env BACKUP_DIR=/path/to/dir LOG_LEVEL=error yarn jest src/libs/categorization/dashboard/services-fixtures.spec.js BACKUP_DIR environment variable is the path to the directory in which you want to write the result of the tes. Default is /tmp LOG_LEVEL environment variable is the log level used by cozy-logger . As the tests can be quite verbose, using the error level avoids unecessary information. You can add --watch to run the tests in watch mode to avoid running everything each time. Adding IT_IS_A_TEST=true will run the tests on a reduced dataset, as the whole tests can take a long time to complete.", "title": "Run the tests"}, {"location": "cozy-konnector-libs/categorization-dashboard/#update-the-tests", "text": "To update the snapshots of the tests: yarn jest src/libs/categorization/dashboard/ -u Then, to save the results with a new encrypted archive (you need the encryption passphrase): yarn encrypt-banking-tests", "title": "Update the tests"}, {"location": "cozy-konnector-libs/cli/", "text": "CLI \u00b6 cozy-jobs-cli is a npm package providing CLI tools allowing to run your connector in different modes. standalone development or in dedicated REPL You can install it in your connector as a dev dependency. cozy-run-standalone \u00b6 It can be handy to run a konnector without inserting the data in a cozy. This mode is called \u201cstandalone\u201d. You can run your connector in standalone mode with : $ cozy-run-standalone If you want, you can add the following code in the scripts section of your package.json file: \"scripts\" : { \"standalone\" : \"cozy-run-standalone\" } It will then possible to do: yarn standalone The requests to the cozy-stack will be stubbed using the [./fixture.json] file as source of data and when cozy-client-js is asked to create or update data, the data will be output to the console. The bills (or any file) will be saved in the ./data directory. It is possible to add an argument to this command which tells which file to run. Default is defined in package.json main section or ./src/index.js It is possible to record and replay the requests done by the standalone command using the replay module. When your connector is run with this command, a global function is available in your connector : global.openInBrowser , which can take an html string or a cheerio object as input and will show the corresponding html page in your default browser. Arguments \u00b6 Usage : cozy - run - standalone [ options ] < file > Options : -- record Record all the requests in the ./ fixtures directory using the replay module -- replay Replay all the recorded requests -- persist Do not empty ./ data / importedData . json at each run - h , -- help output usage information cozy-run-dev \u00b6 If you want to run your connector linked to a cozy-stack, even remotely, the \u201cdev\u201d mode is for you. Add the following code in the scripts section of your package.json file: \"scripts\": { + \"dev\": \"cozy-run-dev\" } and run: yarn dev This command will register your konnector as an OAuth application to the cozy-stack and then set the COZY_CREDENTIALS and COZY_FIELDS environment variable. By default, the cozy-stack is expected to run at http://cozy.tools:8080. If this is not your case, update the COZY_URL field in [./konnector-dev-config.json]. After that, your connector is running but will not work since credentials to the target service are not configured. You can do this also in [./konnector-dev-config.json] in the \u201cfields\u201d section. \"fields\": { + \"login\": \"homer.simpson@gmail.com\", + \"password\": \"maggieisthebest\" } Please note that the [./konnector-dev-config.json] file accepts javascript comments. They will be stripped out when read by cozy-run commands. The files are saved in the /cozy-konnector-dev-root directory of your cozy. It is also possible to add an argument to this command which tells which file to run. Default is defined in package.json main section or ./src/index.js When your connector is run with this command, a global function is available in your connector : global.openInBrowser , which can take an html string or a cheerio object as input and will show the corresponding html page in your default browser. Arguments \u00b6 $ cozy-run-dev [ -t token.json ] [ -m manifest.webapp ] -t , --token : Specify where the token should be saved -m , --manifest : Specify the manifest.path that should be used for the permissions cozy-run-shell \u00b6 When you are developping a connector, it is possible to get a REPL with all the cozy-konnector-libs tools available and some enhancements. scripts : { dev : \"cozy-run-shell\" } and run: yarn shell In this REPL, all the cozy-konnector-libs tools are available as globals and a default global request instance initialized with cheerio and cookie handling is available. For example run : request ( 'http://quotes.toscrape.com/' ) After running a request, a global $ object with a cheerio instance is available. Enter : $ A full global request-promise response object is also available. If you always want the details of the request and the response to be displayed. Just run once: debug () And you get a syntax colored html representation of the result of the request. If you run : $ ( 'p' ) You get an array of elements with for each element: - the type of the element (p) - the html of the element - the cleaned text of the element It is also possible to load a html file into the shell. Run : yarn shell index.html The html file will load and $ will be correctly initialized. The openInBrowser is also available , which can take an html string or a cheerio object as input and will show the corresponding html page in your default browser. Arguments \u00b6 $ cozy-run-shell [ ]", "title": "CLI"}, {"location": "cozy-konnector-libs/cli/#cli", "text": "cozy-jobs-cli is a npm package providing CLI tools allowing to run your connector in different modes. standalone development or in dedicated REPL You can install it in your connector as a dev dependency.", "title": "CLI"}, {"location": "cozy-konnector-libs/cli/#cozy-run-standalone", "text": "It can be handy to run a konnector without inserting the data in a cozy. This mode is called \u201cstandalone\u201d. You can run your connector in standalone mode with : $ cozy-run-standalone If you want, you can add the following code in the scripts section of your package.json file: \"scripts\" : { \"standalone\" : \"cozy-run-standalone\" } It will then possible to do: yarn standalone The requests to the cozy-stack will be stubbed using the [./fixture.json] file as source of data and when cozy-client-js is asked to create or update data, the data will be output to the console. The bills (or any file) will be saved in the ./data directory. It is possible to add an argument to this command which tells which file to run. Default is defined in package.json main section or ./src/index.js It is possible to record and replay the requests done by the standalone command using the replay module. When your connector is run with this command, a global function is available in your connector : global.openInBrowser , which can take an html string or a cheerio object as input and will show the corresponding html page in your default browser.", "title": "cozy-run-standalone"}, {"location": "cozy-konnector-libs/cli/#arguments", "text": "Usage : cozy - run - standalone [ options ] < file > Options : -- record Record all the requests in the ./ fixtures directory using the replay module -- replay Replay all the recorded requests -- persist Do not empty ./ data / importedData . json at each run - h , -- help output usage information", "title": "Arguments"}, {"location": "cozy-konnector-libs/cli/#cozy-run-dev", "text": "If you want to run your connector linked to a cozy-stack, even remotely, the \u201cdev\u201d mode is for you. Add the following code in the scripts section of your package.json file: \"scripts\": { + \"dev\": \"cozy-run-dev\" } and run: yarn dev This command will register your konnector as an OAuth application to the cozy-stack and then set the COZY_CREDENTIALS and COZY_FIELDS environment variable. By default, the cozy-stack is expected to run at http://cozy.tools:8080. If this is not your case, update the COZY_URL field in [./konnector-dev-config.json]. After that, your connector is running but will not work since credentials to the target service are not configured. You can do this also in [./konnector-dev-config.json] in the \u201cfields\u201d section. \"fields\": { + \"login\": \"homer.simpson@gmail.com\", + \"password\": \"maggieisthebest\" } Please note that the [./konnector-dev-config.json] file accepts javascript comments. They will be stripped out when read by cozy-run commands. The files are saved in the /cozy-konnector-dev-root directory of your cozy. It is also possible to add an argument to this command which tells which file to run. Default is defined in package.json main section or ./src/index.js When your connector is run with this command, a global function is available in your connector : global.openInBrowser , which can take an html string or a cheerio object as input and will show the corresponding html page in your default browser.", "title": "cozy-run-dev"}, {"location": "cozy-konnector-libs/cli/#arguments_1", "text": "$ cozy-run-dev [ -t token.json ] [ -m manifest.webapp ] -t , --token : Specify where the token should be saved -m , --manifest : Specify the manifest.path that should be used for the permissions", "title": "Arguments"}, {"location": "cozy-konnector-libs/cli/#cozy-run-shell", "text": "When you are developping a connector, it is possible to get a REPL with all the cozy-konnector-libs tools available and some enhancements. scripts : { dev : \"cozy-run-shell\" } and run: yarn shell In this REPL, all the cozy-konnector-libs tools are available as globals and a default global request instance initialized with cheerio and cookie handling is available. For example run : request ( 'http://quotes.toscrape.com/' ) After running a request, a global $ object with a cheerio instance is available. Enter : $ A full global request-promise response object is also available. If you always want the details of the request and the response to be displayed. Just run once: debug () And you get a syntax colored html representation of the result of the request. If you run : $ ( 'p' ) You get an array of elements with for each element: - the type of the element (p) - the html of the element - the cleaned text of the element It is also possible to load a html file into the shell. Run : yarn shell index.html The html file will load and $ will be correctly initialized. The openInBrowser is also available , which can take an html string or a cheerio object as input and will show the corresponding html page in your default browser.", "title": "cozy-run-shell"}, {"location": "cozy-konnector-libs/cli/#arguments_2", "text": "$ cozy-run-shell [ ]", "title": "Arguments"}, {"location": "cozy-konnector-libs/dev/", "text": "Developing a konnector \u00b6 Without an accessible cozy-stack \u00b6 If you just want to test this connector without any cozy available. You first need an installed [nodejs] (LTS version is fine). And the last version of yarn : npm install --global yarn Then just run : yarn yarn standalone The requests to the cozy-stack will be stubbed using the [./fixture.json] file as source of data and when cozy-client is asked to create or update data, the data will be output to the console. The bills (or any file) will be saved in the . directory. With the cozy-stack \u00b6 If you do not want to have to install the konnector on a cozy v3 to test it, you can register the konnector as an OAuth application with the following commands : yarn yarn dev This command will register your konnector as an OAuth application to the cozy-stack. By default, the cozy-stack is supposed to be located in http://cozy.tools:8080. If this is not your case, just update the COZY_URL field in [./konnector-dev-config.json]. After that, your konnector is running but should not work since you did not specify any credentials to the target service. You can do this also in [./konnector-dev-config.json] in the \u201cfields\u201d attribute. You can also add js comments in this json configuration file, they will be stripped out when read by cozy-jobs-cli Now run yarn dev one more time, it should be ok. The files are saved in the root directory of your cozy by default. How does the cozy-stack run the connector ? \u00b6 The cozy-stack runs the connector in a nsjail container to be sure it does not affect the environment. The connector is run by calling yarn start with the following envrionment variables : COZY_CREDENTIALS needs to be the result of cozy-stack instances token-cli COZY_URL is the full http or https url to your cozy COZY_FIELDS contains context information for the konnector. Here is an example: { \"data\" : { \"attributes\" : { \"arguments\" : { \"account\" : \"cf31eaef5d899404a7e8c3737c1c2d1f\" , \"folder_to_save\" : \"folderPathId\" , \"slug\" : \"mykonnector\" } } } } The \u201caccount\u201d field is the id of the record with doctype \u201cio.cozy.accounts\u201d which will be used as parameters for your konnector. Build (without Travis) \u00b6 To be able to run the connector, the cozy stack needs a connector which is built into only one file, without needing to install its dependencies, this will be a lot faster to install. There is a command in package.json to help you to do that : yarn build This command uses [webpack] to bundle all the code needed by your connector into one file. This will generate an index.js file in the build directory and add all files the connector will need. You can deploy this build by using the specific script : yarn deploy This command will commit and push your build in the branch build fo your project. And your konnector can now be installed using the following url : git://github.com/konnectors/cozy-konnector- .git#build Build using Travis CI \u00b6 This project contains a .travis.yml config file which allows you to build your connector automatically using [Travis-CI][travis]. You can follow these steps to enable building using Travis: On your [travis-ci.org][travis] account, find your project name (should be the same than your Github repository) and enable Travis by using the related checkbox. Once enabled, go to this project on Travis by clicking on it and go to the \u201cSettings\u201d menu by using the \u201cMore options\u201d menu at the top right. Enable these three options: \u201cBuild only if .travis.yml is present\u201d \u201cBuild branch updates\u201d (run Travis after each branch update) \u201cBuild pull request updates\u201d (run Travis after each Pull Request update) Then, you have to generate a Github token in your Github account settings . Here is the Github blog post about API token . Don\u2019t forget to authorize the access to the repo scope like following: Then, add an environment variable (still in your Travis project settings) named GITHUB_TOKEN and use your previous generated Github token as value (We highly recommand you to keep the checkbox \u201cDisplay value in build log\u201d to OFF value in order to keep your token value hidden in the Travis logs.) Now Travis is ready to build your project, it should build it each time your push a commit in your repository or create a pull request. Note: Travis will push your build to your build branch ONLY for commits made on your master branch (included PR merge commits). You can see the related Travis statement here . Add your new connector to Cozy Collect \u00b6 The Cozy Collect application will soon use an application store as source of connectors. But for now, if you want to add your new connector to Cozy Collect, you can submit a message in the forum in the collect section , and we will handle this for you.", "title": "Develop"}, {"location": "cozy-konnector-libs/dev/#developing-a-konnector", "text": "", "title": "Developing a konnector"}, {"location": "cozy-konnector-libs/dev/#without-an-accessible-cozy-stack", "text": "If you just want to test this connector without any cozy available. You first need an installed [nodejs] (LTS version is fine). And the last version of yarn : npm install --global yarn Then just run : yarn yarn standalone The requests to the cozy-stack will be stubbed using the [./fixture.json] file as source of data and when cozy-client is asked to create or update data, the data will be output to the console. The bills (or any file) will be saved in the . directory.", "title": "Without an accessible cozy-stack"}, {"location": "cozy-konnector-libs/dev/#with-the-cozy-stack", "text": "If you do not want to have to install the konnector on a cozy v3 to test it, you can register the konnector as an OAuth application with the following commands : yarn yarn dev This command will register your konnector as an OAuth application to the cozy-stack. By default, the cozy-stack is supposed to be located in http://cozy.tools:8080. If this is not your case, just update the COZY_URL field in [./konnector-dev-config.json]. After that, your konnector is running but should not work since you did not specify any credentials to the target service. You can do this also in [./konnector-dev-config.json] in the \u201cfields\u201d attribute. You can also add js comments in this json configuration file, they will be stripped out when read by cozy-jobs-cli Now run yarn dev one more time, it should be ok. The files are saved in the root directory of your cozy by default.", "title": "With the cozy-stack"}, {"location": "cozy-konnector-libs/dev/#how-does-the-cozy-stack-run-the-connector", "text": "The cozy-stack runs the connector in a nsjail container to be sure it does not affect the environment. The connector is run by calling yarn start with the following envrionment variables : COZY_CREDENTIALS needs to be the result of cozy-stack instances token-cli COZY_URL is the full http or https url to your cozy COZY_FIELDS contains context information for the konnector. Here is an example: { \"data\" : { \"attributes\" : { \"arguments\" : { \"account\" : \"cf31eaef5d899404a7e8c3737c1c2d1f\" , \"folder_to_save\" : \"folderPathId\" , \"slug\" : \"mykonnector\" } } } } The \u201caccount\u201d field is the id of the record with doctype \u201cio.cozy.accounts\u201d which will be used as parameters for your konnector.", "title": "How does the cozy-stack run the connector ?"}, {"location": "cozy-konnector-libs/dev/#build-without-travis", "text": "To be able to run the connector, the cozy stack needs a connector which is built into only one file, without needing to install its dependencies, this will be a lot faster to install. There is a command in package.json to help you to do that : yarn build This command uses [webpack] to bundle all the code needed by your connector into one file. This will generate an index.js file in the build directory and add all files the connector will need. You can deploy this build by using the specific script : yarn deploy This command will commit and push your build in the branch build fo your project. And your konnector can now be installed using the following url : git://github.com/konnectors/cozy-konnector- .git#build", "title": "Build (without Travis)"}, {"location": "cozy-konnector-libs/dev/#build-using-travis-ci", "text": "This project contains a .travis.yml config file which allows you to build your connector automatically using [Travis-CI][travis]. You can follow these steps to enable building using Travis: On your [travis-ci.org][travis] account, find your project name (should be the same than your Github repository) and enable Travis by using the related checkbox. Once enabled, go to this project on Travis by clicking on it and go to the \u201cSettings\u201d menu by using the \u201cMore options\u201d menu at the top right. Enable these three options: \u201cBuild only if .travis.yml is present\u201d \u201cBuild branch updates\u201d (run Travis after each branch update) \u201cBuild pull request updates\u201d (run Travis after each Pull Request update) Then, you have to generate a Github token in your Github account settings . Here is the Github blog post about API token . Don\u2019t forget to authorize the access to the repo scope like following: Then, add an environment variable (still in your Travis project settings) named GITHUB_TOKEN and use your previous generated Github token as value (We highly recommand you to keep the checkbox \u201cDisplay value in build log\u201d to OFF value in order to keep your token value hidden in the Travis logs.) Now Travis is ready to build your project, it should build it each time your push a commit in your repository or create a pull request. Note: Travis will push your build to your build branch ONLY for commits made on your master branch (included PR merge commits). You can see the related Travis statement here .", "title": "Build using Travis CI"}, {"location": "cozy-konnector-libs/dev/#add-your-new-connector-to-cozy-collect", "text": "The Cozy Collect application will soon use an application store as source of connectors. But for now, if you want to add your new connector to Cozy Collect, you can submit a message in the forum in the collect section , and we will handle this for you.", "title": "Add your new connector to Cozy Collect"}, {"location": "cozy-konnector-libs/errors/", "text": "Communication with the outside \u00b6 Konnectors communicate with the stack via its stdout. Each line is parsed by the stack as JSON. When an error is thrown by the konnector, it is catched and translated to JSON. Message types \u00b6 This is the list of error codes that your konnector can throw and which will be translated by the collect application. Example : const login = function () { throw new Error('LOGIN_FAILED') } Collect will then signal to the user that the credentials used are not correct. Error code Meaning LOGIN_OK The konnector has logged in LOGIN_FAILED The konnector could not login NOT_EXISTING_DIRECTORY The folder specified as folder_to_save does not exist (checked by BaseKonnector) VENDOR_DOWN The vendor\u2019s website is down USER_ACTION_NEEDED The user needs to go to the vendor\u2019s website to fix something UNKNOWN_ERROR There was an unexpected error, please take a look at the logs to know what happened Sentry \u00b6 If process.env.SENTRY_DSN is set : Raven will be configured to send exception to this address the BaseKonnector will have its run method wrapped into a Raven.context so that when it fails, it sends the exception to Raven before exiting. The idea being that the process.env.SENTRY_DSN is only set up for people having opted in for exception handling. Self-hosted instances of the cozy-stack will be free to use or not our SENTRY_DSN.", "title": "Errors"}, {"location": "cozy-konnector-libs/errors/#communication-with-the-outside", "text": "Konnectors communicate with the stack via its stdout. Each line is parsed by the stack as JSON. When an error is thrown by the konnector, it is catched and translated to JSON.", "title": "Communication with the outside"}, {"location": "cozy-konnector-libs/errors/#message-types", "text": "This is the list of error codes that your konnector can throw and which will be translated by the collect application. Example : const login = function () { throw new Error('LOGIN_FAILED') } Collect will then signal to the user that the credentials used are not correct. Error code Meaning LOGIN_OK The konnector has logged in LOGIN_FAILED The konnector could not login NOT_EXISTING_DIRECTORY The folder specified as folder_to_save does not exist (checked by BaseKonnector) VENDOR_DOWN The vendor\u2019s website is down USER_ACTION_NEEDED The user needs to go to the vendor\u2019s website to fix something UNKNOWN_ERROR There was an unexpected error, please take a look at the logs to know what happened", "title": "Message types"}, {"location": "cozy-konnector-libs/errors/#sentry", "text": "If process.env.SENTRY_DSN is set : Raven will be configured to send exception to this address the BaseKonnector will have its run method wrapped into a Raven.context so that when it fails, it sends the exception to Raven before exiting. The idea being that the process.env.SENTRY_DSN is only set up for people having opted in for exception handling. Self-hosted instances of the cozy-stack will be free to use or not our SENTRY_DSN.", "title": "Sentry"}, {"location": "cozy-konnector-libs/operation-linking/", "text": "Linking bank operations \u00b6 When bills are saved via saveBills, we try to find a bank operation that matches it. Criterias for matching : Label : the label of the operation must match an identifier provided in the konnector For example, for SFR mobile, the identifiers that we try to find in the label is \u201csfr mobile\u201d. For SFR box, we try to find \u201csfr fixe\u201d and \u201csfr adsl\u201d. We try to find without the case. Date : the date of the banking operation must be +- 15 days of the bill Amount : the amount of the banking operation must be +-0.001 of the original bill amount Those criterias can be changed by the konnector themselves.", "title": "Operation linking"}, {"location": "cozy-konnector-libs/operation-linking/#linking-bank-operations", "text": "When bills are saved via saveBills, we try to find a bank operation that matches it. Criterias for matching : Label : the label of the operation must match an identifier provided in the konnector For example, for SFR mobile, the identifiers that we try to find in the label is \u201csfr mobile\u201d. For SFR box, we try to find \u201csfr fixe\u201d and \u201csfr adsl\u201d. We try to find without the case. Date : the date of the banking operation must be +- 15 days of the bill Amount : the amount of the banking operation must be +-0.001 of the original bill amount Those criterias can be changed by the konnector themselves.", "title": "Linking bank operations"}, {"location": "cozy-konnector-libs/synchronization/", "text": "Table of contents \u00b6 Konnector synchronisation data and options Problems Current usage Objectives of this document Storing synchronization data in documents Simple case, by id By multiple attributes By custom method Saving document based on synchronization strategy Adding synchronization data Filtering entries Synchronization strategy findLegacyDocument getSyncData Array Example function Example konnector shouldSave shouldUpdate Whole example Konnector synchronisation data and options \u00b6 Problems \u00b6 Except bank konnectors which are already solving the addressed problem, all konnectors are currently processing data they are collecting in the same way: Get all data to synchronize Store it in CouchDB, even if it means overriding previously synchronized data. This process has at least two major flows : * We are always synchronizing all the data provided by the external service. * When something is modified (for example, the name of the stored file, it\u2019s almost sure that the previous one will be kept and that we\u2019ll have a duplicate) Another side effect could be that in a very large set of documents to synchronize, the whole process may take more than 3 minutes and never synchronize documents at the end of the list. Current usage \u00b6 When saving bills, cozy-konnector-libs provides a filtering and hydratation mechanism, to avoid overriding existing bills. It is done in function hydrateAndFilters . This method performs two actions : * hydrate entries retrieved from service with usable data from couchDB (like existing bill id) * filter entries retrieved from service and return only entries that need to be saved/synchronized. Objectives of this document \u00b6 The goals of this document are: Define a common way to store synchronization data for all konnector Propose a naive implementation for an abstract synchronisation data storing mechanism, provided by cozy-konnector-libs Propose a solution to synchronize every type of data or file, not only bills Taking the hydrateAndFilter function as basis, split it in three functions performing the following tasks : actual filtering, synchronization data hydratation and saving/updating current database document with correspondig external entries (the part done by the actual hydratation ) Storing synchronization data in documents \u00b6 Before saving any data or file, we will add in the relying document every synchronization data we will need. The added data will depend on how the service the konnector connects to retrieve entries and which information they gave us. Simple case, by id \u00b6 We suppose that in the most cases, we will face to entries provinding their own id attribute. The idea is to store it as synchronization data to be able to easily retrieve them later. To store synchronization data, we are using a sync attribute in document metadata attribute. Example: { \"metadata\" : { \"sync\" : { \"id\" : \"7ee401e841c94159addb47f190903139\" , \"konnector\" : \"trainline\" , \"last_sync\" : \"Mon, 12 Feb 2018 16:25:34 GMT\" } } } The expected information to be save is: field role id The id of the document, but given by the external service. If the external service does not provide any id or uuid, it could be interesting to generate one, with an hash of the file for example. konnector The slug of the konnector (Example: trainline , freemobile , cic ). This could be very useful to retrieve data synchronized with this konnector. last_sync Date of last synchronization, set to now() when storage is made. By multiple attributes \u00b6 If the external service does not provide any id attribute, we may need to use instead a list of attributes, for example firstname , lastname , dateofbirth . { \"metadata\" : { \"sync\" : { \"firstname\" : \"Claude\" , \"lastname\" : \"Causi\" , \"dateofbirth\" : \"06/12/1980\" } } } As we cannot be sure that we will have different data, it could be better to use a custom way of providing an unique identifier. By custom method \u00b6 When the external service does not provide any identifier, we have to use a custom method to generate one. It could be for example the filename or a hash generated with the document content. { \"metadata\" : { \"sync\" : { \"id:\" : \"customhash34FED5465645ABF54656FCB\" } } } Saving document based on synchronization strategy \u00b6 To solve the synchronization process we need to: * be able to add synchronization data on any type of document * be able to compare external entries to current database state * provide a default implementation while letting the contributors to define their own ones Adding synchronization data \u00b6 We should provide an addSyncData function could, which look like this (naive implementation, this piece of code needs to be improved to handle cases where synchronizationStrategy.idAttribute is an array or a function): const addSyncData = ( document , entry , synchronizationStrategy ) => { return { ... document , metadata : { ... document . metadata , id : entry [ synchronizationStrategy . idAttribute ] } } ```` Where `document` is the future document to save , `entry` the corresponding external entry , and `synchronizationStrategy` and object defining the synchronization properties and methods ( see below ). ### Filtering entries Now we have saved our documents in database with consistent synchronization metadata , we need to provide a way to filter external entries . We should provide a `filterEntriesToSynchronize` which returns a list of entries with new data or data to update . As `addSyncData` , this method will receive a `synchronizationStrategy` . The filtering algorithm should be based on the returned value of `synchronizationStrategy.shouldSave` and `synchronizationStrategy.shouldUpdate` . > \u26a0\ufe0f As the `synchronizationStrategy.shouldSave` and `synchronizationStrategy.shouldUpdate` will be asynchronous methods , `filterEntriesToSynchronize` should also be asynchronous . A naive example of `filterEntriesToSynchronize` implementation should be : ```js const filterEntriesToSynchronize = async (cozy, entries, synchronizationStrategy) = { const filtered = [] entries.forEach(entry => { // getExistingSynchronizedDocument needs to be implemented, it should retrieve // existing document from database, based on synchronization data. const existingDocument = cozy.getExistingSynchronizedDocument(entry, synchronizationStrategy) const toSave = await synchronizationStrategy.shouldSave(entry, existingDocument) const toUpdate = await synchronizationStrategy.shouldUpdate(entry, existingDocument) if (toSave || toUpdate) filtered.push(entry) }) return filtered } Synchronization strategy \u00b6 For our functions or methods dealing with synchronization, we pass a synchronizationStrategy object. Internally, we will use a default one but let the ability to contributors to pass their own ones. It is a simple object containing the following properties: Option Role disableSyncData (boolean) Disable storage of synchronization data. Default: false findLegacyDocument (function) Custom function which a konnector may use to look for a legacy document. Default is null . See below for more details. getSyncData (function) A mapping method returning additional synchronization data which have to be added to the document. idAttribute (string|Array|function) How the identifier attribute is named in the entry. Default value: id . See below for additional customization konnector Mandatory (string) The slug (or better, an uuid) of the current konnector. shouldSave (function) A method taking current entry and matching document in database to evaluate if an entry has to be saved in database. See below default method and customization. shouldUpdate (function) A method taking current entry and matching document in database to evaluate if a document must be updated with current entry. See below for default method and customization. findLegacyDocument \u00b6 If a document has not been saved yet with actual synchronization data, we will have no way to retrieve it, except by providing a findLegacyDocument function to saveEntry options. This signature of a findLegacyDocument function is: async function ( entry , cozy ) => { /* look for your document */ } ```` The `cozy` parameter is an instance of Cozy - Client . The idea is for example to retrive a document by its file path or any other accurate information . ### getSyncData This method returns any addtional synchronization data the konnector should need . Default method should be something returning an empty object or `null` . ```js (entry) => ({}) A konnector should provide its own method: { getSyncData : ( entry ) => ({ filename : entry . name }) } ``` ### idAttribute #### String Name of the id attribute in entry. Default is ` id `. If we want to use another name, we may use: ``` js saveFiles ( files , { idAttribute : 'uuid' }) Array \u00b6 This attribute may also be an array of string, defining each entry attribute which must be used for identifier. Example \u00b6 saveFiles ( files , { idAttribute : [ 'name' , 'author' , 'date' ]}) In this case, all fields are used in synchronization data. function \u00b6 When an entry does not provide an unique identifer, it is possible to use a function as idAttribute to customize the way the unique identifer is generated. Example \u00b6 addData ( file , { idAttribute : ( entry ) => hash ( entry )}) // hash() is a custom method hashing the current file. konnector \u00b6 The konnector attribute is used as a key reference to retrieve all document synchronized by this konnector. For now, the konnector option will be needed for every call. But it could be interesting to initialize some kind of runner with it, which may encapsulate all the cozy-konnector-libs functions. shouldSave \u00b6 The shouldSave function returns a boolean which indicate if the entry should be saved. The default method should be: async function shouldSave ( entry , existingDocument , cozy ) => { return Promise . resolve ( ! existingDocument ) } When calling this function, it is assumed that cozy-konnector-libs first queries the database for an exisring document, based on synchronization data and pass the document resulting the query to the shouldSave function, event if this document is null . We pass the whole document, and not only synchronization data, to let the contributors free on their way they are determining it a document should be saved. As a third parameter, a cozyClient instance is passed, it may be used by a konnector to perform another query. Because of this third parameter, the whole shouldSave method is asynchronous. shouldUpdate \u00b6 The shouldUpdate function acts exactly like shouldSave , except that it is used to determine if a document should be updated. By default, we make the choice to never update a document (except if it does not have synchronization data, see findLegacyDocument above). But some konnectors like Linxo related ones need to update existing documents. The default method is: async function shouldUpdate ( entry , existingDocument , cozy ) { // Update an existing document only if it does not have synchronization data const hasSyncData = !! existingDocument && !! existingDocument . metadata && !! existingDocument . metadata . sync return Promise . resolve ( ! hasSyncData ) } ```` ## Whole example As the way data are saved from `cozy-konnector-libs` differs based on data type , we let the saving mechanism to others functions or methods . For example , in existing codebase , bills are saved in a specific way , resulting in two documents in database . However , we could provide top - level functions or methods , like `synchronizeBills` or a more generic `synchronizeData` . Here is a whole and naive example of how `synchronizeBills` could be implemebted : ```js const synchronizeBills = async (cozy, entries, synchronizationStrategy) => { return await filteredEntries = await filterEntriesToSynchronize(cozy, entries, synchronizationStrategy) .then(filteredEntries => filteredEntries.map(entry => addSyncData(entry, synchronizationStrategy))) // existing saveBills method (with maybe some little changes) .saveBills(synchronizedDocuments) } Usage could be: synchronizeBills(cozy, entries, { findLegacyDocument: (entry, cozy) => { return cozy.files.statByPath(getEntryPath(entry)) }, getSyncData: (file) => ({ fileName: file.name }), idAttribute: 'uuid', konnector: 'myservice', shouldSave: (file) => { // For whatever reason we only save files created after 2010 return Promise.resolve(moment(file.creationDate).year().isAfter(2010)) }, shouldUpdate: (file, existingDocument) => { const hasBeenModified = moment(file.modificationDate).isAfter(existingDocument.metadata.sync.last_sync) return Promise.resolve(hasBeenModified) } }) Every synchronized document will contain: { \"metadata\" : { \"sync\" : { \"konnector\" : \"myservice\" , \"id\" : \"\" , \"last_sync\" : \"\" , \"fileName\" : \"\" } } }", "title": "Synchronization"}, {"location": "cozy-konnector-libs/synchronization/#table-of-contents", "text": "Konnector synchronisation data and options Problems Current usage Objectives of this document Storing synchronization data in documents Simple case, by id By multiple attributes By custom method Saving document based on synchronization strategy Adding synchronization data Filtering entries Synchronization strategy findLegacyDocument getSyncData Array Example function Example konnector shouldSave shouldUpdate Whole example", "title": "Table of contents"}, {"location": "cozy-konnector-libs/synchronization/#konnector-synchronisation-data-and-options", "text": "", "title": "Konnector synchronisation data and options"}, {"location": "cozy-konnector-libs/synchronization/#problems", "text": "Except bank konnectors which are already solving the addressed problem, all konnectors are currently processing data they are collecting in the same way: Get all data to synchronize Store it in CouchDB, even if it means overriding previously synchronized data. This process has at least two major flows : * We are always synchronizing all the data provided by the external service. * When something is modified (for example, the name of the stored file, it\u2019s almost sure that the previous one will be kept and that we\u2019ll have a duplicate) Another side effect could be that in a very large set of documents to synchronize, the whole process may take more than 3 minutes and never synchronize documents at the end of the list.", "title": "Problems"}, {"location": "cozy-konnector-libs/synchronization/#current-usage", "text": "When saving bills, cozy-konnector-libs provides a filtering and hydratation mechanism, to avoid overriding existing bills. It is done in function hydrateAndFilters . This method performs two actions : * hydrate entries retrieved from service with usable data from couchDB (like existing bill id) * filter entries retrieved from service and return only entries that need to be saved/synchronized.", "title": "Current usage"}, {"location": "cozy-konnector-libs/synchronization/#objectives-of-this-document", "text": "The goals of this document are: Define a common way to store synchronization data for all konnector Propose a naive implementation for an abstract synchronisation data storing mechanism, provided by cozy-konnector-libs Propose a solution to synchronize every type of data or file, not only bills Taking the hydrateAndFilter function as basis, split it in three functions performing the following tasks : actual filtering, synchronization data hydratation and saving/updating current database document with correspondig external entries (the part done by the actual hydratation )", "title": "Objectives of this document"}, {"location": "cozy-konnector-libs/synchronization/#storing-synchronization-data-in-documents", "text": "Before saving any data or file, we will add in the relying document every synchronization data we will need. The added data will depend on how the service the konnector connects to retrieve entries and which information they gave us.", "title": "Storing synchronization data in documents"}, {"location": "cozy-konnector-libs/synchronization/#simple-case-by-id", "text": "We suppose that in the most cases, we will face to entries provinding their own id attribute. The idea is to store it as synchronization data to be able to easily retrieve them later. To store synchronization data, we are using a sync attribute in document metadata attribute. Example: { \"metadata\" : { \"sync\" : { \"id\" : \"7ee401e841c94159addb47f190903139\" , \"konnector\" : \"trainline\" , \"last_sync\" : \"Mon, 12 Feb 2018 16:25:34 GMT\" } } } The expected information to be save is: field role id The id of the document, but given by the external service. If the external service does not provide any id or uuid, it could be interesting to generate one, with an hash of the file for example. konnector The slug of the konnector (Example: trainline , freemobile , cic ). This could be very useful to retrieve data synchronized with this konnector. last_sync Date of last synchronization, set to now() when storage is made.", "title": "Simple case, by id"}, {"location": "cozy-konnector-libs/synchronization/#by-multiple-attributes", "text": "If the external service does not provide any id attribute, we may need to use instead a list of attributes, for example firstname , lastname , dateofbirth . { \"metadata\" : { \"sync\" : { \"firstname\" : \"Claude\" , \"lastname\" : \"Causi\" , \"dateofbirth\" : \"06/12/1980\" } } } As we cannot be sure that we will have different data, it could be better to use a custom way of providing an unique identifier.", "title": "By multiple attributes"}, {"location": "cozy-konnector-libs/synchronization/#by-custom-method", "text": "When the external service does not provide any identifier, we have to use a custom method to generate one. It could be for example the filename or a hash generated with the document content. { \"metadata\" : { \"sync\" : { \"id:\" : \"customhash34FED5465645ABF54656FCB\" } } }", "title": "By custom method"}, {"location": "cozy-konnector-libs/synchronization/#saving-document-based-on-synchronization-strategy", "text": "To solve the synchronization process we need to: * be able to add synchronization data on any type of document * be able to compare external entries to current database state * provide a default implementation while letting the contributors to define their own ones", "title": "Saving document based on synchronization strategy"}, {"location": "cozy-konnector-libs/synchronization/#adding-synchronization-data", "text": "We should provide an addSyncData function could, which look like this (naive implementation, this piece of code needs to be improved to handle cases where synchronizationStrategy.idAttribute is an array or a function): const addSyncData = ( document , entry , synchronizationStrategy ) => { return { ... document , metadata : { ... document . metadata , id : entry [ synchronizationStrategy . idAttribute ] } } ```` Where `document` is the future document to save , `entry` the corresponding external entry , and `synchronizationStrategy` and object defining the synchronization properties and methods ( see below ). ### Filtering entries Now we have saved our documents in database with consistent synchronization metadata , we need to provide a way to filter external entries . We should provide a `filterEntriesToSynchronize` which returns a list of entries with new data or data to update . As `addSyncData` , this method will receive a `synchronizationStrategy` . The filtering algorithm should be based on the returned value of `synchronizationStrategy.shouldSave` and `synchronizationStrategy.shouldUpdate` . > \u26a0\ufe0f As the `synchronizationStrategy.shouldSave` and `synchronizationStrategy.shouldUpdate` will be asynchronous methods , `filterEntriesToSynchronize` should also be asynchronous . A naive example of `filterEntriesToSynchronize` implementation should be : ```js const filterEntriesToSynchronize = async (cozy, entries, synchronizationStrategy) = { const filtered = [] entries.forEach(entry => { // getExistingSynchronizedDocument needs to be implemented, it should retrieve // existing document from database, based on synchronization data. const existingDocument = cozy.getExistingSynchronizedDocument(entry, synchronizationStrategy) const toSave = await synchronizationStrategy.shouldSave(entry, existingDocument) const toUpdate = await synchronizationStrategy.shouldUpdate(entry, existingDocument) if (toSave || toUpdate) filtered.push(entry) }) return filtered }", "title": "Adding synchronization data"}, {"location": "cozy-konnector-libs/synchronization/#synchronization-strategy", "text": "For our functions or methods dealing with synchronization, we pass a synchronizationStrategy object. Internally, we will use a default one but let the ability to contributors to pass their own ones. It is a simple object containing the following properties: Option Role disableSyncData (boolean) Disable storage of synchronization data. Default: false findLegacyDocument (function) Custom function which a konnector may use to look for a legacy document. Default is null . See below for more details. getSyncData (function) A mapping method returning additional synchronization data which have to be added to the document. idAttribute (string|Array|function) How the identifier attribute is named in the entry. Default value: id . See below for additional customization konnector Mandatory (string) The slug (or better, an uuid) of the current konnector. shouldSave (function) A method taking current entry and matching document in database to evaluate if an entry has to be saved in database. See below default method and customization. shouldUpdate (function) A method taking current entry and matching document in database to evaluate if a document must be updated with current entry. See below for default method and customization.", "title": "Synchronization strategy"}, {"location": "cozy-konnector-libs/synchronization/#findlegacydocument", "text": "If a document has not been saved yet with actual synchronization data, we will have no way to retrieve it, except by providing a findLegacyDocument function to saveEntry options. This signature of a findLegacyDocument function is: async function ( entry , cozy ) => { /* look for your document */ } ```` The `cozy` parameter is an instance of Cozy - Client . The idea is for example to retrive a document by its file path or any other accurate information . ### getSyncData This method returns any addtional synchronization data the konnector should need . Default method should be something returning an empty object or `null` . ```js (entry) => ({}) A konnector should provide its own method: { getSyncData : ( entry ) => ({ filename : entry . name }) } ``` ### idAttribute #### String Name of the id attribute in entry. Default is ` id `. If we want to use another name, we may use: ``` js saveFiles ( files , { idAttribute : 'uuid' })", "title": "findLegacyDocument"}, {"location": "cozy-konnector-libs/synchronization/#array", "text": "This attribute may also be an array of string, defining each entry attribute which must be used for identifier.", "title": "Array"}, {"location": "cozy-konnector-libs/synchronization/#example", "text": "saveFiles ( files , { idAttribute : [ 'name' , 'author' , 'date' ]}) In this case, all fields are used in synchronization data.", "title": "Example"}, {"location": "cozy-konnector-libs/synchronization/#function", "text": "When an entry does not provide an unique identifer, it is possible to use a function as idAttribute to customize the way the unique identifer is generated.", "title": "function"}, {"location": "cozy-konnector-libs/synchronization/#example_1", "text": "addData ( file , { idAttribute : ( entry ) => hash ( entry )}) // hash() is a custom method hashing the current file.", "title": "Example"}, {"location": "cozy-konnector-libs/synchronization/#konnector", "text": "The konnector attribute is used as a key reference to retrieve all document synchronized by this konnector. For now, the konnector option will be needed for every call. But it could be interesting to initialize some kind of runner with it, which may encapsulate all the cozy-konnector-libs functions.", "title": "konnector"}, {"location": "cozy-konnector-libs/synchronization/#shouldsave", "text": "The shouldSave function returns a boolean which indicate if the entry should be saved. The default method should be: async function shouldSave ( entry , existingDocument , cozy ) => { return Promise . resolve ( ! existingDocument ) } When calling this function, it is assumed that cozy-konnector-libs first queries the database for an exisring document, based on synchronization data and pass the document resulting the query to the shouldSave function, event if this document is null . We pass the whole document, and not only synchronization data, to let the contributors free on their way they are determining it a document should be saved. As a third parameter, a cozyClient instance is passed, it may be used by a konnector to perform another query. Because of this third parameter, the whole shouldSave method is asynchronous.", "title": "shouldSave"}, {"location": "cozy-konnector-libs/synchronization/#shouldupdate", "text": "The shouldUpdate function acts exactly like shouldSave , except that it is used to determine if a document should be updated. By default, we make the choice to never update a document (except if it does not have synchronization data, see findLegacyDocument above). But some konnectors like Linxo related ones need to update existing documents. The default method is: async function shouldUpdate ( entry , existingDocument , cozy ) { // Update an existing document only if it does not have synchronization data const hasSyncData = !! existingDocument && !! existingDocument . metadata && !! existingDocument . metadata . sync return Promise . resolve ( ! hasSyncData ) } ```` ## Whole example As the way data are saved from `cozy-konnector-libs` differs based on data type , we let the saving mechanism to others functions or methods . For example , in existing codebase , bills are saved in a specific way , resulting in two documents in database . However , we could provide top - level functions or methods , like `synchronizeBills` or a more generic `synchronizeData` . Here is a whole and naive example of how `synchronizeBills` could be implemebted : ```js const synchronizeBills = async (cozy, entries, synchronizationStrategy) => { return await filteredEntries = await filterEntriesToSynchronize(cozy, entries, synchronizationStrategy) .then(filteredEntries => filteredEntries.map(entry => addSyncData(entry, synchronizationStrategy))) // existing saveBills method (with maybe some little changes) .saveBills(synchronizedDocuments) } Usage could be: synchronizeBills(cozy, entries, { findLegacyDocument: (entry, cozy) => { return cozy.files.statByPath(getEntryPath(entry)) }, getSyncData: (file) => ({ fileName: file.name }), idAttribute: 'uuid', konnector: 'myservice', shouldSave: (file) => { // For whatever reason we only save files created after 2010 return Promise.resolve(moment(file.creationDate).year().isAfter(2010)) }, shouldUpdate: (file, existingDocument) => { const hasBeenModified = moment(file.modificationDate).isAfter(existingDocument.metadata.sync.last_sync) return Promise.resolve(hasBeenModified) } }) Every synchronized document will contain: { \"metadata\" : { \"sync\" : { \"konnector\" : \"myservice\" , \"id\" : \"\" , \"last_sync\" : \"\" , \"fileName\" : \"\" } } }", "title": "shouldUpdate"}, {"location": "cozy-notifications/", "text": "cozy-notifications provides tools to send notifications (push or email) from a Cozy application or konnector. Installation \u00b6 yarn add cozy-notifications You will most likely also need a custom webpack config if building for node (for example in konnectors, since mjml and its dependents are not built for node-js). webpack.config.js const webpackMerge = require ( 'webpack-merge' ) const cozyNotificationsWebpackConfig = require ( 'cozy-notifications/dist/webpack/config' ) module . exports = webpackMerge ({ // initialConfig }, cozyNotificationsWebpackConfig ) The custom webpack config provided by cozy-notifications applies aliases and resolves for cozy-notifications to be used in a build targetting node. sendNotification \u00b6 The main entrypoint of this library is sendNotifification(cozyClient, notificationView) . Before being able to use it, we need to define a notification view class. Notification views \u00b6 Notification views are responsible for fetching the data necessary for the notification providing a template for the notification configuring the notification ( category , channels ) deciding if the notification should be sent class MyNotification { async buildData () { return { // data that will be used in the template } } getPushContent () { return 'push content' } getTitle () { return 'title' } getExtraAttributes () { return { data : { // data that will be sent in the notification payload for mobiles redirectLink : \"settings/#/subscription\" } } } } MyNotification . template = require ( './template.hbs' ) getExtraAttributes \u00b6 In getExtraAttributes , you can pass data that will be sent in the notification payload for mobiles. getExtraAttributes () { return { data : { // Standardized. When opening the notification, it will open settings app on subscription page. redirectLink : \"settings/#/subscription\" , // Standardized. When opening the notification, it will refresh the app. refresh : true , // You can also pass whatever you want. age : 42 } } } In getExtraAttributes , you can also pass a state (only needed if your notification is stateful ). getExtraAttributes () { return { // State to send the notification only 1 time per day. state : new Date (). toLocaleDateString ( 'fr-FR' , { day : '2-digit' , month : '2-digit' , year : 'numeric' }) } } preferredChannels \u00b6 We can define one which channels the user will receive the notification. MyNotification . preferredChannels = [ 'mobile' , 'mail' ] In this example, we first try to send the notification to a mobile, and if it fails to the email address of the user. Some things to know : the stack has a fallback by email mechanism. So preferredChannels = ['mobile', 'mail'] is equivalent to preferredChannels = ['mobile'] . the stack do not check the delivery of the email. So if you set preferredChannels = ['mail', 'mobile'] , it is very unlikely that a mobile notification will be sent. mobile \u00b6 The mobile channels consists of a push notification. Its title will be the result of the getTitle method and its content will be the result of getPushContent . mail \u00b6 Emails need more markup and thus will need the template class attribute. They are written in mjml , making it possible to write good looking emails in every major mail client. Templates \u00b6 Templates serve for the HTML content of emails. Templates used in notification views are based on handlebars for templating handlebars-layouts to be able to extend layouts mjml to build responsive emails This makes it simple to create emails that are based on built-in templates. For now cozy-notifications supports only the pre-built cozy-layout template. This template has the following parts to be filled: appName topLogo appURL footerHelp content Since appName , topLogo and appURL will mostly never change inside a particular application, it is advised to create a template extending cozy-layout in your application and then refer to it in each of your email templates. To provide the content for a particular part, use the following syntax: {{ #content \"part\" }} Content of the part {{ /content }} where you replace \"part\" with the name of the part you want to fill. Note: it is advised in an application to have your templates inside .hbs files for syntax coloring to work correctly. You must configure your bundler and/or test runner to require those files correctly. app-layout.hbs {{ #extend \"cozy-layout\" }} {{ #content \"logoUrl\" }} https://example.com/logo-url {{ /content }} {{ #content \"appName\" }} My App {{ /content }} {{ #content \"topLogo\" }} {{ /content }} {{ #content \"appURL\" }} https://my-app.com {{ /content }} {{ #content \"footerHelp\" }} {{ tGlobal @ root.lang 'settings' }} {{ tGlobal @ root.lang 'support' }} {{ /content }} {{ /extend }} Now that we have provided generic parts, we can code a particular template. A sample template for a particular notification: my-notification.hbs {{ #extend \"app-layout\" }} {{ #content \"emailTitle\" }} A notification from My App ! {{ /content }} {{ #content \"emailSubtitle\" }} You should read this :) {{ /content }} {{ #content \"content\" }} {{ greeting name }} , Just to tell you that My App is awesome ! {{ /content }} {{ /extend }} We can now use our template for a notification view. import template from './my-notification.hbs' import appTemplate from './app-layout.hbs' import { NotificationView } from 'cozy-notifications' class MyNotificationView extends NotificationView { getPartials () { return { 'app-layout' : appTemplate } } } MyNotificationView . template = template Accessing different parts \u00b6 cozy-notifications is built with the vision that in the future, the whole email will not be sent directly to the stack, but only rendered parts will be sent; in other words, only appURL , topLogo , content etc\u2026 will be sent, instead of the whole content). This is why cozy-notifications needs to know our uncompiled partials. We can destructure parts to access rendered parts. import { renderer } from 'cozy-notifications' const render = renderer ({ partials , helpers }) const { parts } = render ({ template , data }) // { \"emailTitle\": \"A notification from My App !\", ... } Built-in helpers \u00b6 t will be passed automatically as a helper in templates. We must pass the locales object when instantiating the NotificationView. const locales = { de : { hello : \"Guten Tag %{name} !\" } } const myNotifView = new MyNotificationView ({ ..., locales }) {{ t \"hello\" name = 'Homer' }} webLink is able to build links that go the web version of an app {{ webLink slug = \"home\" }} universalLink is able to build links that use automatically the web or mobile version the app {{ universalLink slug = \"banks\" }} palette lets you pick a color by giving its \u2013varName. A primary button Related documentation \u00b6 Notification configuration and routes on cozy-stack Notification custom behavior for flagship app on cozy-stack How to debug notifications on flagship app How to debug notifications on cozy-banks How notifications have been added in devtools on cozy-banks", "title": "Send notifications (cozy-notifications)"}, {"location": "cozy-notifications/#installation", "text": "yarn add cozy-notifications You will most likely also need a custom webpack config if building for node (for example in konnectors, since mjml and its dependents are not built for node-js). webpack.config.js const webpackMerge = require ( 'webpack-merge' ) const cozyNotificationsWebpackConfig = require ( 'cozy-notifications/dist/webpack/config' ) module . exports = webpackMerge ({ // initialConfig }, cozyNotificationsWebpackConfig ) The custom webpack config provided by cozy-notifications applies aliases and resolves for cozy-notifications to be used in a build targetting node.", "title": "Installation"}, {"location": "cozy-notifications/#sendnotification", "text": "The main entrypoint of this library is sendNotifification(cozyClient, notificationView) . Before being able to use it, we need to define a notification view class.", "title": "sendNotification"}, {"location": "cozy-notifications/#notification-views", "text": "Notification views are responsible for fetching the data necessary for the notification providing a template for the notification configuring the notification ( category , channels ) deciding if the notification should be sent class MyNotification { async buildData () { return { // data that will be used in the template } } getPushContent () { return 'push content' } getTitle () { return 'title' } getExtraAttributes () { return { data : { // data that will be sent in the notification payload for mobiles redirectLink : \"settings/#/subscription\" } } } } MyNotification . template = require ( './template.hbs' )", "title": "Notification views"}, {"location": "cozy-notifications/#getextraattributes", "text": "In getExtraAttributes , you can pass data that will be sent in the notification payload for mobiles. getExtraAttributes () { return { data : { // Standardized. When opening the notification, it will open settings app on subscription page. redirectLink : \"settings/#/subscription\" , // Standardized. When opening the notification, it will refresh the app. refresh : true , // You can also pass whatever you want. age : 42 } } } In getExtraAttributes , you can also pass a state (only needed if your notification is stateful ). getExtraAttributes () { return { // State to send the notification only 1 time per day. state : new Date (). toLocaleDateString ( 'fr-FR' , { day : '2-digit' , month : '2-digit' , year : 'numeric' }) } }", "title": "getExtraAttributes"}, {"location": "cozy-notifications/#preferredchannels", "text": "We can define one which channels the user will receive the notification. MyNotification . preferredChannels = [ 'mobile' , 'mail' ] In this example, we first try to send the notification to a mobile, and if it fails to the email address of the user. Some things to know : the stack has a fallback by email mechanism. So preferredChannels = ['mobile', 'mail'] is equivalent to preferredChannels = ['mobile'] . the stack do not check the delivery of the email. So if you set preferredChannels = ['mail', 'mobile'] , it is very unlikely that a mobile notification will be sent.", "title": "preferredChannels"}, {"location": "cozy-notifications/#mobile", "text": "The mobile channels consists of a push notification. Its title will be the result of the getTitle method and its content will be the result of getPushContent .", "title": "mobile"}, {"location": "cozy-notifications/#mail", "text": "Emails need more markup and thus will need the template class attribute. They are written in mjml , making it possible to write good looking emails in every major mail client.", "title": "mail"}, {"location": "cozy-notifications/#templates", "text": "Templates serve for the HTML content of emails. Templates used in notification views are based on handlebars for templating handlebars-layouts to be able to extend layouts mjml to build responsive emails This makes it simple to create emails that are based on built-in templates. For now cozy-notifications supports only the pre-built cozy-layout template. This template has the following parts to be filled: appName topLogo appURL footerHelp content Since appName , topLogo and appURL will mostly never change inside a particular application, it is advised to create a template extending cozy-layout in your application and then refer to it in each of your email templates. To provide the content for a particular part, use the following syntax: {{ #content \"part\" }} Content of the part {{ /content }} where you replace \"part\" with the name of the part you want to fill. Note: it is advised in an application to have your templates inside .hbs files for syntax coloring to work correctly. You must configure your bundler and/or test runner to require those files correctly. app-layout.hbs {{ #extend \"cozy-layout\" }} {{ #content \"logoUrl\" }} https://example.com/logo-url {{ /content }} {{ #content \"appName\" }} My App {{ /content }} {{ #content \"topLogo\" }} {{ /content }} {{ #content \"appURL\" }} https://my-app.com {{ /content }} {{ #content \"footerHelp\" }} {{ tGlobal @ root.lang 'settings' }} {{ tGlobal @ root.lang 'support' }} {{ /content }} {{ /extend }} Now that we have provided generic parts, we can code a particular template. A sample template for a particular notification: my-notification.hbs {{ #extend \"app-layout\" }} {{ #content \"emailTitle\" }} A notification from My App ! {{ /content }} {{ #content \"emailSubtitle\" }} You should read this :) {{ /content }} {{ #content \"content\" }} {{ greeting name }} , Just to tell you that My App is awesome ! {{ /content }} {{ /extend }} We can now use our template for a notification view. import template from './my-notification.hbs' import appTemplate from './app-layout.hbs' import { NotificationView } from 'cozy-notifications' class MyNotificationView extends NotificationView { getPartials () { return { 'app-layout' : appTemplate } } } MyNotificationView . template = template", "title": "Templates"}, {"location": "cozy-notifications/#accessing-different-parts", "text": "cozy-notifications is built with the vision that in the future, the whole email will not be sent directly to the stack, but only rendered parts will be sent; in other words, only appURL , topLogo , content etc\u2026 will be sent, instead of the whole content). This is why cozy-notifications needs to know our uncompiled partials. We can destructure parts to access rendered parts. import { renderer } from 'cozy-notifications' const render = renderer ({ partials , helpers }) const { parts } = render ({ template , data }) // { \"emailTitle\": \"A notification from My App !\", ... }", "title": "Accessing different parts"}, {"location": "cozy-notifications/#built-in-helpers", "text": "t will be passed automatically as a helper in templates. We must pass the locales object when instantiating the NotificationView. const locales = { de : { hello : \"Guten Tag %{name} !\" } } const myNotifView = new MyNotificationView ({ ..., locales }) {{ t \"hello\" name = 'Homer' }} webLink is able to build links that go the web version of an app {{ webLink slug = \"home\" }} universalLink is able to build links that use automatically the web or mobile version the app {{ universalLink slug = \"banks\" }} palette lets you pick a color by giving its \u2013varName. A primary button ", "title": "Built-in helpers"}, {"location": "cozy-notifications/#related-documentation", "text": "Notification configuration and routes on cozy-stack Notification custom behavior for flagship app on cozy-stack How to debug notifications on flagship app How to debug notifications on cozy-banks How notifications have been added in devtools on cozy-banks", "title": "Related documentation"}, {"location": "cozy-notifications/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 0.16.3 (2024-05-27) \u00b6 Note: Version bump only for package cozy-notifications 0.16.2 (2024-03-15) \u00b6 Bug Fixes \u00b6 Minimize services when cozy-notifications is used ( 244f95c ) 0.16.1 (2024-03-11) \u00b6 Note: Version bump only for package cozy-notifications 0.16.0 (2024-03-06) \u00b6 Features \u00b6 mespapiers: Use showAlert instead Alerter into downloadFiles func ( 68ec498 ) 0.15.0 (2024-02-07) \u00b6 Bug Fixes \u00b6 Correct handlebars resolution for webpack config ( 6e5e673 ) Package mjml can not be minimized ( dd7bbf4 ) Features \u00b6 Add a FileSharingProvider to expose feature from flagship app ( dbf10d4 ) Add a rule to load .hbs with raw-loader ( 2df8f4f ) Remove shebang-loader rules ( 87a9c74 ) Remove unused mimer-parser ( 647fa35 ) Update packages ( b07dfaf ) 0.14.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 0.13.2 (2022-02-18) \u00b6 Bug Fixes \u00b6 deps: pin dependencies ( e53d065 ) 0.13.1 (2022-02-01) \u00b6 Bug Fixes \u00b6 deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 ) 0.13.0 (2021-12-02) \u00b6 Features \u00b6 Add confirm trusted recipients dialog ( dfe1695 ) 0.12.0 (2021-02-12) \u00b6 Features \u00b6 Add finance theme ( bb8cf35 ) 0.11.0 (2020-11-30) \u00b6 Features \u00b6 Update cozy-ui minimal versions ( 7e7755f ) 0.10.0 (2020-11-23) \u00b6 Features \u00b6 All babel cli at 7.12.1 ( 387a24a ) Update @babel/core and babel-jest ( 352ddc3 ) Use ^ for dependencies ( fc28de7 ) 0.9.2 (2020-11-11) \u00b6 Note: Version bump only for package cozy-notifications 0.9.1 (2020-10-07) \u00b6 Note: Version bump only for package cozy-notifications 0.9.0 (2020-08-21) \u00b6 Features \u00b6 Update cozy-ui across all libs ( 73549b0 ) 0.8.0 (2020-08-12) \u00b6 Features \u00b6 Apply strict validation ( 0a349dc ) 0.7.1 (2020-07-21) \u00b6 Bug Fixes \u00b6 Use same Cozy-UI and CozyClient version everywhere ( 6216e62 ) 0.7.0 (2020-07-20) \u00b6 Features \u00b6 Update cozy-ui ( a8710f9 ) 0.6.0 (2020-07-16) \u00b6 Bug Fixes \u00b6 Call revokeSelf if not the owner of the sharing ( f7afc60 ) Features \u00b6 Update lodash accross all packages ( 6a20128 ) 0.5.0 (2020-02-24) \u00b6 Features \u00b6 Update cozy-bi-auth ( fc191ee ) 0.4.3 (2020-01-08) \u00b6 Bug Fixes \u00b6 Only set lang inside templateData if it is defined ( 3cf875b ) 0.4.2 (2019-11-28) \u00b6 Bug Fixes \u00b6 Few comments / lang ( 88eaf27 ) 0.4.1 (2019-11-06) \u00b6 Note: Version bump only for package cozy-notifications 0.4.0 (2019-10-01) \u00b6 Features \u00b6 Provide webpack config for project using cozy-notifications ( 8812519 ) 0.3.2 (2019-09-26) \u00b6 Bug Fixes \u00b6 Rename mjml to mjmlUtils to prevent conflicts ( ae3b2d9 ) 0.3.0 (2019-09-26) \u00b6 Bug Fixes \u00b6 Get push content is called with the correct this ( 7423d80 ) Improve textual representation of links ( 25b58aa ) Rename cssUtils since otherwise css.js can be thought to be a CSS files ( 684a9d8 ) Set extra attributes correctly ( d94be21 ) Should send needs template data ( a5363c2 ) toText method is on the class ( 44763d0 ) Features \u00b6 Export build attributes ( 775991e ) 0.2.0 (2019-09-25) \u00b6 Features \u00b6 Automatic conversion to text email ( 4920070 ) notifs: Automatic conversion HTML to text ( 5189ce1 ) Automatic toText ( #811 ) ( 1826b3b ) 0.1.0 (2019-09-25) \u00b6 Bug Fixes \u00b6 Add index.js ( 3f229d6 ) Example ( 7ba461c ) Features \u00b6 Ability to use palette via CSS vars ( a77d44a ) Activate module transform in babel ( 483046c ) Add notification utils ( 4b5e84a ) Built-in helpers and NotificationView ( 84b95ed ) Palette helper ( 6b85f7d ) Use MJML 4 ( b867820 )", "title": "Change Log"}, {"location": "cozy-notifications/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "cozy-notifications/CHANGELOG/#0163-2024-05-27", "text": "Note: Version bump only for package cozy-notifications", "title": "0.16.3 (2024-05-27)"}, {"location": "cozy-notifications/CHANGELOG/#0162-2024-03-15", "text": "", "title": "0.16.2 (2024-03-15)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes", "text": "Minimize services when cozy-notifications is used ( 244f95c )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#0161-2024-03-11", "text": "Note: Version bump only for package cozy-notifications", "title": "0.16.1 (2024-03-11)"}, {"location": "cozy-notifications/CHANGELOG/#0160-2024-03-06", "text": "", "title": "0.16.0 (2024-03-06)"}, {"location": "cozy-notifications/CHANGELOG/#features", "text": "mespapiers: Use showAlert instead Alerter into downloadFiles func ( 68ec498 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#0150-2024-02-07", "text": "", "title": "0.15.0 (2024-02-07)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_1", "text": "Correct handlebars resolution for webpack config ( 6e5e673 ) Package mjml can not be minimized ( dd7bbf4 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#features_1", "text": "Add a FileSharingProvider to expose feature from flagship app ( dbf10d4 ) Add a rule to load .hbs with raw-loader ( 2df8f4f ) Remove shebang-loader rules ( 87a9c74 ) Remove unused mimer-parser ( 647fa35 ) Update packages ( b07dfaf )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#0140-2023-01-31", "text": "", "title": "0.14.0 (2023-01-31)"}, {"location": "cozy-notifications/CHANGELOG/#features_2", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#0132-2022-02-18", "text": "", "title": "0.13.2 (2022-02-18)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_2", "text": "deps: pin dependencies ( e53d065 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#0131-2022-02-01", "text": "", "title": "0.13.1 (2022-02-01)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_3", "text": "deps: update babel monorepo ( dcc215a ) Handle empty context ( 6258e12 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#0130-2021-12-02", "text": "", "title": "0.13.0 (2021-12-02)"}, {"location": "cozy-notifications/CHANGELOG/#features_3", "text": "Add confirm trusted recipients dialog ( dfe1695 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#0120-2021-02-12", "text": "", "title": "0.12.0 (2021-02-12)"}, {"location": "cozy-notifications/CHANGELOG/#features_4", "text": "Add finance theme ( bb8cf35 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#0110-2020-11-30", "text": "", "title": "0.11.0 (2020-11-30)"}, {"location": "cozy-notifications/CHANGELOG/#features_5", "text": "Update cozy-ui minimal versions ( 7e7755f )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#0100-2020-11-23", "text": "", "title": "0.10.0 (2020-11-23)"}, {"location": "cozy-notifications/CHANGELOG/#features_6", "text": "All babel cli at 7.12.1 ( 387a24a ) Update @babel/core and babel-jest ( 352ddc3 ) Use ^ for dependencies ( fc28de7 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#092-2020-11-11", "text": "Note: Version bump only for package cozy-notifications", "title": "0.9.2 (2020-11-11)"}, {"location": "cozy-notifications/CHANGELOG/#091-2020-10-07", "text": "Note: Version bump only for package cozy-notifications", "title": "0.9.1 (2020-10-07)"}, {"location": "cozy-notifications/CHANGELOG/#090-2020-08-21", "text": "", "title": "0.9.0 (2020-08-21)"}, {"location": "cozy-notifications/CHANGELOG/#features_7", "text": "Update cozy-ui across all libs ( 73549b0 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#080-2020-08-12", "text": "", "title": "0.8.0 (2020-08-12)"}, {"location": "cozy-notifications/CHANGELOG/#features_8", "text": "Apply strict validation ( 0a349dc )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#071-2020-07-21", "text": "", "title": "0.7.1 (2020-07-21)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_4", "text": "Use same Cozy-UI and CozyClient version everywhere ( 6216e62 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#070-2020-07-20", "text": "", "title": "0.7.0 (2020-07-20)"}, {"location": "cozy-notifications/CHANGELOG/#features_9", "text": "Update cozy-ui ( a8710f9 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#060-2020-07-16", "text": "", "title": "0.6.0 (2020-07-16)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_5", "text": "Call revokeSelf if not the owner of the sharing ( f7afc60 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#features_10", "text": "Update lodash accross all packages ( 6a20128 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#050-2020-02-24", "text": "", "title": "0.5.0 (2020-02-24)"}, {"location": "cozy-notifications/CHANGELOG/#features_11", "text": "Update cozy-bi-auth ( fc191ee )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#043-2020-01-08", "text": "", "title": "0.4.3 (2020-01-08)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_6", "text": "Only set lang inside templateData if it is defined ( 3cf875b )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#042-2019-11-28", "text": "", "title": "0.4.2 (2019-11-28)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_7", "text": "Few comments / lang ( 88eaf27 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#041-2019-11-06", "text": "Note: Version bump only for package cozy-notifications", "title": "0.4.1 (2019-11-06)"}, {"location": "cozy-notifications/CHANGELOG/#040-2019-10-01", "text": "", "title": "0.4.0 (2019-10-01)"}, {"location": "cozy-notifications/CHANGELOG/#features_12", "text": "Provide webpack config for project using cozy-notifications ( 8812519 )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#032-2019-09-26", "text": "", "title": "0.3.2 (2019-09-26)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_8", "text": "Rename mjml to mjmlUtils to prevent conflicts ( ae3b2d9 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#030-2019-09-26", "text": "", "title": "0.3.0 (2019-09-26)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_9", "text": "Get push content is called with the correct this ( 7423d80 ) Improve textual representation of links ( 25b58aa ) Rename cssUtils since otherwise css.js can be thought to be a CSS files ( 684a9d8 ) Set extra attributes correctly ( d94be21 ) Should send needs template data ( a5363c2 ) toText method is on the class ( 44763d0 )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#features_13", "text": "Export build attributes ( 775991e )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#020-2019-09-25", "text": "", "title": "0.2.0 (2019-09-25)"}, {"location": "cozy-notifications/CHANGELOG/#features_14", "text": "Automatic conversion to text email ( 4920070 ) notifs: Automatic conversion HTML to text ( 5189ce1 ) Automatic toText ( #811 ) ( 1826b3b )", "title": "Features"}, {"location": "cozy-notifications/CHANGELOG/#010-2019-09-25", "text": "", "title": "0.1.0 (2019-09-25)"}, {"location": "cozy-notifications/CHANGELOG/#bug-fixes_10", "text": "Add index.js ( 3f229d6 ) Example ( 7ba461c )", "title": "Bug Fixes"}, {"location": "cozy-notifications/CHANGELOG/#features_15", "text": "Ability to use palette via CSS vars ( a77d44a ) Activate module transform in babel ( 483046c ) Add notification utils ( 4b5e84a ) Built-in helpers and NotificationView ( 84b95ed ) Palette helper ( 6b85f7d ) Use MJML 4 ( b867820 )", "title": "Features"}, {"location": "cozy-realtime/", "text": "Cozy Realtime Subscribe to cozy-stack server side events cozy-stack via Websocket. Install \u00b6 npm install --save cozy-realtime ` yarn add cozy-realtime Setup \u00b6 CozyRealtime comes with a plugin for cozy-client . This is the recommended way to setup: // setup.js import CozyClient from 'cozy-client' import { RealtimePlugin } from 'cozy-realtime' const client = new CozyClient ({}) client . registerPlugin ( RealtimePlugin ) Then, you can listen for a whole doctype, thanks to the component, provided by cozy-client . This will automatically subscribe to all the events occuring on the specified doctype and accordingly update the store, so your app will reflect the data changes in realtime. // App.js import { RealTimeQueries } from 'cozy-client' < App > < RealTimeQueries doctype = \"io.cozy.files\" /> ... Simple, isn\u2019t it? You can also provide your own method to instantiate Websockets. This can be useful when using cozy-realtime from a Node application for example. // main.node.js import { Agent } from 'http' import { WebSocket } from 'ws' import CozyClient from 'cozy-client' import { RealtimePlugin } from 'cozy-realtime' const agent = new Agent ({ keepAlive : true }) const createWebSocket = ( uri , protocol ) => { return new WebSocket ( uri , protocol , { agent }) } const client = new CozyClient ({}) client . registerPlugin ( RealtimePlugin , { createWebSocket }) Manual subscribe \u00b6 If your app needs to handle specific events on the data, you need to subscribe/unsubscribe like this: const realtime = client . plugins . realtime realtime . subscribe ( 'created' , 'io.cozy.bank.accounts' , handleBankAccountCreated ) realtime . unsubscribe ( 'created' , 'io.cozy.bank.accounts' , handleBankAccountCreated ) Example \u00b6 It is important to unsubscribe when unmounting React components. // some-component.js const handleCreate = accounts => { console . log ( `A new 'io.cozy.accounts' is created with id ' ${ accounts . _id } '.` ) } const handleUpdate = accounts => { console . log ( `An account is updated with id ' ${ accounts . _id } '.` ) } class MyComp extends Component { constructor ( props ){ super ( props ) } componentDidMount (){ this . realtime = this . props . client . plugins . realtime if ( this . realtime ){ // Listen to document creations await this . realtime . subscribe ( 'created' , type , this . handleCreate ) //listen of the update for a type await this . realtime . subscribe ( 'updated' , type , this . handleUpdate ) // Listen to a specific document await this . realtime . subscribe ( 'updated' , type , id , this . handleUpdate ) } } componentWillUnmount (){ if ( this . realtime ){ // To unsubscribe await this . realtime . unsubscribe ( 'created' , type , handleCreate ) await this . realtime . unsubscribe ( 'updated' , type , handleUpdate ) await this . realtime . unsubscribe ( 'updated' , type , id , handleUpdate ) // To unsubscribe all await this . realtime . unsubscribeAll () } } } export default withClient ( MyComp ) Subscribe to multiple events \u00b6 Here we subscribe to The creation event The update of a single document import CozyRealtime from 'cozy-realtime' /** * In Node applications, provide a function to instantiate Websockets: * * const createWebSocket = (uri, protocol) => { ... } * * const realtime = new CozyRealtime({ client: cozyClient, createWebSocket }) * */ const realtime = new CozyRealtime ({ client : cozyClient }) const type = 'io.cozy.accounts' const id = 'document_id' const handleCreate = accounts => { console . log ( `A new 'io.cozy.accounts' is created with id ' ${ accounts . _id } '.` ) } const handleUpdate = accounts => { console . log ( `An account is updated with id ' ${ accounts . _id } '.` ) } // To subscribe await realtime . subscribe ( 'created' , type , handleCreate ) await realtime . subscribe ( 'updated' , type , id , handleUpdate ) // To unsubscribe await realtime . unsubscribe ( 'created' , type , handleCreate ) await realtime . unsubscribe ( 'updated' , type , id , handleUpdate ) // To unsubscribe all events in one go await realtime . unsubscribeAll () License \u00b6 cozy-realtime is distributed under the MIT license.", "title": "Realtime data (realtime)"}, {"location": "cozy-realtime/#install", "text": "npm install --save cozy-realtime ` yarn add cozy-realtime", "title": "Install"}, {"location": "cozy-realtime/#setup", "text": "CozyRealtime comes with a plugin for cozy-client . This is the recommended way to setup: // setup.js import CozyClient from 'cozy-client' import { RealtimePlugin } from 'cozy-realtime' const client = new CozyClient ({}) client . registerPlugin ( RealtimePlugin ) Then, you can listen for a whole doctype, thanks to the component, provided by cozy-client . This will automatically subscribe to all the events occuring on the specified doctype and accordingly update the store, so your app will reflect the data changes in realtime. // App.js import { RealTimeQueries } from 'cozy-client' < App > < RealTimeQueries doctype = \"io.cozy.files\" /> ... Simple, isn\u2019t it? You can also provide your own method to instantiate Websockets. This can be useful when using cozy-realtime from a Node application for example. // main.node.js import { Agent } from 'http' import { WebSocket } from 'ws' import CozyClient from 'cozy-client' import { RealtimePlugin } from 'cozy-realtime' const agent = new Agent ({ keepAlive : true }) const createWebSocket = ( uri , protocol ) => { return new WebSocket ( uri , protocol , { agent }) } const client = new CozyClient ({}) client . registerPlugin ( RealtimePlugin , { createWebSocket })", "title": "Setup"}, {"location": "cozy-realtime/#manual-subscribe", "text": "If your app needs to handle specific events on the data, you need to subscribe/unsubscribe like this: const realtime = client . plugins . realtime realtime . subscribe ( 'created' , 'io.cozy.bank.accounts' , handleBankAccountCreated ) realtime . unsubscribe ( 'created' , 'io.cozy.bank.accounts' , handleBankAccountCreated )", "title": "Manual subscribe"}, {"location": "cozy-realtime/#example", "text": "It is important to unsubscribe when unmounting React components. // some-component.js const handleCreate = accounts => { console . log ( `A new 'io.cozy.accounts' is created with id ' ${ accounts . _id } '.` ) } const handleUpdate = accounts => { console . log ( `An account is updated with id ' ${ accounts . _id } '.` ) } class MyComp extends Component { constructor ( props ){ super ( props ) } componentDidMount (){ this . realtime = this . props . client . plugins . realtime if ( this . realtime ){ // Listen to document creations await this . realtime . subscribe ( 'created' , type , this . handleCreate ) //listen of the update for a type await this . realtime . subscribe ( 'updated' , type , this . handleUpdate ) // Listen to a specific document await this . realtime . subscribe ( 'updated' , type , id , this . handleUpdate ) } } componentWillUnmount (){ if ( this . realtime ){ // To unsubscribe await this . realtime . unsubscribe ( 'created' , type , handleCreate ) await this . realtime . unsubscribe ( 'updated' , type , handleUpdate ) await this . realtime . unsubscribe ( 'updated' , type , id , handleUpdate ) // To unsubscribe all await this . realtime . unsubscribeAll () } } } export default withClient ( MyComp )", "title": "Example"}, {"location": "cozy-realtime/#subscribe-to-multiple-events", "text": "Here we subscribe to The creation event The update of a single document import CozyRealtime from 'cozy-realtime' /** * In Node applications, provide a function to instantiate Websockets: * * const createWebSocket = (uri, protocol) => { ... } * * const realtime = new CozyRealtime({ client: cozyClient, createWebSocket }) * */ const realtime = new CozyRealtime ({ client : cozyClient }) const type = 'io.cozy.accounts' const id = 'document_id' const handleCreate = accounts => { console . log ( `A new 'io.cozy.accounts' is created with id ' ${ accounts . _id } '.` ) } const handleUpdate = accounts => { console . log ( `An account is updated with id ' ${ accounts . _id } '.` ) } // To subscribe await realtime . subscribe ( 'created' , type , handleCreate ) await realtime . subscribe ( 'updated' , type , id , handleUpdate ) // To unsubscribe await realtime . unsubscribe ( 'created' , type , handleCreate ) await realtime . unsubscribe ( 'updated' , type , id , handleUpdate ) // To unsubscribe all events in one go await realtime . unsubscribeAll ()", "title": "Subscribe to multiple events"}, {"location": "cozy-realtime/#license", "text": "cozy-realtime is distributed under the MIT license.", "title": "License"}, {"location": "cozy-realtime/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 5.0.1 (2024-05-31) \u00b6 Note: Version bump only for package cozy-realtime 5.0.0 (2023-08-23) \u00b6 Features \u00b6 harvest: Update cozy-client from 38.6.0 to 40.2.0 ( 8931b15 ) BREAKING CHANGES \u00b6 harvest: you must have cozy-client >= 40.2.0 4.6.0 (2023-06-09) \u00b6 Bug Fixes \u00b6 mespapiers: The back button hover area is oval instead of round ( 35d6f4d ) Features \u00b6 Allow passing a custom logger to realtime ( 8841b71 ) 4.5.0 (2023-05-17) \u00b6 Features \u00b6 Allow using non-native WebSocket ( 827f6e4 ) Remove mespapiers.v2-1-0.enabled flag ( d9aee1c ) 4.4.1 (2023-05-02) \u00b6 Bug Fixes \u00b6 Discard errors when closing the websocket ( 0c13fc1 ) 4.4.0 (2023-03-08) \u00b6 Features \u00b6 realtime: Add _type on returned doc by the handlers ( 759cdb3 ) 4.3.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 4.2.9 (2022-11-14) \u00b6 Note: Version bump only for package cozy-realtime 4.2.8 (2022-10-03) \u00b6 Bug Fixes \u00b6 Expose sendNotification from cozy-client realtime plugin ( 82500b4 ) 4.2.7 (2022-10-03) \u00b6 Note: Version bump only for package cozy-realtime 4.2.6 (2022-10-03) \u00b6 Note: Version bump only for package cozy-realtime 4.2.5 (2022-09-12) \u00b6 Note: Version bump only for package cozy-realtime 4.2.4 (2022-09-06) \u00b6 Bug Fixes \u00b6 Use correct image size ( d290c39 ) 4.2.3 (2022-08-01) \u00b6 Note: Version bump only for package cozy-realtime 4.2.2 (2022-07-21) \u00b6 Note: Version bump only for package cozy-realtime 4.2.1 (2022-06-24) \u00b6 Note: Version bump only for package cozy-realtime 4.2.0 (2022-06-03) \u00b6 Features \u00b6 harvest: HandleOAuthResponse can deal with cozy-data from DOM ( 7c6ac1a ) 4.1.0 (2022-05-10) \u00b6 Features \u00b6 Add name in attributes selected for buildFilesQueryByLabels ( d66c975 ) 4.0.8 (2022-04-28) \u00b6 Note: Version bump only for package cozy-realtime 4.0.7 (2022-04-26) \u00b6 Note: Version bump only for package cozy-realtime 4.0.6 (2022-04-25) \u00b6 Note: Version bump only for package cozy-realtime 4.0.5 (2022-02-04) \u00b6 Note: Version bump only for package cozy-realtime 4.0.4 (2022-02-03) \u00b6 Note: Version bump only for package cozy-realtime 4.0.3 (2022-02-01) \u00b6 Bug Fixes \u00b6 deps: update babel monorepo ( dcc215a ) 4.0.2 (2022-01-28) \u00b6 Note: Version bump only for package cozy-realtime 4.0.1 (2022-01-07) \u00b6 Note: Version bump only for package cozy-realtime 4.0.0 (2022-01-07) \u00b6 Features \u00b6 eslint: Propose Eslint plugin promise ( 1fded18 ) BREAKING CHANGES \u00b6 eslint: Most errors are not auto fixable, if needed, use // disable-next-line Or insert in .eslintrc: { \u201crules\u201d: { \u201cpromise/always-return\u201d: \u201cwarn\u201d, \u201cpromise/no-return-wrap\u201d: \u201cwarn\u201d, \u201cpromise/param-names\u201d: \u201cwarn\u201d, \u201cpromise/catch-or-return\u201d: \u201cwarn\u201d, \u201cpromise/no-native\u201d: \u201cwarn\u201d, \u201cpromise/no-nesting\u201d: \u201cwarn\u201d, \u201cpromise/no-promise-in-callback\u201d: \u201cwarn\u201d, \u201cpromise/no-callback-in-promise\u201d: \u201cwarn\u201d, \u201cpromise/avoid-new\u201d: \u201cwarn\u201d, \u201cpromise/no-new-statics\u201d: \u201cwarn\u201d, \u201cpromise/no-return-in-finally\u201d: \u201cwarn\u201d, \u201cpromise/valid-params\u201d: \u201cwarn\u201d } } 3.14.4 (2022-01-06) \u00b6 Note: Version bump only for package cozy-realtime 3.14.3 (2021-12-28) \u00b6 Note: Version bump only for package cozy-realtime 3.14.2 (2021-12-20) \u00b6 Note: Version bump only for package cozy-realtime 3.14.1 (2021-12-02) \u00b6 Note: Version bump only for package cozy-realtime 3.14.0 (2021-10-22) \u00b6 Features \u00b6 Remove drive from homeHref ( 97010d3 ) 3.13.1 (2021-09-03) \u00b6 Bug Fixes \u00b6 deps: update dependency cozy-client to v13.21.0 ( f46c241 ) 3.13.0 (2021-03-12) \u00b6 Bug Fixes \u00b6 Divider import in SharingDetailsModal ( f349b54 ) Do not call useEffect conditionally ( 0984f53 ) Typo in package.json s/main/browser ( 03d5360 ) Features \u00b6 Move useRealtime from cozy-ui to cozy-realtime ( 229e8f5 ) 3.12.2 (2021-02-12) \u00b6 Note: Version bump only for package cozy-realtime 3.12.1 (2021-02-02) \u00b6 Note: Version bump only for package cozy-realtime 3.12.0 (2020-11-23) \u00b6 Features \u00b6 All babel cli at 7.12.1 ( 387a24a ) Use >= for peer dependencies ( 6ec2826 ) 3.11.0 (2020-10-19) \u00b6 Features \u00b6 Use @cozy/minilog instead of minilog ( 621abad ) 3.10.6 (2020-10-01) \u00b6 Bug Fixes \u00b6 Lint issue ( aa10617 ) 3.10.5 (2020-09-15) \u00b6 Note: Version bump only for package cozy-realtime 3.10.4 (2020-09-04) \u00b6 Note: Version bump only for package cozy-realtime 3.10.3 (2020-08-20) \u00b6 Note: Version bump only for package cozy-realtime 3.10.2 (2020-08-03) \u00b6 Note: Version bump only for package cozy-realtime 3.10.1 (2020-07-21) \u00b6 Bug Fixes \u00b6 Use same Cozy-UI and CozyClient version everywhere ( 6216e62 ) 3.10.0 (2020-07-20) \u00b6 Features \u00b6 Update cozy-client ( 14ca0b9 ) 3.9.1 (2020-07-16) \u00b6 Note: Version bump only for package cozy-realtime 3.9.0 (2020-07-08) \u00b6 Features \u00b6 Emit events when plugins are ready ( 5fc182c ) 3.8.2 (2020-07-07) \u00b6 Bug Fixes \u00b6 Better error message when using a logged off client with realtime ( 6dd7192 ) 3.8.1 (2020-06-17) \u00b6 Note: Version bump only for package cozy-realtime 3.8.0 (2020-03-26) \u00b6 Features \u00b6 CozyRealtime handles login/logout ( 44cbcbc ) 3.7.0 (2020-03-03) \u00b6 Features \u00b6 realtime: Allows for immediate reconnect ( a2170a8 ) realtime: Reacts to visibility changes ( 4ce703e ) 3.6.4 (2020-02-27) \u00b6 Note: Version bump only for package cozy-realtime 3.6.3 (2020-02-26) \u00b6 Bug Fixes \u00b6 realtime: Comments in RetryManager ( 9974e9d ) realtime: Ensures we always clean up tests ( f0a49cf ) realtime: Erroneous warning on unsubscribe ( 3447a6f ) realtime: Remove a console.log ( fe1a304 ) realtime: Removes legacy code ( eb1bf74 ) realtime: Resilience to errors in subscribe ( 30f5d33 ) 3.6.2 (2020-02-26) \u00b6 Bug Fixes \u00b6 realtime: Connect concurrency ( eb04d84 ) 3.6.1 (2020-02-25) \u00b6 Note: Version bump only for package cozy-realtime 3.6.0 (2020-02-24) \u00b6 Features \u00b6 Rewrite of realtime ( 1022af7 ) 3.5.0 (2020-02-24) \u00b6 Features \u00b6 Update cozy-bi-auth ( fc191ee ) 3.4.0 (2020-01-10) \u00b6 Bug Fixes \u00b6 Correctly check that window exists ( c5da980 ) Do not handle {add,remove}EventListener when not in browser ( 19d10e2 ) Typo in docstring ( c98e84a ) Typo in error message ( 29054a9 ) Features \u00b6 Ability to send realtime event ( dc95cb9 ) Add chat example ( 40bf01e ) Support \u201cnotified\u201d event ( 7c7f524 ) 3.3.1 (2020-01-03) \u00b6 Bug Fixes \u00b6 cozy-realtime: Don\u2019t crash if no event exist ( 654c3ed ) 3.3.0 (2020-01-02) \u00b6 Features \u00b6 cozy-realtime: Add cozy-client plugin ( 820d663 ) 3.2.3 (2019-10-25) \u00b6 Note: Version bump only for package cozy-realtime 3.2.2 (2019-10-23) \u00b6 Bug Fixes \u00b6 Make account selection control larger ( 74abddc ) Use cozy-minilog to fix octal ( 8ac3248 ) 3.2.1 (2019-09-13) \u00b6 Note: Version bump only for package cozy-realtime 3.2.0 (2019-09-05) \u00b6 Features \u00b6 Add account route ( 7986708 ) 3.1.6 (2019-09-04) \u00b6 Note: Version bump only for package cozy-realtime 3.1.5 (2019-08-30) \u00b6 Note: Version bump only for package cozy-realtime 3.1.4 (2019-08-22) \u00b6 Bug Fixes \u00b6 Add chalk as dependency ( 7be5f33 ) 3.1.3 (2019-07-19) \u00b6 Note: Version bump only for package cozy-realtime 3.1.2 (2019-07-19) \u00b6 Note: Version bump only for package cozy-realtime 3.1.1 (2019-07-11) \u00b6 Note: Version bump only for package cozy-realtime 3.1.0 (2019-05-31) \u00b6 Features \u00b6 Deprecate options.cozyClient, use options.client ( ed3f8ad ) 3.0.1 (2019-05-09) \u00b6 Bug Fixes \u00b6 Realtime: Bump version to 3.0.0 ( 1396f2f ) 2.1.0 (2019-05-09) \u00b6 Bug Fixes \u00b6 Realtime: Complexifies the emission of the event ( abd545b ) Realtime: Launch only one connection ( 29fbcb9 ) Realtime: Lint ( 1c1a028 ) Realtime: Remove all listeners after socket closed ( 0563c81 ) Realtime: Resubscribe with same parameters ( f1aba47 ) Features \u00b6 realtime: New version of library ( 5a13957 ) Realtime: Add limit to retry socket connection ( 11653a6 ) Realtime: Add minilog ( bcf98a0 ) Realtime: Add tests ( d5a7573 ) Realtime: Allow unsubscibe with not all config ( 47c582a ) Realtime: New API with same parameters of subscribe and unsubcribe ( eff5ece ) Realtime: Relaunch listerner on new socket ( 270fcdb ) Realtime: Remove all subscribe before window is unloaded ( a74fa65 ) Realtime: Use object on constructor ( 4744a23 ) Use minilog from window if available ( 1cc390a ) 2.0.8 (2019-04-12) \u00b6 Bug Fixes \u00b6 cozy-realtime: Imperfect fix for unsubscribe ( #378 ) ( 8e9e9ab ) 2.0.7 (2019-03-18) \u00b6 Note: Version bump only for package cozy-realtime 2.0.6 (2019-03-12) \u00b6 Note: Version bump only for package cozy-realtime 2.0.5 (2019-03-12) \u00b6 Note: Version bump only for package cozy-realtime 2.0.4 (2019-03-12) \u00b6 Note: Version bump only for package cozy-realtime 2.0.3 (2019-02-12) \u00b6 Note: Version bump only for package cozy-realtime 2.0.2 (2019-02-11) \u00b6 Note: Version bump only for package cozy-realtime 2.0.1 (2019-02-07) \u00b6 Note: Version bump only for package cozy-realtime 2.0.0 (2019-02-07) \u00b6 Bug Fixes \u00b6 Handle correctly websocket retries ( efd26d8 ), closes #199 cache the socket promise instead of the socket itself ( f5a6c1d ), closes #143 realtime: Better handling subscriptions state cleaning ( f6bc6fb ) realtime: Func initCozySocket must define global cozySocket ( 9d4c8c3 ) realtime: Remove async ( c426ffa ) realtime: Use only global cozySocket ( d3b62e0 ) realtime: Minor review changes ( fbc7dfa ) realtime: Reorder subscribeWhenReady arguments ( 40b81dc ) realtime: \ud83d\udc85 Add max poll tries + tests to subscribeWhenReady ( 3849ac6 ) Code Refactoring \u00b6 realtime: Remove async + use simpler API ( 65e5a16 ), closes #145 Features \u00b6 realtime: Use promise instead of polling to handle authenticating ( bdbf440 ) BREAKING CHANGES \u00b6 realtime: New and simpler API + no more async usage 1.2.8 (2019-01-28) \u00b6 Bug Fixes \u00b6 realtime: Wrong links [skip ci] ( d80b3a0 ) 1.2.7 (2019-01-16) \u00b6 Bug Fixes \u00b6 RealTime: Right repo URL ( 1cdef02 ) 1.2.6 (2019-01-11) \u00b6 Note: Version bump only for package cozy-realtime 1.2.5 (2018-12-28) \u00b6 Note: Version bump only for package cozy-realtime 1.2.4 (2018-12-26) \u00b6 Note: Version bump only for package cozy-realtime 1.2.3 (2018-12-17) \u00b6 Note: Version bump only for package cozy-realtime 1.2.2 (2018-12-10) \u00b6 Note: Version bump only for package cozy-realtime 1.2.1 (2018-11-27) \u00b6 Note: Version bump only for package cozy-realtime 1.2.0 (2018-10-04) \u00b6 Features \u00b6 realtime: Add secure parameter \u2728 ( 8993ac0 ) realtime: Better string validation \ud83d\udcdd ( 1c57d6b ) realtime: Handle domain in config \u2728 ( 55b2be6 ) realtime: New validation rules \u2728 ( 6f58276 ) realtime: Throw error when no domain \ud83d\udca5 ( e5b7669 ) realtime: Validate url \u2705 ( 86f59b7 ) 1.1.10 (2018-10-02) \u00b6 Note: Version bump only for package cozy-realtime 1.1.9 (2018-09-25) \u00b6 Note: Version bump only for package cozy-realtime 1.1.8 (2018-09-25) \u00b6 Note: Version bump only for package cozy-realtime 1.1.7 (2018-09-24) \u00b6 Note: Version bump only for package cozy-realtime 1.1.6 (2018-09-21) \u00b6 Note: Version bump only for package cozy-realtime 1.1.5 (2018-08-30) \u00b6 Note: Version bump only for package cozy-realtime 1.1.4 (2018-08-22) \u00b6 Note: Version bump only for package cozy-realtime 1.1.3 (2018-08-17) \u00b6 Bug Fixes \u00b6 realtime: Domain parsing \ud83d\ude91 ( 9ffbc26 ) 1.1.2 (2018-08-09) \u00b6 Note: Version bump only for package cozy-realtime 1.1.1 (2018-08-08) \u00b6 Note: Version bump only for package cozy-realtime", "title": "Change Log"}, {"location": "cozy-realtime/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "cozy-realtime/CHANGELOG/#501-2024-05-31", "text": "Note: Version bump only for package cozy-realtime", "title": "5.0.1 (2024-05-31)"}, {"location": "cozy-realtime/CHANGELOG/#500-2023-08-23", "text": "", "title": "5.0.0 (2023-08-23)"}, {"location": "cozy-realtime/CHANGELOG/#features", "text": "harvest: Update cozy-client from 38.6.0 to 40.2.0 ( 8931b15 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#breaking-changes", "text": "harvest: you must have cozy-client >= 40.2.0", "title": "BREAKING CHANGES"}, {"location": "cozy-realtime/CHANGELOG/#460-2023-06-09", "text": "", "title": "4.6.0 (2023-06-09)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes", "text": "mespapiers: The back button hover area is oval instead of round ( 35d6f4d )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#features_1", "text": "Allow passing a custom logger to realtime ( 8841b71 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#450-2023-05-17", "text": "", "title": "4.5.0 (2023-05-17)"}, {"location": "cozy-realtime/CHANGELOG/#features_2", "text": "Allow using non-native WebSocket ( 827f6e4 ) Remove mespapiers.v2-1-0.enabled flag ( d9aee1c )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#441-2023-05-02", "text": "", "title": "4.4.1 (2023-05-02)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_1", "text": "Discard errors when closing the websocket ( 0c13fc1 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#440-2023-03-08", "text": "", "title": "4.4.0 (2023-03-08)"}, {"location": "cozy-realtime/CHANGELOG/#features_3", "text": "realtime: Add _type on returned doc by the handlers ( 759cdb3 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#430-2023-01-31", "text": "", "title": "4.3.0 (2023-01-31)"}, {"location": "cozy-realtime/CHANGELOG/#features_4", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#429-2022-11-14", "text": "Note: Version bump only for package cozy-realtime", "title": "4.2.9 (2022-11-14)"}, {"location": "cozy-realtime/CHANGELOG/#428-2022-10-03", "text": "", "title": "4.2.8 (2022-10-03)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_2", "text": "Expose sendNotification from cozy-client realtime plugin ( 82500b4 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#427-2022-10-03", "text": "Note: Version bump only for package cozy-realtime", "title": "4.2.7 (2022-10-03)"}, {"location": "cozy-realtime/CHANGELOG/#426-2022-10-03", "text": "Note: Version bump only for package cozy-realtime", "title": "4.2.6 (2022-10-03)"}, {"location": "cozy-realtime/CHANGELOG/#425-2022-09-12", "text": "Note: Version bump only for package cozy-realtime", "title": "4.2.5 (2022-09-12)"}, {"location": "cozy-realtime/CHANGELOG/#424-2022-09-06", "text": "", "title": "4.2.4 (2022-09-06)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_3", "text": "Use correct image size ( d290c39 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#423-2022-08-01", "text": "Note: Version bump only for package cozy-realtime", "title": "4.2.3 (2022-08-01)"}, {"location": "cozy-realtime/CHANGELOG/#422-2022-07-21", "text": "Note: Version bump only for package cozy-realtime", "title": "4.2.2 (2022-07-21)"}, {"location": "cozy-realtime/CHANGELOG/#421-2022-06-24", "text": "Note: Version bump only for package cozy-realtime", "title": "4.2.1 (2022-06-24)"}, {"location": "cozy-realtime/CHANGELOG/#420-2022-06-03", "text": "", "title": "4.2.0 (2022-06-03)"}, {"location": "cozy-realtime/CHANGELOG/#features_5", "text": "harvest: HandleOAuthResponse can deal with cozy-data from DOM ( 7c6ac1a )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#410-2022-05-10", "text": "", "title": "4.1.0 (2022-05-10)"}, {"location": "cozy-realtime/CHANGELOG/#features_6", "text": "Add name in attributes selected for buildFilesQueryByLabels ( d66c975 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#408-2022-04-28", "text": "Note: Version bump only for package cozy-realtime", "title": "4.0.8 (2022-04-28)"}, {"location": "cozy-realtime/CHANGELOG/#407-2022-04-26", "text": "Note: Version bump only for package cozy-realtime", "title": "4.0.7 (2022-04-26)"}, {"location": "cozy-realtime/CHANGELOG/#406-2022-04-25", "text": "Note: Version bump only for package cozy-realtime", "title": "4.0.6 (2022-04-25)"}, {"location": "cozy-realtime/CHANGELOG/#405-2022-02-04", "text": "Note: Version bump only for package cozy-realtime", "title": "4.0.5 (2022-02-04)"}, {"location": "cozy-realtime/CHANGELOG/#404-2022-02-03", "text": "Note: Version bump only for package cozy-realtime", "title": "4.0.4 (2022-02-03)"}, {"location": "cozy-realtime/CHANGELOG/#403-2022-02-01", "text": "", "title": "4.0.3 (2022-02-01)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_4", "text": "deps: update babel monorepo ( dcc215a )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#402-2022-01-28", "text": "Note: Version bump only for package cozy-realtime", "title": "4.0.2 (2022-01-28)"}, {"location": "cozy-realtime/CHANGELOG/#401-2022-01-07", "text": "Note: Version bump only for package cozy-realtime", "title": "4.0.1 (2022-01-07)"}, {"location": "cozy-realtime/CHANGELOG/#400-2022-01-07", "text": "", "title": "4.0.0 (2022-01-07)"}, {"location": "cozy-realtime/CHANGELOG/#features_7", "text": "eslint: Propose Eslint plugin promise ( 1fded18 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#breaking-changes_1", "text": "eslint: Most errors are not auto fixable, if needed, use // disable-next-line Or insert in .eslintrc: { \u201crules\u201d: { \u201cpromise/always-return\u201d: \u201cwarn\u201d, \u201cpromise/no-return-wrap\u201d: \u201cwarn\u201d, \u201cpromise/param-names\u201d: \u201cwarn\u201d, \u201cpromise/catch-or-return\u201d: \u201cwarn\u201d, \u201cpromise/no-native\u201d: \u201cwarn\u201d, \u201cpromise/no-nesting\u201d: \u201cwarn\u201d, \u201cpromise/no-promise-in-callback\u201d: \u201cwarn\u201d, \u201cpromise/no-callback-in-promise\u201d: \u201cwarn\u201d, \u201cpromise/avoid-new\u201d: \u201cwarn\u201d, \u201cpromise/no-new-statics\u201d: \u201cwarn\u201d, \u201cpromise/no-return-in-finally\u201d: \u201cwarn\u201d, \u201cpromise/valid-params\u201d: \u201cwarn\u201d } }", "title": "BREAKING CHANGES"}, {"location": "cozy-realtime/CHANGELOG/#3144-2022-01-06", "text": "Note: Version bump only for package cozy-realtime", "title": "3.14.4 (2022-01-06)"}, {"location": "cozy-realtime/CHANGELOG/#3143-2021-12-28", "text": "Note: Version bump only for package cozy-realtime", "title": "3.14.3 (2021-12-28)"}, {"location": "cozy-realtime/CHANGELOG/#3142-2021-12-20", "text": "Note: Version bump only for package cozy-realtime", "title": "3.14.2 (2021-12-20)"}, {"location": "cozy-realtime/CHANGELOG/#3141-2021-12-02", "text": "Note: Version bump only for package cozy-realtime", "title": "3.14.1 (2021-12-02)"}, {"location": "cozy-realtime/CHANGELOG/#3140-2021-10-22", "text": "", "title": "3.14.0 (2021-10-22)"}, {"location": "cozy-realtime/CHANGELOG/#features_8", "text": "Remove drive from homeHref ( 97010d3 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#3131-2021-09-03", "text": "", "title": "3.13.1 (2021-09-03)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_5", "text": "deps: update dependency cozy-client to v13.21.0 ( f46c241 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#3130-2021-03-12", "text": "", "title": "3.13.0 (2021-03-12)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_6", "text": "Divider import in SharingDetailsModal ( f349b54 ) Do not call useEffect conditionally ( 0984f53 ) Typo in package.json s/main/browser ( 03d5360 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#features_9", "text": "Move useRealtime from cozy-ui to cozy-realtime ( 229e8f5 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#3122-2021-02-12", "text": "Note: Version bump only for package cozy-realtime", "title": "3.12.2 (2021-02-12)"}, {"location": "cozy-realtime/CHANGELOG/#3121-2021-02-02", "text": "Note: Version bump only for package cozy-realtime", "title": "3.12.1 (2021-02-02)"}, {"location": "cozy-realtime/CHANGELOG/#3120-2020-11-23", "text": "", "title": "3.12.0 (2020-11-23)"}, {"location": "cozy-realtime/CHANGELOG/#features_10", "text": "All babel cli at 7.12.1 ( 387a24a ) Use >= for peer dependencies ( 6ec2826 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#3110-2020-10-19", "text": "", "title": "3.11.0 (2020-10-19)"}, {"location": "cozy-realtime/CHANGELOG/#features_11", "text": "Use @cozy/minilog instead of minilog ( 621abad )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#3106-2020-10-01", "text": "", "title": "3.10.6 (2020-10-01)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_7", "text": "Lint issue ( aa10617 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#3105-2020-09-15", "text": "Note: Version bump only for package cozy-realtime", "title": "3.10.5 (2020-09-15)"}, {"location": "cozy-realtime/CHANGELOG/#3104-2020-09-04", "text": "Note: Version bump only for package cozy-realtime", "title": "3.10.4 (2020-09-04)"}, {"location": "cozy-realtime/CHANGELOG/#3103-2020-08-20", "text": "Note: Version bump only for package cozy-realtime", "title": "3.10.3 (2020-08-20)"}, {"location": "cozy-realtime/CHANGELOG/#3102-2020-08-03", "text": "Note: Version bump only for package cozy-realtime", "title": "3.10.2 (2020-08-03)"}, {"location": "cozy-realtime/CHANGELOG/#3101-2020-07-21", "text": "", "title": "3.10.1 (2020-07-21)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_8", "text": "Use same Cozy-UI and CozyClient version everywhere ( 6216e62 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#3100-2020-07-20", "text": "", "title": "3.10.0 (2020-07-20)"}, {"location": "cozy-realtime/CHANGELOG/#features_12", "text": "Update cozy-client ( 14ca0b9 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#391-2020-07-16", "text": "Note: Version bump only for package cozy-realtime", "title": "3.9.1 (2020-07-16)"}, {"location": "cozy-realtime/CHANGELOG/#390-2020-07-08", "text": "", "title": "3.9.0 (2020-07-08)"}, {"location": "cozy-realtime/CHANGELOG/#features_13", "text": "Emit events when plugins are ready ( 5fc182c )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#382-2020-07-07", "text": "", "title": "3.8.2 (2020-07-07)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_9", "text": "Better error message when using a logged off client with realtime ( 6dd7192 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#381-2020-06-17", "text": "Note: Version bump only for package cozy-realtime", "title": "3.8.1 (2020-06-17)"}, {"location": "cozy-realtime/CHANGELOG/#380-2020-03-26", "text": "", "title": "3.8.0 (2020-03-26)"}, {"location": "cozy-realtime/CHANGELOG/#features_14", "text": "CozyRealtime handles login/logout ( 44cbcbc )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#370-2020-03-03", "text": "", "title": "3.7.0 (2020-03-03)"}, {"location": "cozy-realtime/CHANGELOG/#features_15", "text": "realtime: Allows for immediate reconnect ( a2170a8 ) realtime: Reacts to visibility changes ( 4ce703e )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#364-2020-02-27", "text": "Note: Version bump only for package cozy-realtime", "title": "3.6.4 (2020-02-27)"}, {"location": "cozy-realtime/CHANGELOG/#363-2020-02-26", "text": "", "title": "3.6.3 (2020-02-26)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_10", "text": "realtime: Comments in RetryManager ( 9974e9d ) realtime: Ensures we always clean up tests ( f0a49cf ) realtime: Erroneous warning on unsubscribe ( 3447a6f ) realtime: Remove a console.log ( fe1a304 ) realtime: Removes legacy code ( eb1bf74 ) realtime: Resilience to errors in subscribe ( 30f5d33 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#362-2020-02-26", "text": "", "title": "3.6.2 (2020-02-26)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_11", "text": "realtime: Connect concurrency ( eb04d84 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#361-2020-02-25", "text": "Note: Version bump only for package cozy-realtime", "title": "3.6.1 (2020-02-25)"}, {"location": "cozy-realtime/CHANGELOG/#360-2020-02-24", "text": "", "title": "3.6.0 (2020-02-24)"}, {"location": "cozy-realtime/CHANGELOG/#features_16", "text": "Rewrite of realtime ( 1022af7 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#350-2020-02-24", "text": "", "title": "3.5.0 (2020-02-24)"}, {"location": "cozy-realtime/CHANGELOG/#features_17", "text": "Update cozy-bi-auth ( fc191ee )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#340-2020-01-10", "text": "", "title": "3.4.0 (2020-01-10)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_12", "text": "Correctly check that window exists ( c5da980 ) Do not handle {add,remove}EventListener when not in browser ( 19d10e2 ) Typo in docstring ( c98e84a ) Typo in error message ( 29054a9 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#features_18", "text": "Ability to send realtime event ( dc95cb9 ) Add chat example ( 40bf01e ) Support \u201cnotified\u201d event ( 7c7f524 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#331-2020-01-03", "text": "", "title": "3.3.1 (2020-01-03)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_13", "text": "cozy-realtime: Don\u2019t crash if no event exist ( 654c3ed )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#330-2020-01-02", "text": "", "title": "3.3.0 (2020-01-02)"}, {"location": "cozy-realtime/CHANGELOG/#features_19", "text": "cozy-realtime: Add cozy-client plugin ( 820d663 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#323-2019-10-25", "text": "Note: Version bump only for package cozy-realtime", "title": "3.2.3 (2019-10-25)"}, {"location": "cozy-realtime/CHANGELOG/#322-2019-10-23", "text": "", "title": "3.2.2 (2019-10-23)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_14", "text": "Make account selection control larger ( 74abddc ) Use cozy-minilog to fix octal ( 8ac3248 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#321-2019-09-13", "text": "Note: Version bump only for package cozy-realtime", "title": "3.2.1 (2019-09-13)"}, {"location": "cozy-realtime/CHANGELOG/#320-2019-09-05", "text": "", "title": "3.2.0 (2019-09-05)"}, {"location": "cozy-realtime/CHANGELOG/#features_20", "text": "Add account route ( 7986708 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#316-2019-09-04", "text": "Note: Version bump only for package cozy-realtime", "title": "3.1.6 (2019-09-04)"}, {"location": "cozy-realtime/CHANGELOG/#315-2019-08-30", "text": "Note: Version bump only for package cozy-realtime", "title": "3.1.5 (2019-08-30)"}, {"location": "cozy-realtime/CHANGELOG/#314-2019-08-22", "text": "", "title": "3.1.4 (2019-08-22)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_15", "text": "Add chalk as dependency ( 7be5f33 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#313-2019-07-19", "text": "Note: Version bump only for package cozy-realtime", "title": "3.1.3 (2019-07-19)"}, {"location": "cozy-realtime/CHANGELOG/#312-2019-07-19", "text": "Note: Version bump only for package cozy-realtime", "title": "3.1.2 (2019-07-19)"}, {"location": "cozy-realtime/CHANGELOG/#311-2019-07-11", "text": "Note: Version bump only for package cozy-realtime ", "title": "3.1.1 (2019-07-11)"}, {"location": "cozy-realtime/CHANGELOG/#310-2019-05-31", "text": "", "title": "3.1.0 (2019-05-31)"}, {"location": "cozy-realtime/CHANGELOG/#features_21", "text": "Deprecate options.cozyClient, use options.client ( ed3f8ad )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#301-2019-05-09", "text": "", "title": "3.0.1 (2019-05-09)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_16", "text": "Realtime: Bump version to 3.0.0 ( 1396f2f )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#210-2019-05-09", "text": "", "title": "2.1.0 (2019-05-09)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_17", "text": "Realtime: Complexifies the emission of the event ( abd545b ) Realtime: Launch only one connection ( 29fbcb9 ) Realtime: Lint ( 1c1a028 ) Realtime: Remove all listeners after socket closed ( 0563c81 ) Realtime: Resubscribe with same parameters ( f1aba47 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#features_22", "text": "realtime: New version of library ( 5a13957 ) Realtime: Add limit to retry socket connection ( 11653a6 ) Realtime: Add minilog ( bcf98a0 ) Realtime: Add tests ( d5a7573 ) Realtime: Allow unsubscibe with not all config ( 47c582a ) Realtime: New API with same parameters of subscribe and unsubcribe ( eff5ece ) Realtime: Relaunch listerner on new socket ( 270fcdb ) Realtime: Remove all subscribe before window is unloaded ( a74fa65 ) Realtime: Use object on constructor ( 4744a23 ) Use minilog from window if available ( 1cc390a )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#208-2019-04-12", "text": "", "title": "2.0.8 (2019-04-12)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_18", "text": "cozy-realtime: Imperfect fix for unsubscribe ( #378 ) ( 8e9e9ab )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#207-2019-03-18", "text": "Note: Version bump only for package cozy-realtime", "title": "2.0.7 (2019-03-18)"}, {"location": "cozy-realtime/CHANGELOG/#206-2019-03-12", "text": "Note: Version bump only for package cozy-realtime", "title": "2.0.6 (2019-03-12)"}, {"location": "cozy-realtime/CHANGELOG/#205-2019-03-12", "text": "Note: Version bump only for package cozy-realtime", "title": "2.0.5 (2019-03-12)"}, {"location": "cozy-realtime/CHANGELOG/#204-2019-03-12", "text": "Note: Version bump only for package cozy-realtime", "title": "2.0.4 (2019-03-12)"}, {"location": "cozy-realtime/CHANGELOG/#203-2019-02-12", "text": "Note: Version bump only for package cozy-realtime", "title": "2.0.3 (2019-02-12)"}, {"location": "cozy-realtime/CHANGELOG/#202-2019-02-11", "text": "Note: Version bump only for package cozy-realtime", "title": "2.0.2 (2019-02-11)"}, {"location": "cozy-realtime/CHANGELOG/#201-2019-02-07", "text": "Note: Version bump only for package cozy-realtime", "title": "2.0.1 (2019-02-07)"}, {"location": "cozy-realtime/CHANGELOG/#200-2019-02-07", "text": "", "title": "2.0.0 (2019-02-07)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_19", "text": "Handle correctly websocket retries ( efd26d8 ), closes #199 cache the socket promise instead of the socket itself ( f5a6c1d ), closes #143 realtime: Better handling subscriptions state cleaning ( f6bc6fb ) realtime: Func initCozySocket must define global cozySocket ( 9d4c8c3 ) realtime: Remove async ( c426ffa ) realtime: Use only global cozySocket ( d3b62e0 ) realtime: Minor review changes ( fbc7dfa ) realtime: Reorder subscribeWhenReady arguments ( 40b81dc ) realtime: \ud83d\udc85 Add max poll tries + tests to subscribeWhenReady ( 3849ac6 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#code-refactoring", "text": "realtime: Remove async + use simpler API ( 65e5a16 ), closes #145", "title": "Code Refactoring"}, {"location": "cozy-realtime/CHANGELOG/#features_23", "text": "realtime: Use promise instead of polling to handle authenticating ( bdbf440 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#breaking-changes_2", "text": "realtime: New and simpler API + no more async usage", "title": "BREAKING CHANGES"}, {"location": "cozy-realtime/CHANGELOG/#128-2019-01-28", "text": "", "title": "1.2.8 (2019-01-28)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_20", "text": "realtime: Wrong links [skip ci] ( d80b3a0 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#127-2019-01-16", "text": "", "title": "1.2.7 (2019-01-16)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_21", "text": "RealTime: Right repo URL ( 1cdef02 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#126-2019-01-11", "text": "Note: Version bump only for package cozy-realtime", "title": "1.2.6 (2019-01-11)"}, {"location": "cozy-realtime/CHANGELOG/#125-2018-12-28", "text": "Note: Version bump only for package cozy-realtime", "title": "1.2.5 (2018-12-28)"}, {"location": "cozy-realtime/CHANGELOG/#124-2018-12-26", "text": "Note: Version bump only for package cozy-realtime", "title": "1.2.4 (2018-12-26)"}, {"location": "cozy-realtime/CHANGELOG/#123-2018-12-17", "text": "Note: Version bump only for package cozy-realtime", "title": "1.2.3 (2018-12-17)"}, {"location": "cozy-realtime/CHANGELOG/#122-2018-12-10", "text": "Note: Version bump only for package cozy-realtime", "title": "1.2.2 (2018-12-10)"}, {"location": "cozy-realtime/CHANGELOG/#121-2018-11-27", "text": "Note: Version bump only for package cozy-realtime", "title": "1.2.1 (2018-11-27)"}, {"location": "cozy-realtime/CHANGELOG/#120-2018-10-04", "text": "", "title": "1.2.0 (2018-10-04)"}, {"location": "cozy-realtime/CHANGELOG/#features_24", "text": "realtime: Add secure parameter \u2728 ( 8993ac0 ) realtime: Better string validation \ud83d\udcdd ( 1c57d6b ) realtime: Handle domain in config \u2728 ( 55b2be6 ) realtime: New validation rules \u2728 ( 6f58276 ) realtime: Throw error when no domain \ud83d\udca5 ( e5b7669 ) realtime: Validate url \u2705 ( 86f59b7 )", "title": "Features"}, {"location": "cozy-realtime/CHANGELOG/#1110-2018-10-02", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.10 (2018-10-02)"}, {"location": "cozy-realtime/CHANGELOG/#119-2018-09-25", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.9 (2018-09-25)"}, {"location": "cozy-realtime/CHANGELOG/#118-2018-09-25", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.8 (2018-09-25)"}, {"location": "cozy-realtime/CHANGELOG/#117-2018-09-24", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.7 (2018-09-24)"}, {"location": "cozy-realtime/CHANGELOG/#116-2018-09-21", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.6 (2018-09-21)"}, {"location": "cozy-realtime/CHANGELOG/#115-2018-08-30", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.5 (2018-08-30)"}, {"location": "cozy-realtime/CHANGELOG/#114-2018-08-22", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.4 (2018-08-22)"}, {"location": "cozy-realtime/CHANGELOG/#113-2018-08-17", "text": "", "title": "1.1.3 (2018-08-17)"}, {"location": "cozy-realtime/CHANGELOG/#bug-fixes_22", "text": "realtime: Domain parsing \ud83d\ude91 ( 9ffbc26 )", "title": "Bug Fixes"}, {"location": "cozy-realtime/CHANGELOG/#112-2018-08-09", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.2 (2018-08-09)"}, {"location": "cozy-realtime/CHANGELOG/#111-2018-08-08", "text": "Note: Version bump only for package cozy-realtime", "title": "1.1.1 (2018-08-08)"}, {"location": "cozy-scripts/webpack-configs/", "text": "The cozy-scripts Webpack configurations \u00b6 Introduction Config file types Bundles webpack.bundle.default.js Unit Configs webpack.config.analyzer.js webpack.config.base.js Properties Rules Plugins webpack.config.chunks.js webpack.config.cozy-ui.js webpack.config.cozy-ui.react.js webpack.config.css-modules.js webpack.config.eslint.js webpack.config.intents.js webpack.config.hash.js webpack.config.manifest.js webpack.config.pictures.js webpack.config.progress.js webpack.config.services.js webpack.config.react.js webpack.config.vendors.js Environments webpack.environment.dev.js Properties Plugins webpack.environment.prod.js Plugins Targets webpack.target.browser.js Properties Plugins webpack.target.mobile.js Properties Plugins: Miscellaneous webpack.vars.js Introduction \u00b6 To build a Cozy application, cozy-scripts uses webpack under the hood, and this documentation is dedicated to all webpack configuration files. The webpack config is split to facilitate understanding. Having many unit files for the configuration allows to support specific application needs without \u2018ejecting\u2019 (removing cozy-scripts dependency and copy all webpack configurations and dependencies to the application repository). These files should be independent enough to be usable upon request as far as possible without conflicts. Config file types \u00b6 Bundle: A bundle regroups many unit configuration for a specific use case like the default React application. Environment: An environment config is in charge of providing variables and plugins specific to a compiling context (development or production for example). Target: For now we only have two targets, browser for the default web application and mobile for native mobile applications using Cordova (in progress). Bundles \u00b6 webpack.bundle.default.js \u00b6 This file is the default config bundle used for the application built from cozy-scripts . If you wish to customize a behavior, you can overload this configuration by creating a custom app.config.js in your application root directory: // app.config.js // using ES Modules import configs from 'cozy-scripts/config/webpack.bundle.default.js' import myConfig from './config/webpack.myconfig.js' // it's possible to add many custom configurations using this way, // the last will overwrite the previous in case of conflicts module . exports = [ configs , myConfig ] Unit Configs \u00b6 webpack.config.analyzer.js \u00b6 This file will only add the plugin webpack-bundle-analyzer to be run on with the --analyzer option. It will run a server (on port 8889 to not be in conflict with the webpack dev server) and open an interactive treemap visualization of the contents of all your bundles in your browser. webpack.config.base.js \u00b6 The default basic configuration of the application. Properties \u00b6 output to [name].js filename resolve: modules to ['node_modules', 'src'] extensions: .js , .json and .css Rules \u00b6 all .js (excluding node_modules , cozy-bar and cozy-client-js ) to be loaded using babel-loader (with cacheDirectory option for caching in node_modules/.cache/babel-loader ) all .css to be loaded using options: mini-css-extract-plugin extractor loader by default or style-loader for hot reloading css-loader with sourceMap postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } A specific noParse property is enabled on /localforage/dist . Plugins \u00b6 postcss-assets-webpack-plugin (logs from this plugin are shown only in --debug mode) to load all .css files with: css-mqpacker (pack all CSS media query rules into one) postcss-discard-duplicates (remove duplicates) postcss-discard-empty (remove empty definitions) csswring only in production environment to minify and remove comments ( preservehacks enabled) webpack.config.chunks.js \u00b6 This configuration will use the optimization property with splitChunks in order to split the build into two chunks: - The main one, it can be app or intents - And the vendors chunk which will gather all stuff from node_modules Splitting chunks allow to decrease the size of the main chunk and optimize the build for caching (mainly the main chunk will change during development). webpack.config.cozy-ui.js \u00b6 This configuration will allow to load styles from cozy-ui . It adds a rule for all .styl files excluding node_modules and node_modules/cozy-ui/react to be loaded using: - mini-css-extract-plugin extractor loader by default or style-loader for hot reloading - css-loader with sourceMap - postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } - stylus-loader using the custom stylus plugin from cozy-ui as option It also uses svg-sprite-loader/plugin to merge the built svg sprite from cozy-ui into the application\u2019s one webpack.config.cozy-ui.react.js \u00b6 This configuration is specific to react components usage from cozy-ui , since they currently need css-modules . This configuration file could be removed if this cozy-ui requirement disappear. It adds a rule for all .styl files from cozy-ui/react to be loaded using: - mini-css-extract-plugin extractor loader by default or style-loader for hot reloading - css-loader with modules , sourceMap and [local]--[hash:base64:5] as localIdentName - postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } - stylus-loader using the custom stylus plugin from cozy-ui as option webpack.config.css-modules.js \u00b6 This configuration will allow to use css-modules with stylus files. To overload previous stylus loaders, it uses the following webpack-merge smartStrategy : { 'modules.loaders': 'replace' } . It adds a rule for all .styl files excluding node_modules and node_modules/cozy-ui/react to be loaded using: - mini-css-extract-plugin extractor loader by default or style-loader for hot reloading - css-loader with modules , sourceMap and [local]--[hash:base64:5] as localIdentName - postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } - stylus-loader webpack.config.eslint.js \u00b6 A rule to preload all .js/.jsx files with eslint-loader (excluding node_modules ) extending babel-preset-cozy-app The emitWarning option is set to true for production environment or if hot reload is enabled to force emitting warning and to avoid errors breaking the build. webpack.config.intents.js \u00b6 This is a specific configuration file to develop application intents for the Cozy platform. It will: - add a webpack entry: the babel-polyfill import and the src/targets/intents/intents.jsx file - use html-webpack-plugin configured to use index.ejs HTML template from src/targets/intents/ with options: - title : name property of the package.json + intents - filename : intents/index.html , the output file - excludeChunks : to exclude chunk app - inject to false - minify with collapseWhitespace to true webpack.config.hash.js \u00b6 A custom webpack plugin usage to extract the hash from built files for reference. webpack.config.manifest.js \u00b6 A copy-webpack-plugin plugin usage to copy the manifest.webapp , README.md and LICENSE files to the output build folder. In the production environment, the manifest.webapp is transformed to include locales from the application src/locales folder (locales concerning manifest descriptions, permissions, names\u2026). It will look for the manifest property (if found) of the locale .json file. So the locales property of the manifest.webapp will be an object of language slugs as properties and each slug matching the related locales found. The langs array in the manifest will also be computed according to the languages found in src/locales . Except for production environment, the manifest.webapp is transformed using a custom function to change the slug property value to app (to keep using app.cozy.tools:8080 URL for different app development). webpack.config.pictures.js \u00b6 This configuration will handle all pictures files. It will add two rules: - all .svg files in sprites/ and icons/ folders will be loaded using svg-sprite-loader with output name to [name]_[hash] . This loader will merge all SVG content to one .svg file and replace their reference to the matching id . Only one .svg sprite file will be loaded by the ouput application. - all other .svg , .png , .gif , .jpg , .jpeg files will be loaded using file-loader with options: - path to img , the ouput folder - symbolId to [name].[hash].[ext] for production environment, [name].[ext] for other environments It also adds svg-sprite-loader/plugin as plugin to use it with the related loader. webpack.config.progress.js \u00b6 This config will just add a custom webpack plugin to display a progress bar when webpack building/watching. It internally uses the included webpack plugin webpack.ProgressPlugin . webpack.config.services.js \u00b6 This config will provide a separate config to build app services using Webpack multi-compiling . In this case, all services files ( .js files in the /src/targets/services/ folder) will be built using this separate webpack config. This config will: - use __mergeStrategy to drive the webpack-merge strategy : - disable smart merging - use the replace mode plugins , output , entry , optimization and module - define as webpack entry an array of all .js files contained in /src/target/services folder - use as output the /build/services folder with [name].js as filename - define the target as 'node' - disable devtool (boolean to false ) - define the global variable __TARGET__ to services using the plugin webpack.DefinePlugin This config will be used only if the webpack target is browser . webpack.config.react.js \u00b6 A config to load .jsx using for React components. It will: - resolve .jsx extensions - add a rule for .jsx files excluding node_modules (exception for node_modules/cozy-ui ) to be loaded using babel-loader (with cacheDirectory option for caching in node_modules/.cache/babel-loader ) webpack.config.vendors.js \u00b6 A copy-webpack-plugin plugin usage to copy all files from the vendors/assets/ folder to the output build folder. This config will also process the application icon and run svgo to optimize it if this is a SVG file. Environments \u00b6 webpack.environment.dev.js \u00b6 Properties \u00b6 devtool to #source-map externals with ['cozy'] to exclude all cozy.* dependencies from the output bundle (since it will be serve by ProvidePlugin ) mode to development Plugins \u00b6 webpack.DefinePlugin to define globals variables at compiling time: __DEVELOPMENT__ to true __STACK_ASSETS__ to false webpack.ProvidePlugin to provide cozy-bar and cozy-client-js from node_modules (in production, these modules will be provided to the application by the cozy-stack ) Copy ( copy-webpack-plugin ) the cozy-bar.css file from node_modules ot the app build to be able to develop on the cozy-bar using the app Add the cozy-bar css to the main html file via html-webpack-include-assets-plugin Only in the hot reload mode: - webpack.HotModuleReplacementPlugin which allows all kinds of modules to be updated at runtime without the need for a full refresh - write-file-webpack-plugin to write all the build file from webpack-dev-server to the disk (necessary for the hot-reloading) webpack.environment.prod.js \u00b6 Plugins \u00b6 webpack.optimize.OccurrenceOrderPlugin webpack.DefinePlugin to define globals variables at compiling time: process.env.NODE_ENV to production __DEVELOPMENT__ to false __DEVTOOLS__ to false __STACK_ASSETS__ to true if target different from mobile In this production mode, webpack will automatically use the Terser plugin to optimize the build (with parallel: true to speedup the build). Targets \u00b6 webpack.target.browser.js \u00b6 Properties \u00b6 entry : the babel-polyfill import and the index.jsx from src/targets/browser/ output : build/ path with filename to [name].js and pathinfo enabling only with the COZY_SCRIPTS_DEBUG mode externals with { 'cozy-client-js': 'cozy' } to exclude cozy-client-js (via cozy.* ) dependency from the output bundle Plugins \u00b6 script-ext-html-webpack-plugin to load the main application .js file using the defer attribute (to be loaded after the initial loading) and used with html-webpack-plugin html-webpack-plugin configured to use index.ejs HTML template from src/targets/browser/ with options: title : name property of the package.json inject to false excludeChunks : to exclude chunk intents minify with collapseWhitespace to true webpack.DefinePlugin to define globals variables at compile time: __TARGET__ to browser webpack.target.mobile.js \u00b6 Properties \u00b6 entry : the babel-polyfill import and the index.jsx from src/targets/mobile output : src/targets/mobile/www path and pathinfo enabling only with the COZY_SCRIPTS_DEBUG mode Plugins: \u00b6 script-ext-html-webpack-plugin to load the main application .js file using the defer attribute (to be loaded after the initial loading) and used with html-webpack-plugin html-webpack-plugin configured to use index.ejs HTML template from src/targets/mobile/ with options: title : name property of the package.json excludeChunks : to exclude chunk intents inject to head minify with collapseWhitespace to true webpack.DefinePlugin to define globals variables at compile time: __ALLOW_HTTP__ to false if production environment, true for other environments __TARGET__ to mobile __APP_VERSION__ to the version property of the package.json webpack.ProvidePlugin to provide cozy-bar and cozy-client-js from node_modules (since it\u2019s for the native application, it\u2019s not served by the cozy-stack unlike the browser version) Miscellaneous \u00b6 webpack.vars.js \u00b6 This file is used to get webpack variables. They are necessary to build correctly the application. It will export these following variables: - addAnalyzer according to the COZY_SCRIPTS_ANALYZER environment variable (used to get the webpack-bundle-analyze usage) - environment according to NODE_ENV environment variable ( target:environment ) - getCSSLoader , a function returing the correctly style lodaer to use ( mini-css-extract-plugin loader by default and style-loader for hot reloading) - isDebugMode according to the COZY_SCRIPTS_DEBUG environment variable (used to get into a debug mode of cozy-scripts ) - target according to NODE_ENV environment variable ( target:environment ) - useHotReload according to the HOT_RELOAD environment variable to use hot reloading feature or not If no environment variable NODE_ENV is found, it will be browser:development by default.", "title": "The `cozy-scripts` Webpack configurations"}, {"location": "cozy-scripts/webpack-configs/#the-cozy-scripts-webpack-configurations", "text": "Introduction Config file types Bundles webpack.bundle.default.js Unit Configs webpack.config.analyzer.js webpack.config.base.js Properties Rules Plugins webpack.config.chunks.js webpack.config.cozy-ui.js webpack.config.cozy-ui.react.js webpack.config.css-modules.js webpack.config.eslint.js webpack.config.intents.js webpack.config.hash.js webpack.config.manifest.js webpack.config.pictures.js webpack.config.progress.js webpack.config.services.js webpack.config.react.js webpack.config.vendors.js Environments webpack.environment.dev.js Properties Plugins webpack.environment.prod.js Plugins Targets webpack.target.browser.js Properties Plugins webpack.target.mobile.js Properties Plugins: Miscellaneous webpack.vars.js", "title": "The cozy-scripts Webpack configurations"}, {"location": "cozy-scripts/webpack-configs/#introduction", "text": "To build a Cozy application, cozy-scripts uses webpack under the hood, and this documentation is dedicated to all webpack configuration files. The webpack config is split to facilitate understanding. Having many unit files for the configuration allows to support specific application needs without \u2018ejecting\u2019 (removing cozy-scripts dependency and copy all webpack configurations and dependencies to the application repository). These files should be independent enough to be usable upon request as far as possible without conflicts.", "title": "Introduction"}, {"location": "cozy-scripts/webpack-configs/#config-file-types", "text": "Bundle: A bundle regroups many unit configuration for a specific use case like the default React application. Environment: An environment config is in charge of providing variables and plugins specific to a compiling context (development or production for example). Target: For now we only have two targets, browser for the default web application and mobile for native mobile applications using Cordova (in progress).", "title": "Config file types"}, {"location": "cozy-scripts/webpack-configs/#bundles", "text": "", "title": "Bundles"}, {"location": "cozy-scripts/webpack-configs/#webpackbundledefaultjs", "text": "This file is the default config bundle used for the application built from cozy-scripts . If you wish to customize a behavior, you can overload this configuration by creating a custom app.config.js in your application root directory: // app.config.js // using ES Modules import configs from 'cozy-scripts/config/webpack.bundle.default.js' import myConfig from './config/webpack.myconfig.js' // it's possible to add many custom configurations using this way, // the last will overwrite the previous in case of conflicts module . exports = [ configs , myConfig ]", "title": "webpack.bundle.default.js"}, {"location": "cozy-scripts/webpack-configs/#unit-configs", "text": "", "title": "Unit Configs"}, {"location": "cozy-scripts/webpack-configs/#webpackconfiganalyzerjs", "text": "This file will only add the plugin webpack-bundle-analyzer to be run on with the --analyzer option. It will run a server (on port 8889 to not be in conflict with the webpack dev server) and open an interactive treemap visualization of the contents of all your bundles in your browser.", "title": "webpack.config.analyzer.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigbasejs", "text": "The default basic configuration of the application.", "title": "webpack.config.base.js"}, {"location": "cozy-scripts/webpack-configs/#properties", "text": "output to [name].js filename resolve: modules to ['node_modules', 'src'] extensions: .js , .json and .css", "title": "Properties"}, {"location": "cozy-scripts/webpack-configs/#rules", "text": "all .js (excluding node_modules , cozy-bar and cozy-client-js ) to be loaded using babel-loader (with cacheDirectory option for caching in node_modules/.cache/babel-loader ) all .css to be loaded using options: mini-css-extract-plugin extractor loader by default or style-loader for hot reloading css-loader with sourceMap postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } A specific noParse property is enabled on /localforage/dist .", "title": "Rules"}, {"location": "cozy-scripts/webpack-configs/#plugins", "text": "postcss-assets-webpack-plugin (logs from this plugin are shown only in --debug mode) to load all .css files with: css-mqpacker (pack all CSS media query rules into one) postcss-discard-duplicates (remove duplicates) postcss-discard-empty (remove empty definitions) csswring only in production environment to minify and remove comments ( preservehacks enabled)", "title": "Plugins"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigchunksjs", "text": "This configuration will use the optimization property with splitChunks in order to split the build into two chunks: - The main one, it can be app or intents - And the vendors chunk which will gather all stuff from node_modules Splitting chunks allow to decrease the size of the main chunk and optimize the build for caching (mainly the main chunk will change during development).", "title": "webpack.config.chunks.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigcozy-uijs", "text": "This configuration will allow to load styles from cozy-ui . It adds a rule for all .styl files excluding node_modules and node_modules/cozy-ui/react to be loaded using: - mini-css-extract-plugin extractor loader by default or style-loader for hot reloading - css-loader with sourceMap - postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } - stylus-loader using the custom stylus plugin from cozy-ui as option It also uses svg-sprite-loader/plugin to merge the built svg sprite from cozy-ui into the application\u2019s one", "title": "webpack.config.cozy-ui.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigcozy-uireactjs", "text": "This configuration is specific to react components usage from cozy-ui , since they currently need css-modules . This configuration file could be removed if this cozy-ui requirement disappear. It adds a rule for all .styl files from cozy-ui/react to be loaded using: - mini-css-extract-plugin extractor loader by default or style-loader for hot reloading - css-loader with modules , sourceMap and [local]--[hash:base64:5] as localIdentName - postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } - stylus-loader using the custom stylus plugin from cozy-ui as option", "title": "webpack.config.cozy-ui.react.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigcss-modulesjs", "text": "This configuration will allow to use css-modules with stylus files. To overload previous stylus loaders, it uses the following webpack-merge smartStrategy : { 'modules.loaders': 'replace' } . It adds a rule for all .styl files excluding node_modules and node_modules/cozy-ui/react to be loaded using: - mini-css-extract-plugin extractor loader by default or style-loader for hot reloading - css-loader with modules , sourceMap and [local]--[hash:base64:5] as localIdentName - postcss-loader to optimize css output code with sourceMap and autoprefixer plugin to { browsers: ['last 2 versions'] } - stylus-loader", "title": "webpack.config.css-modules.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigeslintjs", "text": "A rule to preload all .js/.jsx files with eslint-loader (excluding node_modules ) extending babel-preset-cozy-app The emitWarning option is set to true for production environment or if hot reload is enabled to force emitting warning and to avoid errors breaking the build.", "title": "webpack.config.eslint.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigintentsjs", "text": "This is a specific configuration file to develop application intents for the Cozy platform. It will: - add a webpack entry: the babel-polyfill import and the src/targets/intents/intents.jsx file - use html-webpack-plugin configured to use index.ejs HTML template from src/targets/intents/ with options: - title : name property of the package.json + intents - filename : intents/index.html , the output file - excludeChunks : to exclude chunk app - inject to false - minify with collapseWhitespace to true", "title": "webpack.config.intents.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfighashjs", "text": "A custom webpack plugin usage to extract the hash from built files for reference.", "title": "webpack.config.hash.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigmanifestjs", "text": "A copy-webpack-plugin plugin usage to copy the manifest.webapp , README.md and LICENSE files to the output build folder. In the production environment, the manifest.webapp is transformed to include locales from the application src/locales folder (locales concerning manifest descriptions, permissions, names\u2026). It will look for the manifest property (if found) of the locale .json file. So the locales property of the manifest.webapp will be an object of language slugs as properties and each slug matching the related locales found. The langs array in the manifest will also be computed according to the languages found in src/locales . Except for production environment, the manifest.webapp is transformed using a custom function to change the slug property value to app (to keep using app.cozy.tools:8080 URL for different app development).", "title": "webpack.config.manifest.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigpicturesjs", "text": "This configuration will handle all pictures files. It will add two rules: - all .svg files in sprites/ and icons/ folders will be loaded using svg-sprite-loader with output name to [name]_[hash] . This loader will merge all SVG content to one .svg file and replace their reference to the matching id . Only one .svg sprite file will be loaded by the ouput application. - all other .svg , .png , .gif , .jpg , .jpeg files will be loaded using file-loader with options: - path to img , the ouput folder - symbolId to [name].[hash].[ext] for production environment, [name].[ext] for other environments It also adds svg-sprite-loader/plugin as plugin to use it with the related loader.", "title": "webpack.config.pictures.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigprogressjs", "text": "This config will just add a custom webpack plugin to display a progress bar when webpack building/watching. It internally uses the included webpack plugin webpack.ProgressPlugin .", "title": "webpack.config.progress.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigservicesjs", "text": "This config will provide a separate config to build app services using Webpack multi-compiling . In this case, all services files ( .js files in the /src/targets/services/ folder) will be built using this separate webpack config. This config will: - use __mergeStrategy to drive the webpack-merge strategy : - disable smart merging - use the replace mode plugins , output , entry , optimization and module - define as webpack entry an array of all .js files contained in /src/target/services folder - use as output the /build/services folder with [name].js as filename - define the target as 'node' - disable devtool (boolean to false ) - define the global variable __TARGET__ to services using the plugin webpack.DefinePlugin This config will be used only if the webpack target is browser .", "title": "webpack.config.services.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigreactjs", "text": "A config to load .jsx using for React components. It will: - resolve .jsx extensions - add a rule for .jsx files excluding node_modules (exception for node_modules/cozy-ui ) to be loaded using babel-loader (with cacheDirectory option for caching in node_modules/.cache/babel-loader )", "title": "webpack.config.react.js"}, {"location": "cozy-scripts/webpack-configs/#webpackconfigvendorsjs", "text": "A copy-webpack-plugin plugin usage to copy all files from the vendors/assets/ folder to the output build folder. This config will also process the application icon and run svgo to optimize it if this is a SVG file.", "title": "webpack.config.vendors.js"}, {"location": "cozy-scripts/webpack-configs/#environments", "text": "", "title": "Environments"}, {"location": "cozy-scripts/webpack-configs/#webpackenvironmentdevjs", "text": "", "title": "webpack.environment.dev.js"}, {"location": "cozy-scripts/webpack-configs/#properties_1", "text": "devtool to #source-map externals with ['cozy'] to exclude all cozy.* dependencies from the output bundle (since it will be serve by ProvidePlugin ) mode to development", "title": "Properties"}, {"location": "cozy-scripts/webpack-configs/#plugins_1", "text": "webpack.DefinePlugin to define globals variables at compiling time: __DEVELOPMENT__ to true __STACK_ASSETS__ to false webpack.ProvidePlugin to provide cozy-bar and cozy-client-js from node_modules (in production, these modules will be provided to the application by the cozy-stack ) Copy ( copy-webpack-plugin ) the cozy-bar.css file from node_modules ot the app build to be able to develop on the cozy-bar using the app Add the cozy-bar css to the main html file via html-webpack-include-assets-plugin Only in the hot reload mode: - webpack.HotModuleReplacementPlugin which allows all kinds of modules to be updated at runtime without the need for a full refresh - write-file-webpack-plugin to write all the build file from webpack-dev-server to the disk (necessary for the hot-reloading)", "title": "Plugins"}, {"location": "cozy-scripts/webpack-configs/#webpackenvironmentprodjs", "text": "", "title": "webpack.environment.prod.js"}, {"location": "cozy-scripts/webpack-configs/#plugins_2", "text": "webpack.optimize.OccurrenceOrderPlugin webpack.DefinePlugin to define globals variables at compiling time: process.env.NODE_ENV to production __DEVELOPMENT__ to false __DEVTOOLS__ to false __STACK_ASSETS__ to true if target different from mobile In this production mode, webpack will automatically use the Terser plugin to optimize the build (with parallel: true to speedup the build).", "title": "Plugins"}, {"location": "cozy-scripts/webpack-configs/#targets", "text": "", "title": "Targets"}, {"location": "cozy-scripts/webpack-configs/#webpacktargetbrowserjs", "text": "", "title": "webpack.target.browser.js"}, {"location": "cozy-scripts/webpack-configs/#properties_2", "text": "entry : the babel-polyfill import and the index.jsx from src/targets/browser/ output : build/ path with filename to [name].js and pathinfo enabling only with the COZY_SCRIPTS_DEBUG mode externals with { 'cozy-client-js': 'cozy' } to exclude cozy-client-js (via cozy.* ) dependency from the output bundle", "title": "Properties"}, {"location": "cozy-scripts/webpack-configs/#plugins_3", "text": "script-ext-html-webpack-plugin to load the main application .js file using the defer attribute (to be loaded after the initial loading) and used with html-webpack-plugin html-webpack-plugin configured to use index.ejs HTML template from src/targets/browser/ with options: title : name property of the package.json inject to false excludeChunks : to exclude chunk intents minify with collapseWhitespace to true webpack.DefinePlugin to define globals variables at compile time: __TARGET__ to browser", "title": "Plugins"}, {"location": "cozy-scripts/webpack-configs/#webpacktargetmobilejs", "text": "", "title": "webpack.target.mobile.js"}, {"location": "cozy-scripts/webpack-configs/#properties_3", "text": "entry : the babel-polyfill import and the index.jsx from src/targets/mobile output : src/targets/mobile/www path and pathinfo enabling only with the COZY_SCRIPTS_DEBUG mode", "title": "Properties"}, {"location": "cozy-scripts/webpack-configs/#plugins_4", "text": "script-ext-html-webpack-plugin to load the main application .js file using the defer attribute (to be loaded after the initial loading) and used with html-webpack-plugin html-webpack-plugin configured to use index.ejs HTML template from src/targets/mobile/ with options: title : name property of the package.json excludeChunks : to exclude chunk intents inject to head minify with collapseWhitespace to true webpack.DefinePlugin to define globals variables at compile time: __ALLOW_HTTP__ to false if production environment, true for other environments __TARGET__ to mobile __APP_VERSION__ to the version property of the package.json webpack.ProvidePlugin to provide cozy-bar and cozy-client-js from node_modules (since it\u2019s for the native application, it\u2019s not served by the cozy-stack unlike the browser version)", "title": "Plugins:"}, {"location": "cozy-scripts/webpack-configs/#miscellaneous", "text": "", "title": "Miscellaneous"}, {"location": "cozy-scripts/webpack-configs/#webpackvarsjs", "text": "This file is used to get webpack variables. They are necessary to build correctly the application. It will export these following variables: - addAnalyzer according to the COZY_SCRIPTS_ANALYZER environment variable (used to get the webpack-bundle-analyze usage) - environment according to NODE_ENV environment variable ( target:environment ) - getCSSLoader , a function returing the correctly style lodaer to use ( mini-css-extract-plugin loader by default and style-loader for hot reloading) - isDebugMode according to the COZY_SCRIPTS_DEBUG environment variable (used to get into a debug mode of cozy-scripts ) - target according to NODE_ENV environment variable ( target:environment ) - useHotReload according to the HOT_RELOAD environment variable to use hot reloading feature or not If no environment variable NODE_ENV is found, it will be browser:development by default.", "title": "webpack.vars.js"}, {"location": "cozy-scripts/webpack-merge-strategies/", "text": "Merge Webpack configurations using strategies with cozy-scripts \u00b6 cozy-scripts uses the webpack-merge module to merge all webpack config files provided by default or by the application. And that module can handle many merge options. Smart merging \u00b6 When this mode is used, webpack-merge will try to be smart about loaders merging and will try to gather loaders with matching tests into a single one. This merge kind also handle strategies explained in the next part. You can find more informations in the official documentation Strategies \u00b6 When merging configurations, the mechanism will append by default properties and values. Sometimes you may want to replace a previous property by a new one without duplicating it. So you have to specify a merge strategy for the related configuration. You can find more informations in the official documentation How to use them? \u00b6 cozy-scripts will check the configurations before merging and passing them to webpack and a custom property, named __mergeStrategy , will allow you to specify a strategy when merging the related configuration. Then this property will be removed right before using webpack since custom properties are not allowed. Let\u2019s take a case where you want to use the webpack.bundle.default but you want to replace the stylus loader (from webpack.config.cozy-ui.js ) which doesn\u2019t use css-modules by default to use them. Here is the configuration that you must provide: // app.config.js const configs = require ( 'cozy-scripts/config/webpack.bundle.default.js' ) const MiniCssExtractPlugin = require ( 'mini-css-extract-plugin' ) module . exports = [ configs , { // this object should be in a separate JS file for better readibility // but this is an example __mergeStrategy : { smart : true , // enable the smart mode or not (Boolean) strategy : { // webpack config properties here like `entry`, `output`... 'module.loaders' : 'replace' // replace | append | prepend // loaders !== rules, we want to replace loader properties not rules directly } }, module : { rules : [ { test : /\\.styl$/ , // the exclude property must also be the same than the loader // you want to replace exclude : /(node_modules|cozy-ui\\/react)/ , loader : extractor . extract ({ fallback : 'style-loader' , use : [ MiniCssExtractPlugin . loader , { loader : 'css-loader' , options : { sourceMap : true , importLoaders : 1 , modules : true , localIdentName : '[local]--[hash:base64:5]' } }, { loader : 'postcss-loader' , options : { sourceMap : true , plugins : function () { return [ require ( 'autoprefixer' )({ browsers : [ 'last 2 versions' ] }) ] } } }, { loader : 'stylus-loader' , options : { preferPathResolver : 'webpack' } } ] }) } ] } } ]", "title": "Merge Webpack configurations using strategies with `cozy-scripts`"}, {"location": "cozy-scripts/webpack-merge-strategies/#merge-webpack-configurations-using-strategies-with-cozy-scripts", "text": "cozy-scripts uses the webpack-merge module to merge all webpack config files provided by default or by the application. And that module can handle many merge options.", "title": "Merge Webpack configurations using strategies with cozy-scripts"}, {"location": "cozy-scripts/webpack-merge-strategies/#smart-merging", "text": "When this mode is used, webpack-merge will try to be smart about loaders merging and will try to gather loaders with matching tests into a single one. This merge kind also handle strategies explained in the next part. You can find more informations in the official documentation", "title": "Smart merging"}, {"location": "cozy-scripts/webpack-merge-strategies/#strategies", "text": "When merging configurations, the mechanism will append by default properties and values. Sometimes you may want to replace a previous property by a new one without duplicating it. So you have to specify a merge strategy for the related configuration. You can find more informations in the official documentation", "title": "Strategies"}, {"location": "cozy-scripts/webpack-merge-strategies/#how-to-use-them", "text": "cozy-scripts will check the configurations before merging and passing them to webpack and a custom property, named __mergeStrategy , will allow you to specify a strategy when merging the related configuration. Then this property will be removed right before using webpack since custom properties are not allowed. Let\u2019s take a case where you want to use the webpack.bundle.default but you want to replace the stylus loader (from webpack.config.cozy-ui.js ) which doesn\u2019t use css-modules by default to use them. Here is the configuration that you must provide: // app.config.js const configs = require ( 'cozy-scripts/config/webpack.bundle.default.js' ) const MiniCssExtractPlugin = require ( 'mini-css-extract-plugin' ) module . exports = [ configs , { // this object should be in a separate JS file for better readibility // but this is an example __mergeStrategy : { smart : true , // enable the smart mode or not (Boolean) strategy : { // webpack config properties here like `entry`, `output`... 'module.loaders' : 'replace' // replace | append | prepend // loaders !== rules, we want to replace loader properties not rules directly } }, module : { rules : [ { test : /\\.styl$/ , // the exclude property must also be the same than the loader // you want to replace exclude : /(node_modules|cozy-ui\\/react)/ , loader : extractor . extract ({ fallback : 'style-loader' , use : [ MiniCssExtractPlugin . loader , { loader : 'css-loader' , options : { sourceMap : true , importLoaders : 1 , modules : true , localIdentName : '[local]--[hash:base64:5]' } }, { loader : 'postcss-loader' , options : { sourceMap : true , plugins : function () { return [ require ( 'autoprefixer' )({ browsers : [ 'last 2 versions' ] }) ] } } }, { loader : 'stylus-loader' , options : { preferPathResolver : 'webpack' } } ] }) } ] } } ]", "title": "How to use them?"}, {"location": "cozy-stack/", "text": "What is the Cozy-Stack? \u00b6 The cozy-stack is the main backend server for the Cozy platform. Full Cozy-Stack documentation here . The Cozy-Stack is in charge of serving / running the applications users have installed on their Cozy. It is in charge of: creating, updating, deleting documents inside the database; authenticating users and client applications; sending emails; launching jobs on the server. Connectors that import data from remote websites are jobs. Jobs can be one time tasks (sending a message) or periodic tasks. Jobs that require executing third party code on the server side (like connectors), are sandboxed; database replication API, allowing to sync documents between the server and local databases, for example in mobile clients. Feel free to open an issue for questions and suggestions. How-to guides \u00b6 Usage \u00b6 Install the cozy-stack Configuration file Managing Instances Security Manpages of the command-line tool Using the admin API Important changes For developers \u00b6 Using the HTTP API of cozy-stack Develop a client-side app Develop a konnector Running and building Docker images Adding a new doctype Working with the stack assets Build a release The contributing guide Explanation \u00b6 Up-to-date \u00b6 Flagship app Move design Realtime internals Sharing design Workflow of the konnectors Archives \u00b6 These pages are the results of studies we made. They may be outdated and are kept as an archive to help understanding what were out original intentions when designing new services. General overview of the initial architecture Onboarding with an application Moving Golang Couchdb Plugins Konnectors design Replication Realtime design Reference \u00b6 List of services \u00b6 /auth - Authentication & OAuth Delegated authentication /apps - Applications Management Apps registry Konnectors /bitwarden - Bitwarden /connection_check - Connection check /contacts - Contacts /data - Data System Mango CouchDB Quirks & PouchDB Quirks /files - Virtual File System Not synchronized directories References of documents in VFS /intents - Intents /jobs - Jobs Workers /move - Move, export and import an instance /notes - Notes with collaborative edition /notifications - Notifications /office - Collaborative edition of Office documents /permissions - Permissions /public - Public /realtime - Realtime /remote - Proxy for remote data/API NextCloud /settings - Settings Terms of Services /sharings - Sharing /shortcuts - Shortcuts /.well-known - Well-known", "title": "README"}, {"location": "cozy-stack/#what-is-the-cozy-stack", "text": "The cozy-stack is the main backend server for the Cozy platform. Full Cozy-Stack documentation here . The Cozy-Stack is in charge of serving / running the applications users have installed on their Cozy. It is in charge of: creating, updating, deleting documents inside the database; authenticating users and client applications; sending emails; launching jobs on the server. Connectors that import data from remote websites are jobs. Jobs can be one time tasks (sending a message) or periodic tasks. Jobs that require executing third party code on the server side (like connectors), are sandboxed; database replication API, allowing to sync documents between the server and local databases, for example in mobile clients. Feel free to open an issue for questions and suggestions.", "title": "What is the Cozy-Stack?"}, {"location": "cozy-stack/#how-to-guides", "text": "", "title": "How-to guides"}, {"location": "cozy-stack/#usage", "text": "Install the cozy-stack Configuration file Managing Instances Security Manpages of the command-line tool Using the admin API Important changes", "title": "Usage"}, {"location": "cozy-stack/#for-developers", "text": "Using the HTTP API of cozy-stack Develop a client-side app Develop a konnector Running and building Docker images Adding a new doctype Working with the stack assets Build a release The contributing guide", "title": "For developers"}, {"location": "cozy-stack/#explanation", "text": "", "title": "Explanation"}, {"location": "cozy-stack/#up-to-date", "text": "Flagship app Move design Realtime internals Sharing design Workflow of the konnectors", "title": "Up-to-date"}, {"location": "cozy-stack/#archives", "text": "These pages are the results of studies we made. They may be outdated and are kept as an archive to help understanding what were out original intentions when designing new services. General overview of the initial architecture Onboarding with an application Moving Golang Couchdb Plugins Konnectors design Replication Realtime design", "title": "Archives"}, {"location": "cozy-stack/#reference", "text": "", "title": "Reference"}, {"location": "cozy-stack/#list-of-services", "text": "/auth - Authentication & OAuth Delegated authentication /apps - Applications Management Apps registry Konnectors /bitwarden - Bitwarden /connection_check - Connection check /contacts - Contacts /data - Data System Mango CouchDB Quirks & PouchDB Quirks /files - Virtual File System Not synchronized directories References of documents in VFS /intents - Intents /jobs - Jobs Workers /move - Move, export and import an instance /notes - Notes with collaborative edition /notifications - Notifications /office - Collaborative edition of Office documents /permissions - Permissions /public - Public /realtime - Realtime /remote - Proxy for remote data/API NextCloud /settings - Settings Terms of Services /sharings - Sharing /shortcuts - Shortcuts /.well-known - Well-known", "title": "List of services"}, {"location": "cozy-stack/CONTRIBUTING/", "text": "How to contribute to the Cozy Stack? \u00b6 Thank you for your interest in contributing to Cozy! There are many ways to contribute, and we appreciate all of them. Security Issues \u00b6 If you discover a security issue, please bring it to their attention right away! Please DO NOT file a public issue, instead send your report privately to security AT cozycloud DOT cc. Security reports are greatly appreciated and we will publicly thank you for it. We currently do not offer a paid security bounty program, but are not ruling it out in the future. Bug Reports \u00b6 While bugs are unfortunate, they\u2019re a reality in software. We can\u2019t fix what we don\u2019t know about, so please report liberally. If you\u2019re not sure if something is a bug or not, feel free to file a bug anyway. Opening an issue is as easy as following this link and filling out the fields. Here are some things you can write about your bug: A short summary What did you try, step by step? What did you expect? What did happen instead? What is the version of the Cozy Stack? You can also use the cozy-stack tools bug command to open the form to report issue prefilled with some useful system informations. Pull Requests \u00b6 Workflow \u00b6 Pull requests are the primary mechanism we use to change Cozy. GitHub itself has some great documentation on using the Pull Request feature. We use the \u2018fork and pull\u2019 model described there. Step 1: Fork \u00b6 Fork the project on GitHub and check out your copy locally: $ git clone https://github.com/cozy/cozy-stack.git $ cd cozy-stack $ git remote add fork git://github.com/username/cozy-stack.git Step 2: Branch \u00b6 Create a branch and start hacking: $ git checkout -b my-branch -t origin/master Step 3: Code \u00b6 Well, I think you know how to do that. Just be sure to follow the coding guidelines from the Go community (gofmt, Effective Go , comment the code, etc.). We are using goimports to format code, and golangci-lint to detect code smells. $ make lint We are using eslint to lint JavaScript code. The linting rules are based on cozy-app $ make jslint Step 4: Test \u00b6 Don\u2019t forget to add tests and be sure they are green. You need CouchDB installed, with an account, and configuring the stack to use this account: $ export COZY_COUCHDB_URL = http://admin:password@localhost:5984 $ make unit-tests If you want to play with the modified cozy-stack (for example, testing it with a webapp), you can build it locally and start it with this command: $ make run Step 5: Commit \u00b6 Writing good commit messages is important. A commit message should describe what changed and why. Step 6: Rebase \u00b6 Use git pull --rebase , or git rebase (but not git merge ), to sync your work from time to time: $ git pull origin master --rebase Step 7: Push \u00b6 $ git push fork my-branch Go to https://github.com/username/cozy-stack and select your branch. Click the \u2018Pull Request\u2019 button and fill out the form. Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in a separate commit and push that to your branch. Code organization \u00b6 The codebase of cozy-stack contains several packages, and it is quite easy to have circular import issues in go. To limit the risk, we have split the packages in several directories with some rules for the imports. In short, a package in this list should import other packages that are on the same line or below: main and cmd are the top level packages web is where we have the routers and handlers for web requests worker is where we define the workers for our job system model is for high-level internal packages (in general one package is used for one doctype) client is a small number of packages used for writing clients for the stack pkg is the low-level packages (most of those packages are just a couple of structs and functions). Note that tests/testutils can be used safely in web and worker packages. In model , it can be used but it is recommended to use a fake package for the tests if it is the case. For example, model/oauth/client_test.go is declared as package oauth_test . External assets \u00b6 The cozy-stack serve some assets for the client application. In particular, cozy-client-js and cozy-bar assets are listed in assets/.externals . To update them, you can open a pull request for this file. When a maintainer will accept this pull request, he will also run make assets to transform them in go code (to make the repository go gettable). Useful commands \u00b6 There are some useful commands to know in order to develop with the go code of cozy-stack: cd cozy-stack make help # Show the commands that can be launched via make go build # Build the stack, also takes care of updating dependencies through gomodules go install # Installs the `cozy-stack` binary go test -v ./... # To launch the tests go run main.go serve # To start the API server godoc -http = :6060 # To start the documentation server # Open http://127.0.0.1:6060/pkg/github.com/cozy/cozy-stack/ Writing documentation \u00b6 Documentation improvements are very welcome. We try to keep a good documentation in the docs/ folder. But, you know, we are developers, we can forget to document important stuff that look obvious to us. And documentation can always be improved. Translations \u00b6 The Cozy Stack is translated on a platform called Transifex . This tutorial can help you to learn how to make your first steps here. If you have any question, don\u2019t hesitate to ask us! The translations are kept synchronized with transifex via their github integration. Community \u00b6 You can help us by making our community even more vibrant. For example, you can write a blog post, take some videos, answer the questions on the forum , organize new meetups, and speak about what you like in Cozy!", "title": "The contributing guide"}, {"location": "cozy-stack/CONTRIBUTING/#how-to-contribute-to-the-cozy-stack", "text": "Thank you for your interest in contributing to Cozy! There are many ways to contribute, and we appreciate all of them.", "title": "How to contribute to the Cozy Stack?"}, {"location": "cozy-stack/CONTRIBUTING/#security-issues", "text": "If you discover a security issue, please bring it to their attention right away! Please DO NOT file a public issue, instead send your report privately to security AT cozycloud DOT cc. Security reports are greatly appreciated and we will publicly thank you for it. We currently do not offer a paid security bounty program, but are not ruling it out in the future.", "title": "Security Issues"}, {"location": "cozy-stack/CONTRIBUTING/#bug-reports", "text": "While bugs are unfortunate, they\u2019re a reality in software. We can\u2019t fix what we don\u2019t know about, so please report liberally. If you\u2019re not sure if something is a bug or not, feel free to file a bug anyway. Opening an issue is as easy as following this link and filling out the fields. Here are some things you can write about your bug: A short summary What did you try, step by step? What did you expect? What did happen instead? What is the version of the Cozy Stack? You can also use the cozy-stack tools bug command to open the form to report issue prefilled with some useful system informations.", "title": "Bug Reports"}, {"location": "cozy-stack/CONTRIBUTING/#pull-requests", "text": "", "title": "Pull Requests"}, {"location": "cozy-stack/CONTRIBUTING/#workflow", "text": "Pull requests are the primary mechanism we use to change Cozy. GitHub itself has some great documentation on using the Pull Request feature. We use the \u2018fork and pull\u2019 model described there.", "title": "Workflow"}, {"location": "cozy-stack/CONTRIBUTING/#step-1-fork", "text": "Fork the project on GitHub and check out your copy locally: $ git clone https://github.com/cozy/cozy-stack.git $ cd cozy-stack $ git remote add fork git://github.com/username/cozy-stack.git", "title": "Step 1: Fork"}, {"location": "cozy-stack/CONTRIBUTING/#step-2-branch", "text": "Create a branch and start hacking: $ git checkout -b my-branch -t origin/master", "title": "Step 2: Branch"}, {"location": "cozy-stack/CONTRIBUTING/#step-3-code", "text": "Well, I think you know how to do that. Just be sure to follow the coding guidelines from the Go community (gofmt, Effective Go , comment the code, etc.). We are using goimports to format code, and golangci-lint to detect code smells. $ make lint We are using eslint to lint JavaScript code. The linting rules are based on cozy-app $ make jslint", "title": "Step 3: Code"}, {"location": "cozy-stack/CONTRIBUTING/#step-4-test", "text": "Don\u2019t forget to add tests and be sure they are green. You need CouchDB installed, with an account, and configuring the stack to use this account: $ export COZY_COUCHDB_URL = http://admin:password@localhost:5984 $ make unit-tests If you want to play with the modified cozy-stack (for example, testing it with a webapp), you can build it locally and start it with this command: $ make run", "title": "Step 4: Test"}, {"location": "cozy-stack/CONTRIBUTING/#step-5-commit", "text": "Writing good commit messages is important. A commit message should describe what changed and why.", "title": "Step 5: Commit"}, {"location": "cozy-stack/CONTRIBUTING/#step-6-rebase", "text": "Use git pull --rebase , or git rebase (but not git merge ), to sync your work from time to time: $ git pull origin master --rebase", "title": "Step 6: Rebase"}, {"location": "cozy-stack/CONTRIBUTING/#step-7-push", "text": "$ git push fork my-branch Go to https://github.com/username/cozy-stack and select your branch. Click the \u2018Pull Request\u2019 button and fill out the form. Pull requests are usually reviewed within a few days. If there are comments to address, apply your changes in a separate commit and push that to your branch.", "title": "Step 7: Push"}, {"location": "cozy-stack/CONTRIBUTING/#code-organization", "text": "The codebase of cozy-stack contains several packages, and it is quite easy to have circular import issues in go. To limit the risk, we have split the packages in several directories with some rules for the imports. In short, a package in this list should import other packages that are on the same line or below: main and cmd are the top level packages web is where we have the routers and handlers for web requests worker is where we define the workers for our job system model is for high-level internal packages (in general one package is used for one doctype) client is a small number of packages used for writing clients for the stack pkg is the low-level packages (most of those packages are just a couple of structs and functions). Note that tests/testutils can be used safely in web and worker packages. In model , it can be used but it is recommended to use a fake package for the tests if it is the case. For example, model/oauth/client_test.go is declared as package oauth_test .", "title": "Code organization"}, {"location": "cozy-stack/CONTRIBUTING/#external-assets", "text": "The cozy-stack serve some assets for the client application. In particular, cozy-client-js and cozy-bar assets are listed in assets/.externals . To update them, you can open a pull request for this file. When a maintainer will accept this pull request, he will also run make assets to transform them in go code (to make the repository go gettable).", "title": "External assets"}, {"location": "cozy-stack/CONTRIBUTING/#useful-commands", "text": "There are some useful commands to know in order to develop with the go code of cozy-stack: cd cozy-stack make help # Show the commands that can be launched via make go build # Build the stack, also takes care of updating dependencies through gomodules go install # Installs the `cozy-stack` binary go test -v ./... # To launch the tests go run main.go serve # To start the API server godoc -http = :6060 # To start the documentation server # Open http://127.0.0.1:6060/pkg/github.com/cozy/cozy-stack/", "title": "Useful commands"}, {"location": "cozy-stack/CONTRIBUTING/#writing-documentation", "text": "Documentation improvements are very welcome. We try to keep a good documentation in the docs/ folder. But, you know, we are developers, we can forget to document important stuff that look obvious to us. And documentation can always be improved.", "title": "Writing documentation"}, {"location": "cozy-stack/CONTRIBUTING/#translations", "text": "The Cozy Stack is translated on a platform called Transifex . This tutorial can help you to learn how to make your first steps here. If you have any question, don\u2019t hesitate to ask us! The translations are kept synchronized with transifex via their github integration.", "title": "Translations"}, {"location": "cozy-stack/CONTRIBUTING/#community", "text": "You can help us by making our community even more vibrant. For example, you can write a blog post, take some videos, answer the questions on the forum , organize new meetups, and speak about what you like in Cozy!", "title": "Community"}, {"location": "cozy-stack/INSTALL/", "text": "Table of contents How to install Cozy-stack? \u00b6 Dependencies \u00b6 A reverse-proxy (nginx, caddy, haproxy, etc.) A SMTP server CouchDB 3 Git Image Magick (and the Lato font, ghostscript et rsvg-convert) To install CouchDB 3 through Docker, take a look at our Docker specific documentation . Note: to generate thumbnails for heic/heif images, the version 6.9+ of Image Magick is required. Install for self-hosting \u00b6 We have started to write documentation on how to install cozy on your own server. We have guides for self hosting , either on Debian with precompiled binary packages of from sources on Ubuntu. Don\u2019t hesitate to report issues with them. It will help us improve documentation. Install for development / local tests \u00b6 Install the binary \u00b6 You can either download the binary or compile it. Download an official release \u00b6 You can download a cozy-stack binary from our official releases: https://github.com/cozy/cozy-stack/releases. It is a just a single executable file (choose the one for your platform). Rename it to cozy-stack, give it the executable bit ( chmod +x cozy-stack ) and put it in your $PATH . cozy-stack version should show you the version if every thing is right. Compile the binary using go \u00b6 You can compile a cozy-stack from the source. First, you need to install go , version >= 1.19. With go installed and configured, you can run the following commands: git clone git@github.com:cozy/cozy-stack.git cd cozy-stack make This will fetch the sources and build a binary in $GOPATH/bin/cozy-stack . Don\u2019t forget to add your $GOPATH/bin to your $PATH at the end of your *rc file so that you can execute the binary without entering its full path. export PATH=\"$(go env GOPATH)/bin:$PATH\" Troubleshooting \u00b6 Check if you don\u2019t have an alias \u201cgo\u201d configurated in your *rc file. Add an instance for testing \u00b6 You can configure your cozy-stack using a configuration file or different comand line arguments. Assuming CouchDB is installed and running on default port 5984 , you can start the server: cozy-stack serve And then create an instance for development: make instance The cozy-stack server listens on http://cozy.localhost:8080/ by default. See cozy-stack --help for more informations. The above command will create an instance on http://cozy.localhost:8080/ with the passphrase cozy . By default this will create a storage/ entry in your current directory, containing all your instances by their URL. An instance \u201ccozy.localhost:8080\u201d will have its stored files in storage/cozy.localhost:8080/ . Installed apps will be found in the .cozy_apps/ directory of each instance. Make sure the full stack is up with: curl -H 'Accept: application/json' 'http://cozy.localhost:8080/status/' You can then remove your test instance: cozy-stack instances rm cozy.localhost:8080", "title": "Install the cozy-stack"}, {"location": "cozy-stack/INSTALL/#how-to-install-cozy-stack", "text": "", "title": "How to install Cozy-stack?"}, {"location": "cozy-stack/INSTALL/#dependencies", "text": "A reverse-proxy (nginx, caddy, haproxy, etc.) A SMTP server CouchDB 3 Git Image Magick (and the Lato font, ghostscript et rsvg-convert) To install CouchDB 3 through Docker, take a look at our Docker specific documentation . Note: to generate thumbnails for heic/heif images, the version 6.9+ of Image Magick is required.", "title": "Dependencies"}, {"location": "cozy-stack/INSTALL/#install-for-self-hosting", "text": "We have started to write documentation on how to install cozy on your own server. We have guides for self hosting , either on Debian with precompiled binary packages of from sources on Ubuntu. Don\u2019t hesitate to report issues with them. It will help us improve documentation.", "title": "Install for self-hosting"}, {"location": "cozy-stack/INSTALL/#install-for-development-local-tests", "text": "", "title": "Install for development / local tests"}, {"location": "cozy-stack/INSTALL/#install-the-binary", "text": "You can either download the binary or compile it.", "title": "Install the binary"}, {"location": "cozy-stack/INSTALL/#download-an-official-release", "text": "You can download a cozy-stack binary from our official releases: https://github.com/cozy/cozy-stack/releases. It is a just a single executable file (choose the one for your platform). Rename it to cozy-stack, give it the executable bit ( chmod +x cozy-stack ) and put it in your $PATH . cozy-stack version should show you the version if every thing is right.", "title": "Download an official release"}, {"location": "cozy-stack/INSTALL/#compile-the-binary-using-go", "text": "You can compile a cozy-stack from the source. First, you need to install go , version >= 1.19. With go installed and configured, you can run the following commands: git clone git@github.com:cozy/cozy-stack.git cd cozy-stack make This will fetch the sources and build a binary in $GOPATH/bin/cozy-stack . Don\u2019t forget to add your $GOPATH/bin to your $PATH at the end of your *rc file so that you can execute the binary without entering its full path. export PATH=\"$(go env GOPATH)/bin:$PATH\"", "title": "Compile the binary using go"}, {"location": "cozy-stack/INSTALL/#troubleshooting", "text": "Check if you don\u2019t have an alias \u201cgo\u201d configurated in your *rc file.", "title": "Troubleshooting"}, {"location": "cozy-stack/INSTALL/#add-an-instance-for-testing", "text": "You can configure your cozy-stack using a configuration file or different comand line arguments. Assuming CouchDB is installed and running on default port 5984 , you can start the server: cozy-stack serve And then create an instance for development: make instance The cozy-stack server listens on http://cozy.localhost:8080/ by default. See cozy-stack --help for more informations. The above command will create an instance on http://cozy.localhost:8080/ with the passphrase cozy . By default this will create a storage/ entry in your current directory, containing all your instances by their URL. An instance \u201ccozy.localhost:8080\u201d will have its stored files in storage/cozy.localhost:8080/ . Installed apps will be found in the .cozy_apps/ directory of each instance. Make sure the full stack is up with: curl -H 'Accept: application/json' 'http://cozy.localhost:8080/status/' You can then remove your test instance: cozy-stack instances rm cozy.localhost:8080", "title": "Add an instance for testing"}, {"location": "cozy-stack/accept-from-flagship/", "text": "Table of contents Accept from Flagship \u00b6 Flagship app is a mobile app that allows users to access all their Cozy from their phone (see here for more details). When the Flagship app is installed on the user\u2019s phone, then they can share a document with the app to upload it in their Cozy. When doing so, the user will have to chose which cozy-app should receive the shared document from a list of elligible cozy-apps (i.e. cozy-drive, mespapiers, etc) To be elligible, a cozy-app has to declare what it can receive. This is done in its manifest.webapp file. The manifest \u00b6 The manifest.webapp file is used to declare the cozy-app\u2019s ability to receive files accept_from_flagship field \u00b6 First field to declare is accept_from_flagship . It should be set to true to make the cozy-app visible in the list of elligible cozy-apps Example: { \"name\" : \"Drive\" , \"name_prefix\" : \"Cozy\" , \"slug\" : \"drive\" , //... \"accept_from_flagship\" : true , //... } accept_documents_from_flagship field \u00b6 Declaring accept_from_flagship: true is not enough to be able to receive files from the Flagship app. The app should also declare which kind of files it can handle. The field accept_documents_from_flagship is an object containing all criteria that a file or a list of files should meet to be sharable with the cozy-app. accepted_mime_types criteria \u00b6 accepted_mime_types is used to declare each file type that can be handled by the cozy-app. This field should contain a list of all mime types that are supported by the cozy-app. Example of a cozy-app accepting PDF, and pictures: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"accepted_mime_types\" : [ \"application/pdf\" , \"image/jpeg\" , \"image/png\" ], } } In order to accept all files types, it is possible to use '*/*' mime type Example of a cozy-app accepting all types of documents: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"accepted_mime_types\" : [ \"*/*\" ], } } max_number_of_files criteria \u00b6 max_number_of_files is used to declare the maximum number of files that can be shared simultaneously with the cozy-app. Example of a cozy-app accepting only 1 document at a time: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"max_number_of_files\" : 10 , } } Example of a cozy-app accepting up to 10 documents at a time: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"max_number_of_files\" : 10 , } } Setting a limit is mandatory. The Flagship app doesn\u2019t support unlimited file number. max_size_per_file_in_MB criteria \u00b6 max_size_per_file_in_MB is used to declare the maximum size of files that can be handled by the cozy-app. The size limit is declared in MB. The size limit is per file. If multiple files are shared with the cozy-app, then each file size should be under that limit. Example of a cozy-app accepting documents up to 10MB: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"max_size_per_file_in_MB\" : 10 , } } Setting a limit is mandatory. The Flagship app doesn\u2019t support unlimited file size. route_to_upload criteria \u00b6 route_to_upload is used to declare the cozy-app\u2019s route that should be used by the Flagship app when sharing files with the cozy-app. The app should then implement a page on that route that will be responsible to handle those documents (i.e. ask the user where to save the document, analyse the document etc) Example: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"route_to_upload\" : \"/#/upload?fromFlagshipUpload=true\" , } } The complete manifest \u00b6 Here is an example of a manifest.webapp file for an app accepting only up to 10 picture files, with a maximum of 10MB: { \"name\" : \"Drive\" , \"name_prefix\" : \"Cozy\" , \"slug\" : \"drive\" , //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"accepted_mime_types\" : [ \"image/jpeg\" , \"image/png\" ], \"max_number_of_files\" : 10 , \"max_size_per_file_in_MB\" : 10 , \"route_to_upload\" : \"/#/upload?fromFlagshipUpload=true\" } //... } Note that accept_from_flagship may seems to be redundant if accept_documents_from_flagship exists. This field is an optimization to allow cozy-client queries to filter only cozy-apps that accept sharings. The API \u00b6 When a cozy-app is selected by the user to receive a shared file, this cozy-app is opened using the route_to_upload route. Then the cozy-app can use the Flagship OsReceive API to handle shared files. This API is documented here", "title": "Accept from flagship"}, {"location": "cozy-stack/accept-from-flagship/#accept-from-flagship", "text": "Flagship app is a mobile app that allows users to access all their Cozy from their phone (see here for more details). When the Flagship app is installed on the user\u2019s phone, then they can share a document with the app to upload it in their Cozy. When doing so, the user will have to chose which cozy-app should receive the shared document from a list of elligible cozy-apps (i.e. cozy-drive, mespapiers, etc) To be elligible, a cozy-app has to declare what it can receive. This is done in its manifest.webapp file.", "title": "Accept from Flagship"}, {"location": "cozy-stack/accept-from-flagship/#the-manifest", "text": "The manifest.webapp file is used to declare the cozy-app\u2019s ability to receive files", "title": "The manifest"}, {"location": "cozy-stack/accept-from-flagship/#accept_from_flagship-field", "text": "First field to declare is accept_from_flagship . It should be set to true to make the cozy-app visible in the list of elligible cozy-apps Example: { \"name\" : \"Drive\" , \"name_prefix\" : \"Cozy\" , \"slug\" : \"drive\" , //... \"accept_from_flagship\" : true , //... }", "title": "accept_from_flagship field"}, {"location": "cozy-stack/accept-from-flagship/#accept_documents_from_flagship-field", "text": "Declaring accept_from_flagship: true is not enough to be able to receive files from the Flagship app. The app should also declare which kind of files it can handle. The field accept_documents_from_flagship is an object containing all criteria that a file or a list of files should meet to be sharable with the cozy-app.", "title": "accept_documents_from_flagship field"}, {"location": "cozy-stack/accept-from-flagship/#accepted_mime_types-criteria", "text": "accepted_mime_types is used to declare each file type that can be handled by the cozy-app. This field should contain a list of all mime types that are supported by the cozy-app. Example of a cozy-app accepting PDF, and pictures: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"accepted_mime_types\" : [ \"application/pdf\" , \"image/jpeg\" , \"image/png\" ], } } In order to accept all files types, it is possible to use '*/*' mime type Example of a cozy-app accepting all types of documents: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"accepted_mime_types\" : [ \"*/*\" ], } }", "title": "accepted_mime_types criteria"}, {"location": "cozy-stack/accept-from-flagship/#max_number_of_files-criteria", "text": "max_number_of_files is used to declare the maximum number of files that can be shared simultaneously with the cozy-app. Example of a cozy-app accepting only 1 document at a time: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"max_number_of_files\" : 10 , } } Example of a cozy-app accepting up to 10 documents at a time: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"max_number_of_files\" : 10 , } } Setting a limit is mandatory. The Flagship app doesn\u2019t support unlimited file number.", "title": "max_number_of_files criteria"}, {"location": "cozy-stack/accept-from-flagship/#max_size_per_file_in_mb-criteria", "text": "max_size_per_file_in_MB is used to declare the maximum size of files that can be handled by the cozy-app. The size limit is declared in MB. The size limit is per file. If multiple files are shared with the cozy-app, then each file size should be under that limit. Example of a cozy-app accepting documents up to 10MB: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"max_size_per_file_in_MB\" : 10 , } } Setting a limit is mandatory. The Flagship app doesn\u2019t support unlimited file size.", "title": "max_size_per_file_in_MB criteria"}, {"location": "cozy-stack/accept-from-flagship/#route_to_upload-criteria", "text": "route_to_upload is used to declare the cozy-app\u2019s route that should be used by the Flagship app when sharing files with the cozy-app. The app should then implement a page on that route that will be responsible to handle those documents (i.e. ask the user where to save the document, analyse the document etc) Example: { //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"route_to_upload\" : \"/#/upload?fromFlagshipUpload=true\" , } }", "title": "route_to_upload criteria"}, {"location": "cozy-stack/accept-from-flagship/#the-complete-manifest", "text": "Here is an example of a manifest.webapp file for an app accepting only up to 10 picture files, with a maximum of 10MB: { \"name\" : \"Drive\" , \"name_prefix\" : \"Cozy\" , \"slug\" : \"drive\" , //... \"accept_from_flagship\" : true , \"accept_documents_from_flagship\" : { \"accepted_mime_types\" : [ \"image/jpeg\" , \"image/png\" ], \"max_number_of_files\" : 10 , \"max_size_per_file_in_MB\" : 10 , \"route_to_upload\" : \"/#/upload?fromFlagshipUpload=true\" } //... } Note that accept_from_flagship may seems to be redundant if accept_documents_from_flagship exists. This field is an optimization to allow cozy-client queries to filter only cozy-apps that accept sharings.", "title": "The complete manifest"}, {"location": "cozy-stack/accept-from-flagship/#the-api", "text": "When a cozy-app is selected by the user to receive a shared file, this cozy-app is opened using the route_to_upload route. Then the cozy-app can use the Flagship OsReceive API to handle shared files. This API is documented here", "title": "The API"}, {"location": "cozy-stack/admin/", "text": "Table of contents Admin \u00b6 Introduction \u00b6 An admin API is available on the stack. It offers several endpoints to interact with your cozy-stack installation (E.g. interacting with instances, generating tokens, \u2026). Use the admin API only if you know what you are doing. The admin API provides a basic authentication, you must protect these endpoints as they are very powerful. The default port for the admin endpoints is 6060 . If you want to customize the parameters, please see the config file documentation page . Instance \u00b6 GET /instances \u00b6 Returns the list of all instances. By default, there is no pagination, but it is possible to add a page[limit] parameter in the query-string to paginate ( cf JSON-API pagination ). A page[skip] parameter in the query-string is also supported, but CouchDB may be slow on requests with a skip on large collections. Request \u00b6 GET /instances HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"instances\" , \"id\" : \"3af6ed68a6d9146b3529d2584a001d98\" , \"attributes\" : { \"domain\" : \"alice.cozy.localhost:8080\" , \"prefix\" : \"cozy7d3d5947e7f3b0c674d1b8644646348e\" , \"locale\" : \"fr\" , \"context\" : \"dev\" , \"onboarding_finished\" : true , \"indexes_version\" : 30 }, \"meta\" : { \"rev\" : \"1-32c855c989e8f6def0bc0cc417d8b3b4\" }, \"links\" : { \"self\" : \"/instances/3af6ed68a6d9146b3529d2584a001d98\" } }, { \"type\" : \"instances\" , \"id\" : \"3af6ed68a6d9146b3529d2584a01d557\" , \"attributes\" : { \"domain\" : \"bob.cozy.localhost:8080\" , \"prefix\" : \"cozybf682065ca3c7d64f2dafc6cc12fe702\" , \"locale\" : \"fr\" , \"context\" : \"dev\" , \"onboarding_finished\" : true , \"indexes_version\" : 30 }, \"meta\" : { \"rev\" : \"1-ab6f77dbfdb3aab5b70b022e37fe231f\" }, \"links\" : { \"self\" : \"/instances/3af6ed68a6d9146b3529d2584a01d557\" } } ], \"meta\" : { \"count\" : 2 } } GET /instances/count \u00b6 Returns the count of all instances. Request \u00b6 GET /instances/count HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"count\" : 259 } GET /instances/:domain/last-activity \u00b6 It returns an approximate date of when the instance was last used by their owner (automatic jobs like connectors don\u2019t count). It looks at the sessions and OAuth tokens. Request \u00b6 GET /instances/john.mycozy.cloud/last-activity HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"last-activity\" : \"2022-12-31\" } PATCH /instances/:domain \u00b6 This route can be used to change an instance (email, locale, disk quota, ToS, etc.) Note a special parameter FromCloudery=true in the query string can be used to tell the stack to not call the cloudery if the email or public name has changed, since the change is already coming from the cloudery. Request \u00b6 PATCH /instances/john.mycozy.cloud?Email=john@example.com&FromCloudery=true HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK { \"data\" : { \"type\" : \"instances\" , \"id\" : \"0dc76ad9b1cf3a979b916b3155001830\" , \"attributes\" : { \"domain\" : \"john.mycozy.cloud\" , \"prefix\" : \"cozy1a4e1aabf424a194d7daf946d7b1337d\" , \"locale\" : \"fr\" , \"context\" : \"cozy\" , \"onboarding_finished\" : true , \"indexes_version\" : 31 , \"passphrase_hash\" : \"c2NyeXB0JDMyNzY4JDgkMSQyYjMzMTU1YTY5OTdjYzM2ZjQyYjk1MWM0MWU4ZWVkYSRlODA4NTY2ODQ5OTdkOWNmNzc1ZGEzMjdlYWMwOTgyNTMwMTM3NTJjYTMxMTdhYTIyYTIxODI0NzBmODhjYjdl\" , \"session_secret\" : \"eyG2l+G1xO38WyD1GfqYkgSU/T4rnti+JzOwj6haHpM8PSMvzkGu/CSH0mpXUuuCNVbjEXc+hRwGMJ8lTKqs+w==\" , \"oauth_secret\" : \"tnr6V8jDK27CDVpzNiOOAJZs+5wrvGyNyJxIc/BJ6O87i2eJX4LCzblDFyDbVv/B7qV7HA9/Fc+Agon2gHQg8x0E0zzfGizbFeWt+KPk7UrZNd4sZJ81oWNNd9BrJ2+eKXDmZeYBI0AwUSykyr7iOIpB5jXaIvfOQvH7EYwtKLg=\" , \"cli_secret\" : \"dcLa1VqcoI4eNE7nBrFzhJ9w6rRLlAMESl3PAEqr+IDE29OeN3uyhzLhxPlk0b9rkc0yvozQc/AFttZxyqH/DDYa6rrJyrf91gddtwSfka1pJVss+/DiFaghyWJzEbffBs78X3swA2gSJNu0eGDKdFVY7q8iLT4JpfXy+GPzdLk=\" }, \"meta\" : { \"rev\" : \"1-1c4efe4196191469a65b2a3e0898db61\" }, \"links\" : { \"self\" : \"/instances/0dc76ad9b1cf3a979b916b3155001830\" } } } GET /instances/with-app-version/:slug/:version \u00b6 Returns all the instances using slug/version pair Request \u00b6 GET /instances/with-app-version/drive/1.0.0 HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"instances\" : [ \"alice.cozy.localhost\" , \"bob.cozy.localhost\" , \"zoe.cozy.localhost\" ] } POST /instances/:domain/magic_link \u00b6 Creates a code that can be used in a magic link (if this feature is enabled on the Cozy). Request \u00b6 POST /instances/alice.cozy.localhost/magic_link HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"code\" : \"YmU5NmEzMzAtYjZiYy0wMTNiLTE1YzUtMThjMDRkYWJhMzI2\" } POST /instances/:domain/session_code \u00b6 Creates a session_code that can be used to login on the given instance. Request \u00b6 POST /instances/alice.cozy.localhost/session_code HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"session_code\" : \"L7oJ6BDQtdbLR5Vr5vTxTXLJ1pQzMXcD\" } POST /instances/:domain/session_code/check \u00b6 Checks that a session_code is valid for the given instance. Note that the session_code will be invalidated after that. Request \u00b6 POST /instances/alice.cozy.localhost/session_code/check HTTP / 1.1 Content-Type : application/json { \"session_code\" : \"L7oJ6BDQtdbLR5Vr5vTxTXLJ1pQzMXcD\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"valid\" : true } POST /instances/:domain/email_verified_code \u00b6 Creates an email_verified_code that can be used on the given instance to avoid the 2FA by email. Request \u00b6 POST /instances/alice.cozy.localhost/email_verified_code HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"email_verified_code\" : \"jBPF5Kvpv1oztdaSgdA2315hVpAf6BCd\" } Note: if the two factor authentication by email is not enabled on this instance, it will return a 400 Bad Request error. DELETE /instances/:domain/sessions \u00b6 Delete the databases for io.cozy.sessions and io.cozy.sessions.logins. Request \u00b6 DELETE /instances/alice.cozy.localhost/sessions HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 No Content POST /instances/:domain/fixers/content-mismatch \u00b6 Fixes the 64k (or multiple) content mismatch files of an instance Request \u00b6 POST /instances/alice.cozy.localhost/fixers/content-mismatch HTTP / 1.1 Content-Type : application/json { \"dry_run\" : true } The dry_run (default to true ) body parameter tells if the request is a dry-run or not. Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"dry_run\" : true , \"updated\" : [ { \"filepath\" : \"/file64.txt\" , \"id\" : \"3c79846513e81aee78ab30849d006550\" , \"created_at\" : \"2019-07-30 15:05:27.268876334 +0200 CEST\" , \"updated_at\" : \"2019-07-30 15:05:27.268876334 +0200 CEST\" } ], \"removed\" : [ { \"filepath\" : \"/.cozy_trash/file64.txt-corrupted\" , \"id\" : \"3c79846513e81aee78ab30849d001f98\" , \"created_at\" : \"2019-07-30 10:18:28.826400117 +0200 CEST\" , \"updated_at\" : \"2019-07-30 14:32:29.862882247 +0200 CEST\" } ], \"domain\" : \"alice.cozy.localhost\" } POST /instances/:domain/fixers/password-defined \u00b6 Fill the password_defined field of the io.cozy.settings.instance if it was missing. Request \u00b6 POST /instances/alice.cozy.localhost/fixers/password-defined HTTP / 1.1 POST /instances/:domain/fixers/orphan-account \u00b6 Delete the accounts which are not linked to a konnector Request \u00b6 POST /instances/alice.cozy.localhost/fixers/orphan-account HTTP / 1.1 POST /instances/:domain/export \u00b6 Starts an export for the given instance. The CouchDB documents will be saved in an intermediary archive while the files won\u2019t be added until the data is actually downloaded. The response contains the details of the scheduled export job. Query-String \u00b6 Parameter Description admin-req Boolean indicating when the request is made by an admin and the user should not be notified The admin-req parameter is optional: by default, the instance\u2019s owner will be notified via e-mail, whether the export is successful or not. If it\u2019s successful, the e-mail will contain a link to the Settings app allowing the user to download the data archives. When this parameter is true , no e-mails will be sent and the admin will be able to get the export document via realtime events. Request \u00b6 POST /instances/alice.cozy.localhost/export?admin-req=true HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 Accepted Content-Type : application/json { \"_id\" : \"123123\" , \"_rev\" : \"1-58d2b368da0a1b336bcd18ced210a8a1\" , \"domain\" : \"alice.cozy.localhost\" , \"prefix\" : \"cozyfdd8fd8eb825ad98821b11871abf58c9\" , \"worker\" : \"export\" , \"message\" : { \"parts_size\" : 0 , \"max_age\" : 0 , \"contextual_domain\" : \"alice.cozy.localhost\" , \"admin_req\" : true }, \"event\" : null , \"state\" : \"queued\" , \"queued_at\" : \"2023-02-01T11:50:59.286530525+01:00\" , \"started_at\" : \"0001-01-01T00:00:00Z\" , \"finished_at\" : \"0001-01-01T00:00:00Z\" } GET /instances/:domain/exports/:export-id/data \u00b6 This endpoint will return an archive containing the metadata and files of the user, as part of a multi-part response. Only the first part of the archive contains the metadata. Query-String \u00b6 Parameter Description cursor String reprentation of the export cursor to start the download from The cursor parameter is optional but any given cursor should be one of the defined parts_cursors in the export document. To get all the parts, this endpoint must be called one time with no cursors, and one time for each cursor in parts_cursors . Request \u00b6 GET /instances/alice.cozy.localhost/exports/123123/data?cursor=io.cozy.files%2Fa27b3bae83160774a74525de670d5d8e HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/zip Content-Disposition : attachment; filename=\"alice.cozy.localhost - part001.zip\" POST /instances/:domain/notifications \u00b6 This endpoint allows to send a notification via the notification center. Both the notification declaration and its properties need to be passed in the body. These notifications cannot use templates defined in cozy-stack though so their e-mail content must be provided directly (at least in HTML). When the request is successful, the generated notification object is returned. POST /instances/alice.cozy.localhost/notifications HTTP / 1.1 Authorization : Bearer ... Content-Type : application/json { \"notification\" : { \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"preferred_channels\" : [ \"mobile\" ], \"content\" : \"Hello,\\r\\nWe have detected a negative balance in your my-bank account.\" , \"content_html\" : \"\\r\\n\\t\\r\\n\\t

    Hello,
    We have detected a negative balance in your my-bank account.

    \\r\\n\\t\\r\\n\\t\" }, \"properties\" : { \"description\" : \"Alert the user when its account balance is negative\" , \"collapsible\" : true , \"multiple\" : true , \"stateful\" : true , \"default_priority\" : \"high\" } } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/json { \"_id\" : \"c57a548c-7602-11e7-933b-6f27603d27da\" , \"_rev\" : \"1-1f2903f9a867\" , \"source_id\" : \"cozy/cli//account-balance/my-bank\" , \"originator\" : \"cli\" , \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"created_at\" : \"2024-01-04T15:23:01.832Z\" , \"last_sent\" : \"2024-01-04T15:23:01.832Z\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"content\" : \"Hello,\\r\\nWe have detected a negative balance in your my-bank account.\" , \"contentHTML\" : \"\\r\\n\\t\\r\\n\\t

    Hello,
    We have detected a negative balance in your my-bank account.

    \\r\\n\\t\\r\\n\\t\" } Contexts \u00b6 GET /instances/contexts \u00b6 This endpoint returns the list of the contexts, with their name, config, registries, office server, cloudery endpoints, and OIDC data. Request \u00b6 GET /instances/contexts HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK [ { \"config\" : { \"claudy_actions\" : [ \"desktop\" , \"mobile\" , \"support\" ], \"debug\" : true , \"features\" : [ { \"foo\" : \"bar\" }, { \"baz\" : [ \"qux\" , \"quux\" ] } ], \"help_link\" : \"https://forum.cozy.io/\" , \"noreply_address\" : \"noreply@cozy.beta\" , \"noreply_name\" : \"My Cozy Beta\" , \"sharing_domain\" : \"cozy.localhost\" }, \"context\" : \"dev\" , \"registries\" : [ \"https://apps-registry.cozycloud.cc/\" ], \"office\" : { \"OnlyOfficeURL\" : \"https://documentserver.cozycloud.cc/\" }, \"cloudery_endpoint\" : \"\" , \"oidc\" : { \"allow_oauth_token\" : false , \"authorize_url\" : \"https://identity-prodiver/path/to/authorize\" , \"client_id\" : \"aClientID\" , \"id_token_jwk_url\" : \"https://identity-prodiver/path/to/jwk\" , \"login_domain\" : \"login.mycozy.cloud\" , \"redirect_uri\" : \"https://oauthcallback.mycozy.cloud/oidc/redirect\" , \"scope\" : \"openid profile\" , \"token_url\" : \"https://identity-prodiver/path/to/token\" , \"userinfo_instance_field\" : \"cozy_number\" , \"userinfo_instance_prefix\" : \"name\" , \"userinfo_instance_suffix\" : \".mycozy.cloud\" , \"userinfo_url\" : \"https://identity-prodiver/path/to/userinfo\" } } ] GET /instances/contexts/:name \u00b6 This endpoint returns the config of a given context. Request \u00b6 GET /instances/contexts/dev HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK { \"config\" : { \"claudy_actions\" : [ \"desktop\" , \"mobile\" , \"support\" ], \"debug\" : true , \"features\" : [ { \"foo\" : \"bar\" }, { \"baz\" : [ \"qux\" , \"quux\" ] } ], \"help_link\" : \"https://forum.cozy.io/\" , \"noreply_address\" : \"noreply@cozy.beta\" , \"noreply_name\" : \"My Cozy Beta\" , \"sharing_domain\" : \"cozy.localhost\" }, \"context\" : \"dev\" , \"registries\" : [ \"https://apps-registry.cozycloud.cc/\" ], \"office\" : { \"OnlyOfficeURL\" : \"https://documentserver.cozycloud.cc/\" , \"InboxSecret\" : \"inbox_secret\" , \"OutboxSecret\" : \"outbox_secret\" }, \"cloudery_endpoint\" : \"\" } Checkers \u00b6 GET /instances/:domain/fsck \u00b6 This endpoint can be use to check the VFS of a given instance. It accepts three possible parameters in the query-string: IndexIntegrity=true to check only the integrity of the data in CouchDB FilesConsistency to check the consistency between CouchDB and Swift FailFast to abort on the first error. It will returns a 200 OK , except if the instance is not found where the code will be 404 Not Found (a 5xx can also happen in case of server errors like CouchDB not available). The format of the response will be one JSON per line, and each JSON represents an error. Request \u00b6 GET /instances/alice.cozy.localhost/fsck HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK { \"type\" : \"index_orphan_tree\" , \"dir_doc\" :{ \"type\" : \"directory\" , \"_id\" : \"34a61c6ceb38075fe971cc6a3263659f\" , \"_rev\" : \"2-94ca3acfebf927cb231d125c57f85bd7\" , \"name\" : \"Photos\" , \"dir_id\" : \"45496c5c442dabecae87de3d73008ec4\" , \"created_at\" : \"2020-12-15T18:23:21.498323965+01:00\" , \"updated_at\" : \"2020-12-15T18:23:21.498323965+01:00\" , \"tags\" :[], \"path\" : \"/Photos\" , \"cozyMetadata\" :{ \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-12-15T18:23:21.498327603+01:00\" , \"updatedAt\" : \"2020-12-15T18:23:21.498327603+01:00\" , \"createdOn\" : \"http://alice.cozy.localhost:8080/\" }, \"size\" : \"0\" , \"is_dir\" : true , \"is_orphan\" : true , \"has_cycle\" : false }, \"is_file\" : false , \"is_version\" : false } { \"type\" : \"index_missing\" , \"file_doc\" :{ \"type\" : \"file\" , \"name\" : \"Photos\" , \"dir_id\" : \"\" , \"created_at\" : \"2020-12-15T18:23:21.527308795+01:00\" , \"updated_at\" : \"2020-12-15T18:23:21.527308795+01:00\" , \"tags\" : null , \"path\" : \"/Photos\" , \"size\" : \"4096\" , \"mime\" : \"application/octet-stream\" , \"class\" : \"files\" , \"executable\" : true , \"is_dir\" : false , \"is_orphan\" : false , \"has_cycle\" : false }, \"is_file\" : true , \"is_version\" : false } POST /instances/:domain/checks/triggers \u00b6 This endpoint will check if no trigger has been installed twice (or more). Request \u00b6 POST /instances/alice.cozy.localhost/checks/triggers HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json [ { \"_id\" : \"45496c5c442dabecae87de3d7300666f\" , \"arguments\" : \"io.cozy.files:CREATED,UPDATED,DELETED:image:class\" , \"debounce\" : \"\" , \"other_id\" : \"34a61c6ceb38075fe971cc6a3263895f\" , \"trigger\" : \"@event\" , \"type\" : \"duplicate\" , \"worker\" : \"thumbnail\" } ] POST /instances/:domain/checks/shared \u00b6 This endpoint will check that the io.cozy.shared documents have a correct revision tree (no generation smaller for a children than its parent). Request \u00b6 POST /instances/alice.cozy.localhost/checks/shared HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json [ { \"_id\" : \"io.cozy.files/fd1706de234d17d1ac2fe560051a2aae\" , \"child_rev\" : \"1-e19947b4f9bfb273bc8958ae932ae4c7\" , \"parent_rev\" : \"2-4f82af35577dbc9b686dd447719e4835\" , \"type\" : \"invalid_revs_suite\" }, { \"_id\" : \"io.cozy.files/fd9bef5df406f5b150f302b8c5b3f5f0\" , \"child_rev\" : \"7-05bb459e0ac5450c17df79ed1f13afa1\" , \"parent_rev\" : \"8-07b4cafef3c2e74e698ee4a04d1874c2\" , \"type\" : \"invalid_revs_suite\" } ] POST /instances/:domain/checks/sharings \u00b6 This endpoint can be used to check the setup of sharings owned by a given instance and the consistency of the shared files and folders with their counterparts on the Cozy they\u2019re shared with. It accepts one parameter in the query-string: Fast to skip the files and folders consistency check as it can be quite long It will return a 200 OK , except if the instance is not found where the code will be 404 Not Found (a 5xx can also happen in case of server errors like CouchDB not available). The format of the response will be a JSON array of objects, each object representing an error. Possible error types \u00b6 invalid_rules \u00b6 This will be raised when the owner\u2019s sharing rules are invalid. The validation result will be returned in the error attribute. sharing_in_sharing \u00b6 This will be raised when the root of the sharing being checked is part of another sharing (i.e. one of its parent folders is shared). The parent sharing can be found either on the owner\u2019s instance or on one of its members\u2019 instance. The parent_sharing attribute will contain the parent sharing ID. missing_matching_docs_for_owner \u00b6 This will be raised if the shared files and folders associated with the sharing could not be fetched on the owner\u2019s instance. The request error will be returned in the error attribute. No further consistency checks will be run on this sharing. missing_sharing_for_member \u00b6 This will be raised when the associated io.cozy.sharing document cannot be found on a sharing member\u2019s instance. The request error will be returned in the error attribute. No further consistency checks will be run for this member. missing_files_rule_for_member \u00b6 This will be raised if a member\u2019s sharing doesn\u2019t have any sharing rule for io.cozy.files documents (while the owner\u2019s sharing has been determined to be of this type). The member\u2019s domain will be available in the member attribute. No further consistency checks will be run for this member. missing_matching_docs_for_member \u00b6 This will be raised if the shared files and folders associated with the sharing could not be fetched on a member\u2019s instance. The request error will be returned in the error attribute and the member\u2019s domain in the member attribute. No further consistency checks will be run for this member. disk_quota_exceeded \u00b6 This will be raised if a file is outdated or missing on an instance and its size is larger than the available space on this instance. If the file was created or modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The instance\u2019s domain will be available in the instance attribute. read_only_member \u00b6 This will be raised if a file or folder is outdated or missing on the owner\u2019s instance and the member being checked has only read-only access to the sharing. This is not really an error as this behavior is expected but since it can be confusing for users we log it for debugging purposes. The member\u2019s domain will be available in the member attribute. invalid_doc_rev \u00b6 This will be raised if a file or folder\u2019s revisions don\u2019t match on the owner\u2019s and member\u2019s instances while the member has write access to the sharing and the file size is not greater than the outdated instance\u2019s available disk space. The revisions generations can be the same too. If the document was modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The member\u2019s domain will be available in the member attribute, as well as the revision of the member document in memberRev and the complete owner document in ownerDoc . invalid_doc_name \u00b6 This will be raised if a file or folder\u2019s revisions match on the owner\u2019s and member\u2019s instances but their names don\u2019t. The member\u2019s domain will be available in the member attribute, as well as the name of the member document in memberName and the complete owner document in ownerDoc . invalid_doc_checksum \u00b6 This will be raised if a file\u2019s revisions match on the owner\u2019s and member\u2019s instances but their checksums don\u2019t. The member\u2019s domain will be available in the member attribute, as well as the checksum of the member file in memberChecksum and the complete owner document in ownerDoc . invalid_doc_parent \u00b6 This will be raised if a file or folder\u2019s parent directories don\u2019t match on the owner\u2019s and member\u2019s instances but their names don\u2019t. Since it is expected for the sharing root to not have different parents on each instance, the check does not apply to this document. The member\u2019s domain will be available in the member attribute, as well as the id of the member\u2019s parent directory in memberParent and the complete owner document in ownerDoc . missing_matching_doc_for_owner \u00b6 This will be raised if a file or directory is missing on the owner\u2019s instance while the member being check has write access to the sharing and the file size is not greater than the instance\u2019s available disk space. If the missing document was created or modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The member\u2019s domain will be available in the member attribute and the complete missing member document in memberDoc . missing_matching_doc_for_member \u00b6 This will be raised if a file or directory is missing on a member\u2019s instance while the file size is not greater than the instance\u2019s available disk space. If the missing document was created or modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The member\u2019s domain will be available in the member attribute and the complete missing owner document in ownerDoc . === Other error types include missing_trigger_on_active_sharing , trigger_on_inactive_sharing , not_enough_members , mail_not_sent , invalid_member_status , invalid_instance_for_member , missing_instance_for_member , missing_oauth_client , missing_access_token , invalid_number_of_credentials and missing_inbound_client_id . When checking for files and folders inconsistencies, sharings will be skipped when inactive, not initialized, read-only or not about io.cozy.files documents. Also, for each instance, only the sharings owned by said instance will be checked. Other sharings will be checked via their owner instance. Request \u00b6 POST /instances/alice.cozy.localhost/checks/sharings HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json [ { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"trigger\" : \"track\" , \"trigger_id\" : \"314d69d7ebaed0a1870cca67f4d75e41\" , \"type\" : \"trigger_on_inactive_sharing\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"trigger\" : \"replicate\" , \"trigger_id\" : \"314d69d7ebaed0a1870cca67f4d75e41\" , \"type\" : \"trigger_on_inactive_sharing\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"trigger\" : \"upload\" , \"trigger_id\" : \"314d69d7ebaed0a1870cca67f4d75e41\" , \"type\" : \"trigger_on_inactive_sharing\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"member\" : 0 , \"status\" : \"revoked\" , \"type\" : \"invalid_member_status\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"nb_members\" : 0 , \"owner\" : false , \"type\" : \"invalid_number_of_credentials\" } ] Konnectors \u00b6 GET /konnectors/maintenance \u00b6 Request \u00b6 GET /konnectors/maintenance HTTP / 1.1 A parameter Context can be given on the query string to also includes the konnectors that are in maintenance on the apps registry. Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"meta\" : { \"count\" : 1 }, \"data\" : [ { \"type\" : \"io.cozy.konnectors.maintenance\" , \"attributes\" : { \"level\" : \"stack\" , \"maintenance_activated\" : true , \"maintenance_options\" : { \"flag_disallow_manual_exec\" : false , \"flag_infra_maintenance\" : true , \"flag_short_maintenance\" : true , \"messages\" : { \"fr\" : { \"long_message\" : \"Bla bla bla\" , \"short_message\" : \"Bla\" } } }, \"slug\" : \"ameli\" , \"type\" : \"konnector\" } } ] } Note: level can be stack or registry . PUT /konnectors/maintenance/:slug \u00b6 Request \u00b6 PUT /konnectors/maintenance/ameli HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"flag_short_maintenance\" : true , \"flag_disallow_manual_exec\" : false , \"messages\" : { \"fr\" : { \"long_message\" : \"Bla bla bla\" , \"short_message\" : \"Bla\" }, \"en\" : { \"long_message\" : \"Yadi yadi yada\" , \"short_message\" : \"Yada\" } } } } } Note: the flag_infra_maintenance will always be set to true with this endpoint. Response \u00b6 HTTP / 1.1 204 No Content DELETE /konnectors/maintenance/:slug \u00b6 Request \u00b6 DELETE /konnectors/maintenance/ameli HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 No Content OIDC \u00b6 POST /oidc/:context/:provider/code \u00b6 This endpoint is used by the cloudery to create a delegated code, which will be then used by the flagship app to obtain its access_token and refresh_token. The :provider parameter can be generic or franceconnect . The cloudery sends its access_token for the OIDC provider, the stack can use it to make a request to the userinfo endpoint of the OIDC provider. With the response, the stack can create a delegated code associated to the sub. POST /oidc/dev/franceconnect/code HTTP / 1.1 Accept : application/json Content-Type : application/json Authorization : Bearer ZmE2ZTFmN { \"access_token\" : \"ZmE2ZTFmN\" } HTTP / 1.1 200 OK Content-Type : application/json { \"delegated_code\" : \"wMTNiLTNmZWItMThY\" , \"sub\" : \"DIzYWE2MjA\" , \"email\" : \"jerome@example.org\" } OAuth clients \u00b6 DELETE /oauth/:domain/clients \u00b6 Delete all the OAuth clients for the given instance. It can be limited to a specific kind of clients ( desktop , mobile , sharing , etc.) by using the Kind parameter of the query-string. It returns the number of clients that have been deleted. Request \u00b6 DELETE /oauth/cozy.example/clients HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK { \"count\" : 42 } Swift \u00b6 GET /swift/layouts \u00b6 Count swift layouts by type Request \u00b6 GET /swift/layouts HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"total\" : 3 , \"unknown\" : { \"counter\" : 0 }, \"v1\" : { \"counter\" : 1 }, \"v2a\" : { \"counter\" : 0 }, \"v2b\" : { \"counter\" : 0 }, \"v3a\" : { \"counter\" : 2 }, \"v3b\" : { \"counter\" : 4 } } The show_domains=true query parameter provides the domain names if needed Request \u00b6 GET /swift/layouts?show_domains=true HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"total\" : 3 , \"unknown\" : { \"counter\" : 0 }, \"v1\" : { \"counter\" : 1 , \"domains\" : [ \"bob.cozy.localhost:8081\" ] }, \"v2a\" : { \"counter\" : 0 }, \"v2b\" : { \"counter\" : 0 }, \"v3a\" : { \"counter\" : 2 , \"domains\" : [ \"alice.cozy.localhost:8081\" , \"ru.cozy.localhost:8081\" ] }, \"v3b\" : { \"counter\" : 4 , \"domains\" : [ \"foo.cozy.localhost:8081\" , \"bar.cozy.localhost:8081\" , \"baz.cozy.localhost:8081\" , \"foobar.cozy.localhost:8081\" ] } } GET /swift/vfs/:object \u00b6 Retrieves a Swift object Request \u00b6 GET /swift/vfs/67a88b22520680b1fae840%2F9a8a0%2F18d02%2FiYbkfuCDEMaVoIXg HTTP / 1.1 Host : alice.cozy.localhost Response \u00b6 HTTP / 1.1 200 OK Content-Type : text/plain \"foobar\" PUT /swift/vfs/:object \u00b6 Put an object in Swift Request \u00b6 PUT /swift/vfs/67a88b22520680b1fae840%2F9a8a0%2F18d02%2FiYbkfuCDEMaVoIXg HTTP / 1.1 Host : alice.cozy.localhost Content-Type : text/plain \"this is my content\" DELETE /swift/vfs/:object \u00b6 Removes an object from Swift Request \u00b6 DELETE /swift/vfs/67a88b22520680b1fae840%2F9a8a0%2F18d02%2FiYbkfuCDEMaVoIXg HTTP / 1.1 Host : alice.cozy.localhost GET /swift/vfs \u00b6 List Swift objects of an instance Request \u00b6 GET /swift/vfs HTTP / 1.1 Host : alice.cozy.localhost Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"objects_names\" : [ \"67a88b22520680b1fae840/9a8a0/17264/AxfGhAiWVRhPufKK\" , \"67a88b22520680b1fae840/9a8a0/18d02/iYbkfuCDEMaVoIXg\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-large\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-medium\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-small\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-tiny\" ] } Tools \u00b6 GET /tools/pprof/heap \u00b6 Return a sampling of memory allocations as pprof format. Request \u00b6 GET /tools/pprof/heap HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK", "title": "Using the admin API"}, {"location": "cozy-stack/admin/#admin", "text": "", "title": "Admin"}, {"location": "cozy-stack/admin/#introduction", "text": "An admin API is available on the stack. It offers several endpoints to interact with your cozy-stack installation (E.g. interacting with instances, generating tokens, \u2026). Use the admin API only if you know what you are doing. The admin API provides a basic authentication, you must protect these endpoints as they are very powerful. The default port for the admin endpoints is 6060 . If you want to customize the parameters, please see the config file documentation page .", "title": "Introduction"}, {"location": "cozy-stack/admin/#instance", "text": "", "title": "Instance"}, {"location": "cozy-stack/admin/#get-instances", "text": "Returns the list of all instances. By default, there is no pagination, but it is possible to add a page[limit] parameter in the query-string to paginate ( cf JSON-API pagination ). A page[skip] parameter in the query-string is also supported, but CouchDB may be slow on requests with a skip on large collections.", "title": "GET /instances"}, {"location": "cozy-stack/admin/#request", "text": "GET /instances HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"instances\" , \"id\" : \"3af6ed68a6d9146b3529d2584a001d98\" , \"attributes\" : { \"domain\" : \"alice.cozy.localhost:8080\" , \"prefix\" : \"cozy7d3d5947e7f3b0c674d1b8644646348e\" , \"locale\" : \"fr\" , \"context\" : \"dev\" , \"onboarding_finished\" : true , \"indexes_version\" : 30 }, \"meta\" : { \"rev\" : \"1-32c855c989e8f6def0bc0cc417d8b3b4\" }, \"links\" : { \"self\" : \"/instances/3af6ed68a6d9146b3529d2584a001d98\" } }, { \"type\" : \"instances\" , \"id\" : \"3af6ed68a6d9146b3529d2584a01d557\" , \"attributes\" : { \"domain\" : \"bob.cozy.localhost:8080\" , \"prefix\" : \"cozybf682065ca3c7d64f2dafc6cc12fe702\" , \"locale\" : \"fr\" , \"context\" : \"dev\" , \"onboarding_finished\" : true , \"indexes_version\" : 30 }, \"meta\" : { \"rev\" : \"1-ab6f77dbfdb3aab5b70b022e37fe231f\" }, \"links\" : { \"self\" : \"/instances/3af6ed68a6d9146b3529d2584a01d557\" } } ], \"meta\" : { \"count\" : 2 } }", "title": "Response"}, {"location": "cozy-stack/admin/#get-instancescount", "text": "Returns the count of all instances.", "title": "GET /instances/count"}, {"location": "cozy-stack/admin/#request_1", "text": "GET /instances/count HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"count\" : 259 }", "title": "Response"}, {"location": "cozy-stack/admin/#get-instancesdomainlast-activity", "text": "It returns an approximate date of when the instance was last used by their owner (automatic jobs like connectors don\u2019t count). It looks at the sessions and OAuth tokens.", "title": "GET /instances/:domain/last-activity"}, {"location": "cozy-stack/admin/#request_2", "text": "GET /instances/john.mycozy.cloud/last-activity HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"last-activity\" : \"2022-12-31\" }", "title": "Response"}, {"location": "cozy-stack/admin/#patch-instancesdomain", "text": "This route can be used to change an instance (email, locale, disk quota, ToS, etc.) Note a special parameter FromCloudery=true in the query string can be used to tell the stack to not call the cloudery if the email or public name has changed, since the change is already coming from the cloudery.", "title": "PATCH /instances/:domain"}, {"location": "cozy-stack/admin/#request_3", "text": "PATCH /instances/john.mycozy.cloud?Email=john@example.com&FromCloudery=true HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_3", "text": "HTTP / 1.1 200 OK { \"data\" : { \"type\" : \"instances\" , \"id\" : \"0dc76ad9b1cf3a979b916b3155001830\" , \"attributes\" : { \"domain\" : \"john.mycozy.cloud\" , \"prefix\" : \"cozy1a4e1aabf424a194d7daf946d7b1337d\" , \"locale\" : \"fr\" , \"context\" : \"cozy\" , \"onboarding_finished\" : true , \"indexes_version\" : 31 , \"passphrase_hash\" : \"c2NyeXB0JDMyNzY4JDgkMSQyYjMzMTU1YTY5OTdjYzM2ZjQyYjk1MWM0MWU4ZWVkYSRlODA4NTY2ODQ5OTdkOWNmNzc1ZGEzMjdlYWMwOTgyNTMwMTM3NTJjYTMxMTdhYTIyYTIxODI0NzBmODhjYjdl\" , \"session_secret\" : \"eyG2l+G1xO38WyD1GfqYkgSU/T4rnti+JzOwj6haHpM8PSMvzkGu/CSH0mpXUuuCNVbjEXc+hRwGMJ8lTKqs+w==\" , \"oauth_secret\" : \"tnr6V8jDK27CDVpzNiOOAJZs+5wrvGyNyJxIc/BJ6O87i2eJX4LCzblDFyDbVv/B7qV7HA9/Fc+Agon2gHQg8x0E0zzfGizbFeWt+KPk7UrZNd4sZJ81oWNNd9BrJ2+eKXDmZeYBI0AwUSykyr7iOIpB5jXaIvfOQvH7EYwtKLg=\" , \"cli_secret\" : \"dcLa1VqcoI4eNE7nBrFzhJ9w6rRLlAMESl3PAEqr+IDE29OeN3uyhzLhxPlk0b9rkc0yvozQc/AFttZxyqH/DDYa6rrJyrf91gddtwSfka1pJVss+/DiFaghyWJzEbffBs78X3swA2gSJNu0eGDKdFVY7q8iLT4JpfXy+GPzdLk=\" }, \"meta\" : { \"rev\" : \"1-1c4efe4196191469a65b2a3e0898db61\" }, \"links\" : { \"self\" : \"/instances/0dc76ad9b1cf3a979b916b3155001830\" } } }", "title": "Response"}, {"location": "cozy-stack/admin/#get-instanceswith-app-versionslugversion", "text": "Returns all the instances using slug/version pair", "title": "GET /instances/with-app-version/:slug/:version"}, {"location": "cozy-stack/admin/#request_4", "text": "GET /instances/with-app-version/drive/1.0.0 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"instances\" : [ \"alice.cozy.localhost\" , \"bob.cozy.localhost\" , \"zoe.cozy.localhost\" ] }", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainmagic_link", "text": "Creates a code that can be used in a magic link (if this feature is enabled on the Cozy).", "title": "POST /instances/:domain/magic_link"}, {"location": "cozy-stack/admin/#request_5", "text": "POST /instances/alice.cozy.localhost/magic_link HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"code\" : \"YmU5NmEzMzAtYjZiYy0wMTNiLTE1YzUtMThjMDRkYWJhMzI2\" }", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainsession_code", "text": "Creates a session_code that can be used to login on the given instance.", "title": "POST /instances/:domain/session_code"}, {"location": "cozy-stack/admin/#request_6", "text": "POST /instances/alice.cozy.localhost/session_code HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_6", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"session_code\" : \"L7oJ6BDQtdbLR5Vr5vTxTXLJ1pQzMXcD\" }", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainsession_codecheck", "text": "Checks that a session_code is valid for the given instance. Note that the session_code will be invalidated after that.", "title": "POST /instances/:domain/session_code/check"}, {"location": "cozy-stack/admin/#request_7", "text": "POST /instances/alice.cozy.localhost/session_code/check HTTP / 1.1 Content-Type : application/json { \"session_code\" : \"L7oJ6BDQtdbLR5Vr5vTxTXLJ1pQzMXcD\" }", "title": "Request"}, {"location": "cozy-stack/admin/#response_7", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"valid\" : true }", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainemail_verified_code", "text": "Creates an email_verified_code that can be used on the given instance to avoid the 2FA by email.", "title": "POST /instances/:domain/email_verified_code"}, {"location": "cozy-stack/admin/#request_8", "text": "POST /instances/alice.cozy.localhost/email_verified_code HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_8", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"email_verified_code\" : \"jBPF5Kvpv1oztdaSgdA2315hVpAf6BCd\" } Note: if the two factor authentication by email is not enabled on this instance, it will return a 400 Bad Request error.", "title": "Response"}, {"location": "cozy-stack/admin/#delete-instancesdomainsessions", "text": "Delete the databases for io.cozy.sessions and io.cozy.sessions.logins.", "title": "DELETE /instances/:domain/sessions"}, {"location": "cozy-stack/admin/#request_9", "text": "DELETE /instances/alice.cozy.localhost/sessions HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_9", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainfixerscontent-mismatch", "text": "Fixes the 64k (or multiple) content mismatch files of an instance", "title": "POST /instances/:domain/fixers/content-mismatch"}, {"location": "cozy-stack/admin/#request_10", "text": "POST /instances/alice.cozy.localhost/fixers/content-mismatch HTTP / 1.1 Content-Type : application/json { \"dry_run\" : true } The dry_run (default to true ) body parameter tells if the request is a dry-run or not.", "title": "Request"}, {"location": "cozy-stack/admin/#response_10", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"dry_run\" : true , \"updated\" : [ { \"filepath\" : \"/file64.txt\" , \"id\" : \"3c79846513e81aee78ab30849d006550\" , \"created_at\" : \"2019-07-30 15:05:27.268876334 +0200 CEST\" , \"updated_at\" : \"2019-07-30 15:05:27.268876334 +0200 CEST\" } ], \"removed\" : [ { \"filepath\" : \"/.cozy_trash/file64.txt-corrupted\" , \"id\" : \"3c79846513e81aee78ab30849d001f98\" , \"created_at\" : \"2019-07-30 10:18:28.826400117 +0200 CEST\" , \"updated_at\" : \"2019-07-30 14:32:29.862882247 +0200 CEST\" } ], \"domain\" : \"alice.cozy.localhost\" }", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainfixerspassword-defined", "text": "Fill the password_defined field of the io.cozy.settings.instance if it was missing.", "title": "POST /instances/:domain/fixers/password-defined"}, {"location": "cozy-stack/admin/#request_11", "text": "POST /instances/alice.cozy.localhost/fixers/password-defined HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#post-instancesdomainfixersorphan-account", "text": "Delete the accounts which are not linked to a konnector", "title": "POST /instances/:domain/fixers/orphan-account"}, {"location": "cozy-stack/admin/#request_12", "text": "POST /instances/alice.cozy.localhost/fixers/orphan-account HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#post-instancesdomainexport", "text": "Starts an export for the given instance. The CouchDB documents will be saved in an intermediary archive while the files won\u2019t be added until the data is actually downloaded. The response contains the details of the scheduled export job.", "title": "POST /instances/:domain/export"}, {"location": "cozy-stack/admin/#query-string", "text": "Parameter Description admin-req Boolean indicating when the request is made by an admin and the user should not be notified The admin-req parameter is optional: by default, the instance\u2019s owner will be notified via e-mail, whether the export is successful or not. If it\u2019s successful, the e-mail will contain a link to the Settings app allowing the user to download the data archives. When this parameter is true , no e-mails will be sent and the admin will be able to get the export document via realtime events.", "title": "Query-String"}, {"location": "cozy-stack/admin/#request_13", "text": "POST /instances/alice.cozy.localhost/export?admin-req=true HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_11", "text": "HTTP / 1.1 204 Accepted Content-Type : application/json { \"_id\" : \"123123\" , \"_rev\" : \"1-58d2b368da0a1b336bcd18ced210a8a1\" , \"domain\" : \"alice.cozy.localhost\" , \"prefix\" : \"cozyfdd8fd8eb825ad98821b11871abf58c9\" , \"worker\" : \"export\" , \"message\" : { \"parts_size\" : 0 , \"max_age\" : 0 , \"contextual_domain\" : \"alice.cozy.localhost\" , \"admin_req\" : true }, \"event\" : null , \"state\" : \"queued\" , \"queued_at\" : \"2023-02-01T11:50:59.286530525+01:00\" , \"started_at\" : \"0001-01-01T00:00:00Z\" , \"finished_at\" : \"0001-01-01T00:00:00Z\" }", "title": "Response"}, {"location": "cozy-stack/admin/#get-instancesdomainexportsexport-iddata", "text": "This endpoint will return an archive containing the metadata and files of the user, as part of a multi-part response. Only the first part of the archive contains the metadata.", "title": "GET /instances/:domain/exports/:export-id/data"}, {"location": "cozy-stack/admin/#query-string_1", "text": "Parameter Description cursor String reprentation of the export cursor to start the download from The cursor parameter is optional but any given cursor should be one of the defined parts_cursors in the export document. To get all the parts, this endpoint must be called one time with no cursors, and one time for each cursor in parts_cursors .", "title": "Query-String"}, {"location": "cozy-stack/admin/#request_14", "text": "GET /instances/alice.cozy.localhost/exports/123123/data?cursor=io.cozy.files%2Fa27b3bae83160774a74525de670d5d8e HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_12", "text": "HTTP / 1.1 200 OK Content-Type : application/zip Content-Disposition : attachment; filename=\"alice.cozy.localhost - part001.zip\"", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainnotifications", "text": "This endpoint allows to send a notification via the notification center. Both the notification declaration and its properties need to be passed in the body. These notifications cannot use templates defined in cozy-stack though so their e-mail content must be provided directly (at least in HTML). When the request is successful, the generated notification object is returned. POST /instances/alice.cozy.localhost/notifications HTTP / 1.1 Authorization : Bearer ... Content-Type : application/json { \"notification\" : { \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"preferred_channels\" : [ \"mobile\" ], \"content\" : \"Hello,\\r\\nWe have detected a negative balance in your my-bank account.\" , \"content_html\" : \"\\r\\n\\t\\r\\n\\t

    Hello,
    We have detected a negative balance in your my-bank account.

    \\r\\n\\t\\r\\n\\t\" }, \"properties\" : { \"description\" : \"Alert the user when its account balance is negative\" , \"collapsible\" : true , \"multiple\" : true , \"stateful\" : true , \"default_priority\" : \"high\" } }", "title": "POST /instances/:domain/notifications"}, {"location": "cozy-stack/admin/#response_13", "text": "HTTP / 1.1 201 Created Content-Type : application/json { \"_id\" : \"c57a548c-7602-11e7-933b-6f27603d27da\" , \"_rev\" : \"1-1f2903f9a867\" , \"source_id\" : \"cozy/cli//account-balance/my-bank\" , \"originator\" : \"cli\" , \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"created_at\" : \"2024-01-04T15:23:01.832Z\" , \"last_sent\" : \"2024-01-04T15:23:01.832Z\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"content\" : \"Hello,\\r\\nWe have detected a negative balance in your my-bank account.\" , \"contentHTML\" : \"\\r\\n\\t\\r\\n\\t

    Hello,
    We have detected a negative balance in your my-bank account.

    \\r\\n\\t\\r\\n\\t\" }", "title": "Response"}, {"location": "cozy-stack/admin/#contexts", "text": "", "title": "Contexts"}, {"location": "cozy-stack/admin/#get-instancescontexts", "text": "This endpoint returns the list of the contexts, with their name, config, registries, office server, cloudery endpoints, and OIDC data.", "title": "GET /instances/contexts"}, {"location": "cozy-stack/admin/#request_15", "text": "GET /instances/contexts HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_14", "text": "HTTP / 1.1 200 OK [ { \"config\" : { \"claudy_actions\" : [ \"desktop\" , \"mobile\" , \"support\" ], \"debug\" : true , \"features\" : [ { \"foo\" : \"bar\" }, { \"baz\" : [ \"qux\" , \"quux\" ] } ], \"help_link\" : \"https://forum.cozy.io/\" , \"noreply_address\" : \"noreply@cozy.beta\" , \"noreply_name\" : \"My Cozy Beta\" , \"sharing_domain\" : \"cozy.localhost\" }, \"context\" : \"dev\" , \"registries\" : [ \"https://apps-registry.cozycloud.cc/\" ], \"office\" : { \"OnlyOfficeURL\" : \"https://documentserver.cozycloud.cc/\" }, \"cloudery_endpoint\" : \"\" , \"oidc\" : { \"allow_oauth_token\" : false , \"authorize_url\" : \"https://identity-prodiver/path/to/authorize\" , \"client_id\" : \"aClientID\" , \"id_token_jwk_url\" : \"https://identity-prodiver/path/to/jwk\" , \"login_domain\" : \"login.mycozy.cloud\" , \"redirect_uri\" : \"https://oauthcallback.mycozy.cloud/oidc/redirect\" , \"scope\" : \"openid profile\" , \"token_url\" : \"https://identity-prodiver/path/to/token\" , \"userinfo_instance_field\" : \"cozy_number\" , \"userinfo_instance_prefix\" : \"name\" , \"userinfo_instance_suffix\" : \".mycozy.cloud\" , \"userinfo_url\" : \"https://identity-prodiver/path/to/userinfo\" } } ]", "title": "Response"}, {"location": "cozy-stack/admin/#get-instancescontextsname", "text": "This endpoint returns the config of a given context.", "title": "GET /instances/contexts/:name"}, {"location": "cozy-stack/admin/#request_16", "text": "GET /instances/contexts/dev HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_15", "text": "HTTP / 1.1 200 OK { \"config\" : { \"claudy_actions\" : [ \"desktop\" , \"mobile\" , \"support\" ], \"debug\" : true , \"features\" : [ { \"foo\" : \"bar\" }, { \"baz\" : [ \"qux\" , \"quux\" ] } ], \"help_link\" : \"https://forum.cozy.io/\" , \"noreply_address\" : \"noreply@cozy.beta\" , \"noreply_name\" : \"My Cozy Beta\" , \"sharing_domain\" : \"cozy.localhost\" }, \"context\" : \"dev\" , \"registries\" : [ \"https://apps-registry.cozycloud.cc/\" ], \"office\" : { \"OnlyOfficeURL\" : \"https://documentserver.cozycloud.cc/\" , \"InboxSecret\" : \"inbox_secret\" , \"OutboxSecret\" : \"outbox_secret\" }, \"cloudery_endpoint\" : \"\" }", "title": "Response"}, {"location": "cozy-stack/admin/#checkers", "text": "", "title": "Checkers"}, {"location": "cozy-stack/admin/#get-instancesdomainfsck", "text": "This endpoint can be use to check the VFS of a given instance. It accepts three possible parameters in the query-string: IndexIntegrity=true to check only the integrity of the data in CouchDB FilesConsistency to check the consistency between CouchDB and Swift FailFast to abort on the first error. It will returns a 200 OK , except if the instance is not found where the code will be 404 Not Found (a 5xx can also happen in case of server errors like CouchDB not available). The format of the response will be one JSON per line, and each JSON represents an error.", "title": "GET /instances/:domain/fsck"}, {"location": "cozy-stack/admin/#request_17", "text": "GET /instances/alice.cozy.localhost/fsck HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_16", "text": "HTTP / 1.1 200 OK { \"type\" : \"index_orphan_tree\" , \"dir_doc\" :{ \"type\" : \"directory\" , \"_id\" : \"34a61c6ceb38075fe971cc6a3263659f\" , \"_rev\" : \"2-94ca3acfebf927cb231d125c57f85bd7\" , \"name\" : \"Photos\" , \"dir_id\" : \"45496c5c442dabecae87de3d73008ec4\" , \"created_at\" : \"2020-12-15T18:23:21.498323965+01:00\" , \"updated_at\" : \"2020-12-15T18:23:21.498323965+01:00\" , \"tags\" :[], \"path\" : \"/Photos\" , \"cozyMetadata\" :{ \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-12-15T18:23:21.498327603+01:00\" , \"updatedAt\" : \"2020-12-15T18:23:21.498327603+01:00\" , \"createdOn\" : \"http://alice.cozy.localhost:8080/\" }, \"size\" : \"0\" , \"is_dir\" : true , \"is_orphan\" : true , \"has_cycle\" : false }, \"is_file\" : false , \"is_version\" : false } { \"type\" : \"index_missing\" , \"file_doc\" :{ \"type\" : \"file\" , \"name\" : \"Photos\" , \"dir_id\" : \"\" , \"created_at\" : \"2020-12-15T18:23:21.527308795+01:00\" , \"updated_at\" : \"2020-12-15T18:23:21.527308795+01:00\" , \"tags\" : null , \"path\" : \"/Photos\" , \"size\" : \"4096\" , \"mime\" : \"application/octet-stream\" , \"class\" : \"files\" , \"executable\" : true , \"is_dir\" : false , \"is_orphan\" : false , \"has_cycle\" : false }, \"is_file\" : true , \"is_version\" : false }", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomaincheckstriggers", "text": "This endpoint will check if no trigger has been installed twice (or more).", "title": "POST /instances/:domain/checks/triggers"}, {"location": "cozy-stack/admin/#request_18", "text": "POST /instances/alice.cozy.localhost/checks/triggers HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_17", "text": "HTTP / 1.1 200 OK Content-Type : application/json [ { \"_id\" : \"45496c5c442dabecae87de3d7300666f\" , \"arguments\" : \"io.cozy.files:CREATED,UPDATED,DELETED:image:class\" , \"debounce\" : \"\" , \"other_id\" : \"34a61c6ceb38075fe971cc6a3263895f\" , \"trigger\" : \"@event\" , \"type\" : \"duplicate\" , \"worker\" : \"thumbnail\" } ]", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomainchecksshared", "text": "This endpoint will check that the io.cozy.shared documents have a correct revision tree (no generation smaller for a children than its parent).", "title": "POST /instances/:domain/checks/shared"}, {"location": "cozy-stack/admin/#request_19", "text": "POST /instances/alice.cozy.localhost/checks/shared HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_18", "text": "HTTP / 1.1 200 OK Content-Type : application/json [ { \"_id\" : \"io.cozy.files/fd1706de234d17d1ac2fe560051a2aae\" , \"child_rev\" : \"1-e19947b4f9bfb273bc8958ae932ae4c7\" , \"parent_rev\" : \"2-4f82af35577dbc9b686dd447719e4835\" , \"type\" : \"invalid_revs_suite\" }, { \"_id\" : \"io.cozy.files/fd9bef5df406f5b150f302b8c5b3f5f0\" , \"child_rev\" : \"7-05bb459e0ac5450c17df79ed1f13afa1\" , \"parent_rev\" : \"8-07b4cafef3c2e74e698ee4a04d1874c2\" , \"type\" : \"invalid_revs_suite\" } ]", "title": "Response"}, {"location": "cozy-stack/admin/#post-instancesdomaincheckssharings", "text": "This endpoint can be used to check the setup of sharings owned by a given instance and the consistency of the shared files and folders with their counterparts on the Cozy they\u2019re shared with. It accepts one parameter in the query-string: Fast to skip the files and folders consistency check as it can be quite long It will return a 200 OK , except if the instance is not found where the code will be 404 Not Found (a 5xx can also happen in case of server errors like CouchDB not available). The format of the response will be a JSON array of objects, each object representing an error.", "title": "POST /instances/:domain/checks/sharings"}, {"location": "cozy-stack/admin/#possible-error-types", "text": "", "title": "Possible error types"}, {"location": "cozy-stack/admin/#invalid_rules", "text": "This will be raised when the owner\u2019s sharing rules are invalid. The validation result will be returned in the error attribute.", "title": "invalid_rules"}, {"location": "cozy-stack/admin/#sharing_in_sharing", "text": "This will be raised when the root of the sharing being checked is part of another sharing (i.e. one of its parent folders is shared). The parent sharing can be found either on the owner\u2019s instance or on one of its members\u2019 instance. The parent_sharing attribute will contain the parent sharing ID.", "title": "sharing_in_sharing"}, {"location": "cozy-stack/admin/#missing_matching_docs_for_owner", "text": "This will be raised if the shared files and folders associated with the sharing could not be fetched on the owner\u2019s instance. The request error will be returned in the error attribute. No further consistency checks will be run on this sharing.", "title": "missing_matching_docs_for_owner"}, {"location": "cozy-stack/admin/#missing_sharing_for_member", "text": "This will be raised when the associated io.cozy.sharing document cannot be found on a sharing member\u2019s instance. The request error will be returned in the error attribute. No further consistency checks will be run for this member.", "title": "missing_sharing_for_member"}, {"location": "cozy-stack/admin/#missing_files_rule_for_member", "text": "This will be raised if a member\u2019s sharing doesn\u2019t have any sharing rule for io.cozy.files documents (while the owner\u2019s sharing has been determined to be of this type). The member\u2019s domain will be available in the member attribute. No further consistency checks will be run for this member.", "title": "missing_files_rule_for_member"}, {"location": "cozy-stack/admin/#missing_matching_docs_for_member", "text": "This will be raised if the shared files and folders associated with the sharing could not be fetched on a member\u2019s instance. The request error will be returned in the error attribute and the member\u2019s domain in the member attribute. No further consistency checks will be run for this member.", "title": "missing_matching_docs_for_member"}, {"location": "cozy-stack/admin/#disk_quota_exceeded", "text": "This will be raised if a file is outdated or missing on an instance and its size is larger than the available space on this instance. If the file was created or modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The instance\u2019s domain will be available in the instance attribute.", "title": "disk_quota_exceeded"}, {"location": "cozy-stack/admin/#read_only_member", "text": "This will be raised if a file or folder is outdated or missing on the owner\u2019s instance and the member being checked has only read-only access to the sharing. This is not really an error as this behavior is expected but since it can be confusing for users we log it for debugging purposes. The member\u2019s domain will be available in the member attribute.", "title": "read_only_member"}, {"location": "cozy-stack/admin/#invalid_doc_rev", "text": "This will be raised if a file or folder\u2019s revisions don\u2019t match on the owner\u2019s and member\u2019s instances while the member has write access to the sharing and the file size is not greater than the outdated instance\u2019s available disk space. The revisions generations can be the same too. If the document was modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The member\u2019s domain will be available in the member attribute, as well as the revision of the member document in memberRev and the complete owner document in ownerDoc .", "title": "invalid_doc_rev"}, {"location": "cozy-stack/admin/#invalid_doc_name", "text": "This will be raised if a file or folder\u2019s revisions match on the owner\u2019s and member\u2019s instances but their names don\u2019t. The member\u2019s domain will be available in the member attribute, as well as the name of the member document in memberName and the complete owner document in ownerDoc .", "title": "invalid_doc_name"}, {"location": "cozy-stack/admin/#invalid_doc_checksum", "text": "This will be raised if a file\u2019s revisions match on the owner\u2019s and member\u2019s instances but their checksums don\u2019t. The member\u2019s domain will be available in the member attribute, as well as the checksum of the member file in memberChecksum and the complete owner document in ownerDoc .", "title": "invalid_doc_checksum"}, {"location": "cozy-stack/admin/#invalid_doc_parent", "text": "This will be raised if a file or folder\u2019s parent directories don\u2019t match on the owner\u2019s and member\u2019s instances but their names don\u2019t. Since it is expected for the sharing root to not have different parents on each instance, the check does not apply to this document. The member\u2019s domain will be available in the member attribute, as well as the id of the member\u2019s parent directory in memberParent and the complete owner document in ownerDoc .", "title": "invalid_doc_parent"}, {"location": "cozy-stack/admin/#missing_matching_doc_for_owner", "text": "This will be raised if a file or directory is missing on the owner\u2019s instance while the member being check has write access to the sharing and the file size is not greater than the instance\u2019s available disk space. If the missing document was created or modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The member\u2019s domain will be available in the member attribute and the complete missing member document in memberDoc .", "title": "missing_matching_doc_for_owner"}, {"location": "cozy-stack/admin/#missing_matching_doc_for_member", "text": "This will be raised if a file or directory is missing on a member\u2019s instance while the file size is not greater than the instance\u2019s available disk space. If the missing document was created or modified in the last 5 minutes, the check is skipped as we expect the synchronization to happen later. The member\u2019s domain will be available in the member attribute and the complete missing owner document in ownerDoc . === Other error types include missing_trigger_on_active_sharing , trigger_on_inactive_sharing , not_enough_members , mail_not_sent , invalid_member_status , invalid_instance_for_member , missing_instance_for_member , missing_oauth_client , missing_access_token , invalid_number_of_credentials and missing_inbound_client_id . When checking for files and folders inconsistencies, sharings will be skipped when inactive, not initialized, read-only or not about io.cozy.files documents. Also, for each instance, only the sharings owned by said instance will be checked. Other sharings will be checked via their owner instance.", "title": "missing_matching_doc_for_member"}, {"location": "cozy-stack/admin/#request_20", "text": "POST /instances/alice.cozy.localhost/checks/sharings HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_19", "text": "HTTP / 1.1 200 OK Content-Type : application/json [ { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"trigger\" : \"track\" , \"trigger_id\" : \"314d69d7ebaed0a1870cca67f4d75e41\" , \"type\" : \"trigger_on_inactive_sharing\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"trigger\" : \"replicate\" , \"trigger_id\" : \"314d69d7ebaed0a1870cca67f4d75e41\" , \"type\" : \"trigger_on_inactive_sharing\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"trigger\" : \"upload\" , \"trigger_id\" : \"314d69d7ebaed0a1870cca67f4d75e41\" , \"type\" : \"trigger_on_inactive_sharing\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"member\" : 0 , \"status\" : \"revoked\" , \"type\" : \"invalid_member_status\" }, { \"id\" : \"314d69d7ebaed0a1870cca67f4433390\" , \"nb_members\" : 0 , \"owner\" : false , \"type\" : \"invalid_number_of_credentials\" } ]", "title": "Response"}, {"location": "cozy-stack/admin/#konnectors", "text": "", "title": "Konnectors"}, {"location": "cozy-stack/admin/#get-konnectorsmaintenance", "text": "", "title": "GET /konnectors/maintenance"}, {"location": "cozy-stack/admin/#request_21", "text": "GET /konnectors/maintenance HTTP / 1.1 A parameter Context can be given on the query string to also includes the konnectors that are in maintenance on the apps registry.", "title": "Request"}, {"location": "cozy-stack/admin/#response_20", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"meta\" : { \"count\" : 1 }, \"data\" : [ { \"type\" : \"io.cozy.konnectors.maintenance\" , \"attributes\" : { \"level\" : \"stack\" , \"maintenance_activated\" : true , \"maintenance_options\" : { \"flag_disallow_manual_exec\" : false , \"flag_infra_maintenance\" : true , \"flag_short_maintenance\" : true , \"messages\" : { \"fr\" : { \"long_message\" : \"Bla bla bla\" , \"short_message\" : \"Bla\" } } }, \"slug\" : \"ameli\" , \"type\" : \"konnector\" } } ] } Note: level can be stack or registry .", "title": "Response"}, {"location": "cozy-stack/admin/#put-konnectorsmaintenanceslug", "text": "", "title": "PUT /konnectors/maintenance/:slug"}, {"location": "cozy-stack/admin/#request_22", "text": "PUT /konnectors/maintenance/ameli HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"flag_short_maintenance\" : true , \"flag_disallow_manual_exec\" : false , \"messages\" : { \"fr\" : { \"long_message\" : \"Bla bla bla\" , \"short_message\" : \"Bla\" }, \"en\" : { \"long_message\" : \"Yadi yadi yada\" , \"short_message\" : \"Yada\" } } } } } Note: the flag_infra_maintenance will always be set to true with this endpoint.", "title": "Request"}, {"location": "cozy-stack/admin/#response_21", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/admin/#delete-konnectorsmaintenanceslug", "text": "", "title": "DELETE /konnectors/maintenance/:slug"}, {"location": "cozy-stack/admin/#request_23", "text": "DELETE /konnectors/maintenance/ameli HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_22", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/admin/#oidc", "text": "", "title": "OIDC"}, {"location": "cozy-stack/admin/#post-oidccontextprovidercode", "text": "This endpoint is used by the cloudery to create a delegated code, which will be then used by the flagship app to obtain its access_token and refresh_token. The :provider parameter can be generic or franceconnect . The cloudery sends its access_token for the OIDC provider, the stack can use it to make a request to the userinfo endpoint of the OIDC provider. With the response, the stack can create a delegated code associated to the sub. POST /oidc/dev/franceconnect/code HTTP / 1.1 Accept : application/json Content-Type : application/json Authorization : Bearer ZmE2ZTFmN { \"access_token\" : \"ZmE2ZTFmN\" } HTTP / 1.1 200 OK Content-Type : application/json { \"delegated_code\" : \"wMTNiLTNmZWItMThY\" , \"sub\" : \"DIzYWE2MjA\" , \"email\" : \"jerome@example.org\" }", "title": "POST /oidc/:context/:provider/code"}, {"location": "cozy-stack/admin/#oauth-clients", "text": "", "title": "OAuth clients"}, {"location": "cozy-stack/admin/#delete-oauthdomainclients", "text": "Delete all the OAuth clients for the given instance. It can be limited to a specific kind of clients ( desktop , mobile , sharing , etc.) by using the Kind parameter of the query-string. It returns the number of clients that have been deleted.", "title": "DELETE /oauth/:domain/clients"}, {"location": "cozy-stack/admin/#request_24", "text": "DELETE /oauth/cozy.example/clients HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_23", "text": "HTTP / 1.1 200 OK { \"count\" : 42 }", "title": "Response"}, {"location": "cozy-stack/admin/#swift", "text": "", "title": "Swift"}, {"location": "cozy-stack/admin/#get-swiftlayouts", "text": "Count swift layouts by type", "title": "GET /swift/layouts"}, {"location": "cozy-stack/admin/#request_25", "text": "GET /swift/layouts HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_24", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"total\" : 3 , \"unknown\" : { \"counter\" : 0 }, \"v1\" : { \"counter\" : 1 }, \"v2a\" : { \"counter\" : 0 }, \"v2b\" : { \"counter\" : 0 }, \"v3a\" : { \"counter\" : 2 }, \"v3b\" : { \"counter\" : 4 } } The show_domains=true query parameter provides the domain names if needed", "title": "Response"}, {"location": "cozy-stack/admin/#request_26", "text": "GET /swift/layouts?show_domains=true HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_25", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"total\" : 3 , \"unknown\" : { \"counter\" : 0 }, \"v1\" : { \"counter\" : 1 , \"domains\" : [ \"bob.cozy.localhost:8081\" ] }, \"v2a\" : { \"counter\" : 0 }, \"v2b\" : { \"counter\" : 0 }, \"v3a\" : { \"counter\" : 2 , \"domains\" : [ \"alice.cozy.localhost:8081\" , \"ru.cozy.localhost:8081\" ] }, \"v3b\" : { \"counter\" : 4 , \"domains\" : [ \"foo.cozy.localhost:8081\" , \"bar.cozy.localhost:8081\" , \"baz.cozy.localhost:8081\" , \"foobar.cozy.localhost:8081\" ] } }", "title": "Response"}, {"location": "cozy-stack/admin/#get-swiftvfsobject", "text": "Retrieves a Swift object", "title": "GET /swift/vfs/:object"}, {"location": "cozy-stack/admin/#request_27", "text": "GET /swift/vfs/67a88b22520680b1fae840%2F9a8a0%2F18d02%2FiYbkfuCDEMaVoIXg HTTP / 1.1 Host : alice.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/admin/#response_26", "text": "HTTP / 1.1 200 OK Content-Type : text/plain \"foobar\"", "title": "Response"}, {"location": "cozy-stack/admin/#put-swiftvfsobject", "text": "Put an object in Swift", "title": "PUT /swift/vfs/:object"}, {"location": "cozy-stack/admin/#request_28", "text": "PUT /swift/vfs/67a88b22520680b1fae840%2F9a8a0%2F18d02%2FiYbkfuCDEMaVoIXg HTTP / 1.1 Host : alice.cozy.localhost Content-Type : text/plain \"this is my content\"", "title": "Request"}, {"location": "cozy-stack/admin/#delete-swiftvfsobject", "text": "Removes an object from Swift", "title": "DELETE /swift/vfs/:object"}, {"location": "cozy-stack/admin/#request_29", "text": "DELETE /swift/vfs/67a88b22520680b1fae840%2F9a8a0%2F18d02%2FiYbkfuCDEMaVoIXg HTTP / 1.1 Host : alice.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/admin/#get-swiftvfs", "text": "List Swift objects of an instance", "title": "GET /swift/vfs"}, {"location": "cozy-stack/admin/#request_30", "text": "GET /swift/vfs HTTP / 1.1 Host : alice.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/admin/#response_27", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"objects_names\" : [ \"67a88b22520680b1fae840/9a8a0/17264/AxfGhAiWVRhPufKK\" , \"67a88b22520680b1fae840/9a8a0/18d02/iYbkfuCDEMaVoIXg\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-large\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-medium\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-small\" , \"thumbs/67a88b22520680b1fae840/9a8a0/17264-tiny\" ] }", "title": "Response"}, {"location": "cozy-stack/admin/#tools", "text": "", "title": "Tools"}, {"location": "cozy-stack/admin/#get-toolspprofheap", "text": "Return a sampling of memory allocations as pprof format.", "title": "GET /tools/pprof/heap"}, {"location": "cozy-stack/admin/#request_31", "text": "GET /tools/pprof/heap HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/admin/#response_28", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/apps/", "text": "Table of contents Applications \u00b6 It\u2019s possible to manage serverless applications from the cozy stack and serve them via cozy stack. The stack does the routing and serve the HTML and the assets for the applications. The assets of the applications are installed in the virtual file system. Install an application \u00b6 The manifest \u00b6 To install an application, cozy needs a manifest. It\u2019s a JSON document that describes the application (its name and icon for example), how to install it and what it needs for its usage (the permissions in particular). While we have considered to use the same manifest format as the W3C for PWAs , it didn\u2019t match our expectations. The manifest format for FirefoxOS is a better fit. We took a lot of inspirations from it, starting with the filename for this file: manifest.webapp . Field Description name the name to display on the home name_prefix the prefix to display with the name slug the default slug (it can be changed at install time) editor the editor\u2019s name to display on the cozy-bar of the app icon an icon for the home screenshots an array of path to the screenshots of the application category the category of the application short_description a short description of the application long_description a long description of the application source where the files of the app can be downloaded developer name and url for the developer locales translations of the name and description fields in other locales langs list of languages tags supported by the application version the current version number license the SPDX license identifier platforms a list of type , url values for derivate of the application for other devices intents a list of intents provided by this app (see here for more details) permissions a map of permissions needed by the app (see here for more details) notifications a map of notifications needed by the app (see here for more details) services a map of the services associated with the app (see below for more details) routes a map of routes for the app (see below for more details) mobile information about app\u2019s mobile version (see below for more details) accept_from_flagship boolean stating if the app is compatible with the Flagship app\u2019s \u201cOS Receive\u201d feature accept_documents_from_flagship when accept_from_flagship is true , defines what can be uploaded to the app (see here for more details) Routes \u00b6 A route make the mapping between the requested paths and the files. It can have an index, which is an HTML file, with a token injected on it that identify the application. This token must be used with the user cookies to use the services of the cozy-stack (except in the cases of a shared by link page). By default, a route can be only visited by the authenticated owner of the instance where the app is installed. But a route can be marked as public. In that case, anybody can visit the route. For example, an application can offer an administration interface on /admin , a public page on /public , and shared assets in /assets : { \"/admin\" : { \"folder\" : \"/\" , \"index\" : \"admin.html\" , \"public\" : false }, \"/public\" : { \"folder\" : \"/public\" , \"index\" : \"index.html\" , \"public\" : true }, \"/assets\" : { \"folder\" : \"/public-assets\" , \"public\" : true } } If an application has no routes in its manifest, the stack will create one route, this default one: { \"/\" : { \"folder\" : \"/\" , \"index\" : \"index.html\" , \"public\" : false } } Note : if you have a public route, it\u2019s probably better to put the app icon in it. So, the cozy-bar can display it for the users that go on the public part of the app. When the stack receives a request, it chooses the more specific route that matches, then it looks inside the associated folder to find the file, and send it. If the route is an exact match, the file will be the index, and it will be interpreted as a template, cf the list of variables . For example, with the previous routes, a request to /admin will use the file /admin.html as a template for the response. And a request to /assets/css/theme.css will use the file /public-assets/css/theme.css . Services \u00b6 Application may require background and offline process to analyse the user\u2019s data and emit some notification or warning even without the user being on the application. These part of the application are called services and can be declared as part of the application in its manifest. In contrast to konnectors , services have the same permissions as the web application and are not intended to collect outside informations but rather analyse the current set of collected information inside the cozy. However they share the same mechanisms as the konnectors to describe how and when they should be executed: via our trigger system. To define a service, first the code needs to be stored with the application content, as single (packaged) javascript files. In the manifest, declare the service and its parameters following this example: { \"services\" : { \"low-budget-notification\" : { \"type\" : \"node\" , \"file\" : \"/services/low-budget-notification.js\" , \"trigger\" : \"@cron 0 0 0 * * *\" } // ... } } The trigger field should follow the available triggers described in the jobs documentation . The file field should specify the service code run and the type field describe the code type (only \"node\" for now). If you need to know more about how to develop a service, please check the how-to documentation here . Note: it is possible to declare a service with no trigger. For example, this can be used when the service is programmatically called from another service. Available fields to the service \u00b6 During the service execution, the stack will give some environment variables to the service if you need to use them, available with process.env[FIELD] . Once again, it\u2019s the stack that gives those variables. So if you\u2019re developing a service and using a script to execute/test your service, you won\u2019t get those variables. - \"COZY_URL\" # Cozy URL - \"COZY_CREDENTIALS\" # The cozy app related token - \"COZY_LANGUAGE\" # Lang used for the service (ex: node) - \"COZY_LOCALE\" # Locale of the Cozy - \"COZY_TIME_LIMIT\" # Maximum execution time. After this, the job will be killed - \"COZY_JOB_ID\" # Job ID - \"COZY_COUCH_DOC\" # The CouchDB document which triggers the service Notifications \u00b6 For more informations on how te declare notifications in the manifest, see the notifications documentation . Here is an example: { \"notifications\" : { \"account-balance\" : { \"description\" : \"Alert the user when its account balance is negative\" , \"collapsible\" : true , // only interested in the last value of the notification \"multiple\" : true , // require sub-categories for each account \"stateful\" : false , \"default_priority\" : \"high\" , // high priority for this notification \"templates\" : { \"mail\" : \"file:./notifications/account-balance-mail.tpl\" } } } } Mobile \u00b6 Application may exist on mobile platforms. When it is the case, manifest can contain informations about the mobile apps. On a mobile device and on a native context, this attribute can be used to open the native mobile app from any another Cozy app. Following attributes should be set: - schema : the app\u2019s scheme that can be used to open it - id_playstore : the app\u2019s ID on the Google PlayStore - id_appstore : the app\u2019s ID on the Apple AppStore Example of mobile attribute for Cozy Pass: \"mobile\" : { \"schema\" : \"cozypass://\" , \"id_playstore\" : \"io.cozy.pass\" , \"id_appstore\" : \"cozy-pass/id1502262449\" } Resource caching \u00b6 To help caching of applications assets, we detect the presence of a unique identifier in the name of assets: a unique identifier is matched when the file base name contains a long hexadecimal subpart between \u2018.\u2019, of at least 10 characters. For instance app.badf00dbadf00d.js or icon.badbeefbadbeef.1.png . With such a unique identifier, the asset is considered immutable, and a long cache-control is added on corresponding HTTP responses. We recommend the use of bundling tools like webpack which offer the possibility to add such identifier on the building step of the application packages for all assets. Sources \u00b6 Here is the available sources, defined by the scheme of the source URL: registry:// : to install an application from the instance registries git:// , git+ssh:// , or git+https:// : to install an application from a git repository http:// or https:// : to install an application from an http server (via a tarball) file:// : to install an application from a local directory (for instance: file:///home/user/code/cozy-app ) The registry scheme expect the following elements: scheme: registry host: the name of the application path: /:channel the channel of the application (see the registry doc) Examples: registry://drive/stable , registry://drive/beta , and registry://drive/dev . For the git scheme, the fragment in the URL can be used to specify which branch to install. For the http and https schemes, the fragment can be used to give the expected sha256sum. POST /apps/:slug \u00b6 Install an application, ie download the files and put them in /apps/:slug in the virtual file system of the user, create an io.cozy.apps document, register the permissions, etc. This endpoint is asynchronous and returns a successful return as soon as the application installation has started, meaning we have successfully reached the manifest and started to fetch application data. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the application has been installed or failed. Status codes \u00b6 202 Accepted, when the application installation has been accepted. 400 Bad-Request, when the manifest of the application could not be processed (for instance, it is not valid JSON). 404 Not Found, when the manifest or the source of the application is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url) Query-String \u00b6 Parameter Description Source URL from where the app can be downloaded (only for install) The Source parameter is optional: by default, the stable channel of the registry will be used. Request \u00b6 POST /apps/emails?Source=git://github.com/cozy/cozy-emails.git HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"installing\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" } }] } Note : it\u2019s possible to choose a git branch by passing it in the fragment like this: POST /apps/emails-dev?Source=git://github.com/cozy/cozy-emails.git%23dev HTTP / 1.1 PUT /apps/:slug \u00b6 Update an application with the specified slug name. This endpoint is asynchronous and returns a successful return as soon as the application installation has started, meaning we have successfully reached the manifest and started to fetch application data. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the application has been updated or failed. Request \u00b6 PUT /apps/emails HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"installing\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" } }] } Status codes \u00b6 202 Accepted, when the application installation has been accepted. 400 Bad-Request, when the manifest of the application could not be processed (for instance, it is not valid JSON). 404 Not Found, when the application with the specified slug was not found or when the manifest or the source of the application is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url) Advanced usage \u00b6 Two optional query parameters are available for an app update: PermissionsAcked : (defaults to false ) Tells that the user accepted the permissions/ToS. It is useful if there are newer permissions or Terms Of Service and you want to be sure they were read or accepted. If set to false , the update will be blocked and the user will be told that a new app version is available. Note: PermissionsAcked can be skipped. If an instance is in a context configured with the parameter permissions_skip_verification sets to true , permissions verification will be ignored. Source (defaults to SourceURL installation parameter): Use a different source to update this app (e.g. to install a beta or dev app version) Examples: \u00b6 You have an email application on a stable channel, and you want to update it to a particular beta version: PUT /apps/emails?Source=registry://drive/1.0.0-beta HTTP / 1.1 Accept : application/vnd.api+json You want to attempt the email app update, but prevent it if new permissions were added PUT /apps/emails?PermissionsAcked=false HTTP / 1.1 Accept : application/vnd.api+json You can combine these parameters to use a precise app version and stay on another channel (when permissions are different): Install a version (e.g. 1.0.0 ) Ask an update to stable channel with PermissionsAcked to false Source will be stable , and your version remains 1.0.0 List installed applications \u00b6 GET /apps/ \u00b6 An application can be in one of these states: installed , the application is installed but still require some user interaction to accept its permissions ready , the user can use it installing , the installation is running and the app will soon be usable upgrading , a new version is being installed errored , the app is in an error state and can not be used. Request \u00b6 GET /apps/ HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"2-bbfb0fc32dfcdb5333b28934f195b96a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"ready\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" , \"icon\" : \"/apps/calendar/icon\" , \"related\" : \"https://calendar.alice.example.com/\" } }], \"links\" : {}, \"meta\" : { \"count\" : 1 } } This endpoint is paginated, default limit is currently 100 . Two flags are available to retreieve the other apps if there are more than 100 apps installed: - limit - start_key : The first following doc ID of the next apps The links object contains a \u01f9ext generated-link for the next docs. Request \u00b6 GET /apps/?limit=50 HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"2-bbfb0fc32dfcdb5333b28934f195b96a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"ready\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" , \"icon\" : \"/apps/calendar/icon\" , \"related\" : \"https://calendar.alice.example.com/\" } }, { ... }], \"links\" : { \"next\" : \"http://alice.example.com/apps/?limit=50&start_key=io.cozy.apps%2Fhome\" }, \"meta\" : { \"count\" : 50 } } Get informations about an application \u00b6 GET /apps/:slug \u00b6 This route is used to retrieve informations about an application installed on the cozy. By calling this route, the application will be updated synchronously. Request \u00b6 GET /apps/calendar HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"2-bbfb0fc32dfcdb5333b28934f195b96a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"ready\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" , \"icon\" : \"/apps/calendar/icon\" , \"related\" : \"https://calendar.alice.example.com/\" } } } Get the icon of an application \u00b6 GET /apps/:slug/icon \u00b6 Request \u00b6 GET /apps/calendar/icon HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : image/svg+xml Calendar Download the code of an app \u00b6 This endpoint is used by the flagship app to download the code of an application, in order to use it even while offline. GET /apps/:slug/download & GET /apps/:slug/download/:version \u00b6 The first route will download a tarball of the source code of the latest installed version of the application. The second route will force a specific version of an app (and a 412 Precondition failed may be sent if the code of this specific version is not available). Request \u00b6 GET /apps/drive/download/3.0.1 HTTP / 1.1 Authorization : Bearer flagship-token Host : cozy.example.net Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/gzip When the application has been installed from the registry, the stack will respond with a redirect to the registry. In that case, the downloaded tarball can be gzipped or not (the registry allows both). When the application is installed from another source, the stack will create a gzipped tarball and send it to the client. Open an application inside the flagship app \u00b6 This endpoint can be used by the flagship app to get all the parameters needed to open a webview for a Cozy webapp. It includes a cookie for a session, and the values for filling the HTML template. GET /apps/:slug/open \u00b6 Request \u00b6 GET /apps/drive/open HTTP / 1.1 Accept : application/vnd.api+json Authorization : Bearer flagship-token Host : cozy.example.net Note: it is possible to send a cookie in HTTP headers to use the corresponding session when opening the webapp. Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"da903430-af6e-013a-8b14-18c04daba326\" , \"type\" : \"io.cozy.apps.open\" , \"attributes\" : { \"Cookie\" : \"sess-cozyfa713dc4b104110f181959012ef2e0c5=AAAAAGJ1GI8zZDZlNTJhZTgxNThhY2VlMjhhMjE1NTY3ZTA1OTYyOCZ9ShFEsLD-2cb9bUdvYSg91XRw919a5oK1VxfshaZB; Path=/; Domain=example.net; HttpOnly; Secure; SameSite=Lax\" , \"AppEditor\" : \"Cozy\" , \"AppName\" : \"Drive\" , \"AppSlug\" : \"drive\" , \"Capabilities\" : \"{ \\\"file_versioning\\\": true }\" , \"CozyBar\" : \"...\" , \"CozyClientJS\" : \"...\" , \"CozyFonts\" : \"...\" , \"DefaultWallpaper\" : \"...\" , \"Domain\" : \"cozy.example.net\" , \"Favicon\" : \"...\" , \"Flags\" : \"{}\" , \"IconPath\" : \"icon.svg\" , \"Locale\" : \"en\" , \"SubDomain\" : \"flat\" , \"ThemeCSS\" : \"...\" , \"Token\" : \"eyJhb...Y4KdA\" , \"Tracking\" : \"false\" }, \"links\" : { \"self\" : \"/apps/drive/open\" } } } Uninstall an application \u00b6 DELETE /apps/:slug \u00b6 Request \u00b6 DELETE /apps/tasky HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 No Content Send application logs to cozy-stack \u00b6 POST /apps/:slug/logs \u00b6 Send client-side logs to cozy-stack so they can be stored in the server\u2019s logging system. The job identifier must be sent in the job_id parameter of the query string. The version of the application can be sent in the version parameter. Status codes \u00b6 204 No Content, when all the log lines have been processed. 400 Bad-Request, when the JSON body is invalid. 404 Not Found, when no apps with the given slug could be found. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or log level does not exist) Request \u00b6 POST /apps/emails/logs?job_id=1c6ff5a07eb7013bf7e0-18c04daba326 HTTP / 1.1 Accept : application/vnd.api+json [ { \"timestamp\" : \"2022-10-27T17:13:37.293Z\" , \"level\" : \"info\" , \"msg\" : \"Fetching e-mail data...\" }, { \"timestamp\" : \"2022-10-27T17:13:38.382Z\" , \"level\" : \"error\" , \"msg\" : \"Could not find requested e-mail\" } ] Response \u00b6 HTTP / 1.1 204 No Content Access an application \u00b6 Each application will run on its sub-domain. The sub-domain is the slug used when installing the application ( calendar.cozy.example.org if it was installed via a POST on /apps/calendar). On the main domain ( cozy.example.org ), there will be the registration process, the login form, and it will redirect to home.cozy.example.org for logged-in users. Rationale \u00b6 The applications have different roles and permissions. An application is identified when talking to the stack via a token. The token has to be injected in the application, one way or another, and it have to be unaccessible from other apps. If the applications run on the same domain (for example https://cozy.example.org/apps/calendar ), it\u2019s nearly impossible to protect an application to take the token of another application. The security model of the web is based too heavily on Same Origin Policy for that. If the token is put in the html of the index.html page of an app, another app can use the fetch API to get the html page, parse its content and extract the token. We can think of other ways to inject the token (indexeddb, URL, cookies) but none will provide a better isolation. Maybe in a couple years, when the origin spec will be more advanced. So, if having the apps on the same origin is not possible, we have to put them on several origins. One interesting way to do that is using sandboxed iframes. An iframe with the sandbox attribute , and not allow-same-origin in it, will be assigned to a unique origin. The W3C warns: Potentially hostile files should not be served from the same server as the file containing the iframe element. Sandboxing hostile content is of minimal help if an attacker can convince the user to just visit the hostile content directly, rather than in the iframe. To limit the damage that can be caused by hostile HTML content, it should be served from a separate dedicated domain. Using a different domain ensures that scripts in the files are unable to attack the site, even if the user is tricked into visiting those pages directly, without the protection of the sandbox attribute. It may be possible to disable all html pages to have an html content-type, except the home, and having the home loading the apps in a sandboxed iframe, via the srcdoc attribute. But, it will mean that we will have to reinvent nearly everything. Even showing an image can no longer be done via an tag, it will need to use post-message with the home. Such a solution is difficult to implement, is a very fragile (both for the apps developer than for security) and is an hell to debug when it breaks. Clearly, it\u2019s not an acceptable solution. Thus, the only choice is to have several origins, and sub-domains is the best way for that. Of course, it has the downside to be more complicated to deploy (DNS and TLS certificates). But, in the tradeoff between security and ease of administration, we definetively take the security first. Routes \u00b6 Should we be concerned that all the routes are on the same sub-domain? No, it\u2019s not an issue. There are two types of routes: the ones that are publics and those reserved to the authenticated user. Public routes have no token Private routes are private, they can be accessed only with a valid session cookie, ie by the owner of the instance. Another application can\u2019t use the user cookies to read the token, because of the restrictions of the same origin policy (they are on different domains). And the application can\u2019t use an open proxy to read the private route, because it doesn\u2019t have the user cookies for that (the cookie is marked as httpOnly ).", "title": "/apps - Applications Management"}, {"location": "cozy-stack/apps/#applications", "text": "It\u2019s possible to manage serverless applications from the cozy stack and serve them via cozy stack. The stack does the routing and serve the HTML and the assets for the applications. The assets of the applications are installed in the virtual file system.", "title": "Applications"}, {"location": "cozy-stack/apps/#install-an-application", "text": "", "title": "Install an application"}, {"location": "cozy-stack/apps/#the-manifest", "text": "To install an application, cozy needs a manifest. It\u2019s a JSON document that describes the application (its name and icon for example), how to install it and what it needs for its usage (the permissions in particular). While we have considered to use the same manifest format as the W3C for PWAs , it didn\u2019t match our expectations. The manifest format for FirefoxOS is a better fit. We took a lot of inspirations from it, starting with the filename for this file: manifest.webapp . Field Description name the name to display on the home name_prefix the prefix to display with the name slug the default slug (it can be changed at install time) editor the editor\u2019s name to display on the cozy-bar of the app icon an icon for the home screenshots an array of path to the screenshots of the application category the category of the application short_description a short description of the application long_description a long description of the application source where the files of the app can be downloaded developer name and url for the developer locales translations of the name and description fields in other locales langs list of languages tags supported by the application version the current version number license the SPDX license identifier platforms a list of type , url values for derivate of the application for other devices intents a list of intents provided by this app (see here for more details) permissions a map of permissions needed by the app (see here for more details) notifications a map of notifications needed by the app (see here for more details) services a map of the services associated with the app (see below for more details) routes a map of routes for the app (see below for more details) mobile information about app\u2019s mobile version (see below for more details) accept_from_flagship boolean stating if the app is compatible with the Flagship app\u2019s \u201cOS Receive\u201d feature accept_documents_from_flagship when accept_from_flagship is true , defines what can be uploaded to the app (see here for more details)", "title": "The manifest"}, {"location": "cozy-stack/apps/#routes", "text": "A route make the mapping between the requested paths and the files. It can have an index, which is an HTML file, with a token injected on it that identify the application. This token must be used with the user cookies to use the services of the cozy-stack (except in the cases of a shared by link page). By default, a route can be only visited by the authenticated owner of the instance where the app is installed. But a route can be marked as public. In that case, anybody can visit the route. For example, an application can offer an administration interface on /admin , a public page on /public , and shared assets in /assets : { \"/admin\" : { \"folder\" : \"/\" , \"index\" : \"admin.html\" , \"public\" : false }, \"/public\" : { \"folder\" : \"/public\" , \"index\" : \"index.html\" , \"public\" : true }, \"/assets\" : { \"folder\" : \"/public-assets\" , \"public\" : true } } If an application has no routes in its manifest, the stack will create one route, this default one: { \"/\" : { \"folder\" : \"/\" , \"index\" : \"index.html\" , \"public\" : false } } Note : if you have a public route, it\u2019s probably better to put the app icon in it. So, the cozy-bar can display it for the users that go on the public part of the app. When the stack receives a request, it chooses the more specific route that matches, then it looks inside the associated folder to find the file, and send it. If the route is an exact match, the file will be the index, and it will be interpreted as a template, cf the list of variables . For example, with the previous routes, a request to /admin will use the file /admin.html as a template for the response. And a request to /assets/css/theme.css will use the file /public-assets/css/theme.css .", "title": "Routes"}, {"location": "cozy-stack/apps/#services", "text": "Application may require background and offline process to analyse the user\u2019s data and emit some notification or warning even without the user being on the application. These part of the application are called services and can be declared as part of the application in its manifest. In contrast to konnectors , services have the same permissions as the web application and are not intended to collect outside informations but rather analyse the current set of collected information inside the cozy. However they share the same mechanisms as the konnectors to describe how and when they should be executed: via our trigger system. To define a service, first the code needs to be stored with the application content, as single (packaged) javascript files. In the manifest, declare the service and its parameters following this example: { \"services\" : { \"low-budget-notification\" : { \"type\" : \"node\" , \"file\" : \"/services/low-budget-notification.js\" , \"trigger\" : \"@cron 0 0 0 * * *\" } // ... } } The trigger field should follow the available triggers described in the jobs documentation . The file field should specify the service code run and the type field describe the code type (only \"node\" for now). If you need to know more about how to develop a service, please check the how-to documentation here . Note: it is possible to declare a service with no trigger. For example, this can be used when the service is programmatically called from another service.", "title": "Services"}, {"location": "cozy-stack/apps/#available-fields-to-the-service", "text": "During the service execution, the stack will give some environment variables to the service if you need to use them, available with process.env[FIELD] . Once again, it\u2019s the stack that gives those variables. So if you\u2019re developing a service and using a script to execute/test your service, you won\u2019t get those variables. - \"COZY_URL\" # Cozy URL - \"COZY_CREDENTIALS\" # The cozy app related token - \"COZY_LANGUAGE\" # Lang used for the service (ex: node) - \"COZY_LOCALE\" # Locale of the Cozy - \"COZY_TIME_LIMIT\" # Maximum execution time. After this, the job will be killed - \"COZY_JOB_ID\" # Job ID - \"COZY_COUCH_DOC\" # The CouchDB document which triggers the service", "title": "Available fields to the service"}, {"location": "cozy-stack/apps/#notifications", "text": "For more informations on how te declare notifications in the manifest, see the notifications documentation . Here is an example: { \"notifications\" : { \"account-balance\" : { \"description\" : \"Alert the user when its account balance is negative\" , \"collapsible\" : true , // only interested in the last value of the notification \"multiple\" : true , // require sub-categories for each account \"stateful\" : false , \"default_priority\" : \"high\" , // high priority for this notification \"templates\" : { \"mail\" : \"file:./notifications/account-balance-mail.tpl\" } } } }", "title": "Notifications"}, {"location": "cozy-stack/apps/#mobile", "text": "Application may exist on mobile platforms. When it is the case, manifest can contain informations about the mobile apps. On a mobile device and on a native context, this attribute can be used to open the native mobile app from any another Cozy app. Following attributes should be set: - schema : the app\u2019s scheme that can be used to open it - id_playstore : the app\u2019s ID on the Google PlayStore - id_appstore : the app\u2019s ID on the Apple AppStore Example of mobile attribute for Cozy Pass: \"mobile\" : { \"schema\" : \"cozypass://\" , \"id_playstore\" : \"io.cozy.pass\" , \"id_appstore\" : \"cozy-pass/id1502262449\" }", "title": "Mobile"}, {"location": "cozy-stack/apps/#resource-caching", "text": "To help caching of applications assets, we detect the presence of a unique identifier in the name of assets: a unique identifier is matched when the file base name contains a long hexadecimal subpart between \u2018.\u2019, of at least 10 characters. For instance app.badf00dbadf00d.js or icon.badbeefbadbeef.1.png . With such a unique identifier, the asset is considered immutable, and a long cache-control is added on corresponding HTTP responses. We recommend the use of bundling tools like webpack which offer the possibility to add such identifier on the building step of the application packages for all assets.", "title": "Resource caching"}, {"location": "cozy-stack/apps/#sources", "text": "Here is the available sources, defined by the scheme of the source URL: registry:// : to install an application from the instance registries git:// , git+ssh:// , or git+https:// : to install an application from a git repository http:// or https:// : to install an application from an http server (via a tarball) file:// : to install an application from a local directory (for instance: file:///home/user/code/cozy-app ) The registry scheme expect the following elements: scheme: registry host: the name of the application path: /:channel the channel of the application (see the registry doc) Examples: registry://drive/stable , registry://drive/beta , and registry://drive/dev . For the git scheme, the fragment in the URL can be used to specify which branch to install. For the http and https schemes, the fragment can be used to give the expected sha256sum.", "title": "Sources"}, {"location": "cozy-stack/apps/#post-appsslug", "text": "Install an application, ie download the files and put them in /apps/:slug in the virtual file system of the user, create an io.cozy.apps document, register the permissions, etc. This endpoint is asynchronous and returns a successful return as soon as the application installation has started, meaning we have successfully reached the manifest and started to fetch application data. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the application has been installed or failed.", "title": "POST /apps/:slug"}, {"location": "cozy-stack/apps/#status-codes", "text": "202 Accepted, when the application installation has been accepted. 400 Bad-Request, when the manifest of the application could not be processed (for instance, it is not valid JSON). 404 Not Found, when the manifest or the source of the application is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url)", "title": "Status codes"}, {"location": "cozy-stack/apps/#query-string", "text": "Parameter Description Source URL from where the app can be downloaded (only for install) The Source parameter is optional: by default, the stable channel of the registry will be used.", "title": "Query-String"}, {"location": "cozy-stack/apps/#request", "text": "POST /apps/emails?Source=git://github.com/cozy/cozy-emails.git HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/apps/#response", "text": "HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"installing\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" } }] } Note : it\u2019s possible to choose a git branch by passing it in the fragment like this: POST /apps/emails-dev?Source=git://github.com/cozy/cozy-emails.git%23dev HTTP / 1.1", "title": "Response"}, {"location": "cozy-stack/apps/#put-appsslug", "text": "Update an application with the specified slug name. This endpoint is asynchronous and returns a successful return as soon as the application installation has started, meaning we have successfully reached the manifest and started to fetch application data. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the application has been updated or failed.", "title": "PUT /apps/:slug"}, {"location": "cozy-stack/apps/#request_1", "text": "PUT /apps/emails HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/apps/#response_1", "text": "HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"installing\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" } }] }", "title": "Response"}, {"location": "cozy-stack/apps/#status-codes_1", "text": "202 Accepted, when the application installation has been accepted. 400 Bad-Request, when the manifest of the application could not be processed (for instance, it is not valid JSON). 404 Not Found, when the application with the specified slug was not found or when the manifest or the source of the application is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url)", "title": "Status codes"}, {"location": "cozy-stack/apps/#advanced-usage", "text": "Two optional query parameters are available for an app update: PermissionsAcked : (defaults to false ) Tells that the user accepted the permissions/ToS. It is useful if there are newer permissions or Terms Of Service and you want to be sure they were read or accepted. If set to false , the update will be blocked and the user will be told that a new app version is available. Note: PermissionsAcked can be skipped. If an instance is in a context configured with the parameter permissions_skip_verification sets to true , permissions verification will be ignored. Source (defaults to SourceURL installation parameter): Use a different source to update this app (e.g. to install a beta or dev app version)", "title": "Advanced usage"}, {"location": "cozy-stack/apps/#examples", "text": "You have an email application on a stable channel, and you want to update it to a particular beta version: PUT /apps/emails?Source=registry://drive/1.0.0-beta HTTP / 1.1 Accept : application/vnd.api+json You want to attempt the email app update, but prevent it if new permissions were added PUT /apps/emails?PermissionsAcked=false HTTP / 1.1 Accept : application/vnd.api+json You can combine these parameters to use a precise app version and stay on another channel (when permissions are different): Install a version (e.g. 1.0.0 ) Ask an update to stable channel with PermissionsAcked to false Source will be stable , and your version remains 1.0.0", "title": "Examples:"}, {"location": "cozy-stack/apps/#list-installed-applications", "text": "", "title": "List installed applications"}, {"location": "cozy-stack/apps/#get-apps", "text": "An application can be in one of these states: installed , the application is installed but still require some user interaction to accept its permissions ready , the user can use it installing , the installation is running and the app will soon be usable upgrading , a new version is being installed errored , the app is in an error state and can not be used.", "title": "GET /apps/"}, {"location": "cozy-stack/apps/#request_2", "text": "GET /apps/ HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/apps/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"2-bbfb0fc32dfcdb5333b28934f195b96a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"ready\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" , \"icon\" : \"/apps/calendar/icon\" , \"related\" : \"https://calendar.alice.example.com/\" } }], \"links\" : {}, \"meta\" : { \"count\" : 1 } } This endpoint is paginated, default limit is currently 100 . Two flags are available to retreieve the other apps if there are more than 100 apps installed: - limit - start_key : The first following doc ID of the next apps The links object contains a \u01f9ext generated-link for the next docs.", "title": "Response"}, {"location": "cozy-stack/apps/#request_3", "text": "GET /apps/?limit=50 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/apps/#response_3", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"2-bbfb0fc32dfcdb5333b28934f195b96a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"ready\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" , \"icon\" : \"/apps/calendar/icon\" , \"related\" : \"https://calendar.alice.example.com/\" } }, { ... }], \"links\" : { \"next\" : \"http://alice.example.com/apps/?limit=50&start_key=io.cozy.apps%2Fhome\" }, \"meta\" : { \"count\" : 50 } }", "title": "Response"}, {"location": "cozy-stack/apps/#get-informations-about-an-application", "text": "", "title": "Get informations about an application"}, {"location": "cozy-stack/apps/#get-appsslug", "text": "This route is used to retrieve informations about an application installed on the cozy. By calling this route, the application will be updated synchronously.", "title": "GET /apps/:slug"}, {"location": "cozy-stack/apps/#request_4", "text": "GET /apps/calendar HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/apps/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.apps\" , \"meta\" : { \"rev\" : \"2-bbfb0fc32dfcdb5333b28934f195b96a\" }, \"attributes\" : { \"name\" : \"calendar\" , \"state\" : \"ready\" , \"slug\" : \"calendar\" , ... }, \"links\" : { \"self\" : \"/apps/calendar\" , \"icon\" : \"/apps/calendar/icon\" , \"related\" : \"https://calendar.alice.example.com/\" } } }", "title": "Response"}, {"location": "cozy-stack/apps/#get-the-icon-of-an-application", "text": "", "title": "Get the icon of an application"}, {"location": "cozy-stack/apps/#get-appsslugicon", "text": "", "title": "GET /apps/:slug/icon"}, {"location": "cozy-stack/apps/#request_5", "text": "GET /apps/calendar/icon HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/apps/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : image/svg+xml Calendar ", "title": "Response"}, {"location": "cozy-stack/apps/#download-the-code-of-an-app", "text": "This endpoint is used by the flagship app to download the code of an application, in order to use it even while offline.", "title": "Download the code of an app"}, {"location": "cozy-stack/apps/#get-appsslugdownload-get-appsslugdownloadversion", "text": "The first route will download a tarball of the source code of the latest installed version of the application. The second route will force a specific version of an app (and a 412 Precondition failed may be sent if the code of this specific version is not available).", "title": "GET /apps/:slug/download & GET /apps/:slug/download/:version"}, {"location": "cozy-stack/apps/#request_6", "text": "GET /apps/drive/download/3.0.1 HTTP / 1.1 Authorization : Bearer flagship-token Host : cozy.example.net", "title": "Request"}, {"location": "cozy-stack/apps/#response_6", "text": "HTTP / 1.1 200 OK Content-Type : application/gzip When the application has been installed from the registry, the stack will respond with a redirect to the registry. In that case, the downloaded tarball can be gzipped or not (the registry allows both). When the application is installed from another source, the stack will create a gzipped tarball and send it to the client.", "title": "Response"}, {"location": "cozy-stack/apps/#open-an-application-inside-the-flagship-app", "text": "This endpoint can be used by the flagship app to get all the parameters needed to open a webview for a Cozy webapp. It includes a cookie for a session, and the values for filling the HTML template.", "title": "Open an application inside the flagship app"}, {"location": "cozy-stack/apps/#get-appsslugopen", "text": "", "title": "GET /apps/:slug/open"}, {"location": "cozy-stack/apps/#request_7", "text": "GET /apps/drive/open HTTP / 1.1 Accept : application/vnd.api+json Authorization : Bearer flagship-token Host : cozy.example.net Note: it is possible to send a cookie in HTTP headers to use the corresponding session when opening the webapp.", "title": "Request"}, {"location": "cozy-stack/apps/#response_7", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"da903430-af6e-013a-8b14-18c04daba326\" , \"type\" : \"io.cozy.apps.open\" , \"attributes\" : { \"Cookie\" : \"sess-cozyfa713dc4b104110f181959012ef2e0c5=AAAAAGJ1GI8zZDZlNTJhZTgxNThhY2VlMjhhMjE1NTY3ZTA1OTYyOCZ9ShFEsLD-2cb9bUdvYSg91XRw919a5oK1VxfshaZB; Path=/; Domain=example.net; HttpOnly; Secure; SameSite=Lax\" , \"AppEditor\" : \"Cozy\" , \"AppName\" : \"Drive\" , \"AppSlug\" : \"drive\" , \"Capabilities\" : \"{ \\\"file_versioning\\\": true }\" , \"CozyBar\" : \"...\" , \"CozyClientJS\" : \"...\" , \"CozyFonts\" : \"...\" , \"DefaultWallpaper\" : \"...\" , \"Domain\" : \"cozy.example.net\" , \"Favicon\" : \"...\" , \"Flags\" : \"{}\" , \"IconPath\" : \"icon.svg\" , \"Locale\" : \"en\" , \"SubDomain\" : \"flat\" , \"ThemeCSS\" : \"...\" , \"Token\" : \"eyJhb...Y4KdA\" , \"Tracking\" : \"false\" }, \"links\" : { \"self\" : \"/apps/drive/open\" } } }", "title": "Response"}, {"location": "cozy-stack/apps/#uninstall-an-application", "text": "", "title": "Uninstall an application"}, {"location": "cozy-stack/apps/#delete-appsslug", "text": "", "title": "DELETE /apps/:slug"}, {"location": "cozy-stack/apps/#request_8", "text": "DELETE /apps/tasky HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/apps/#response_8", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/apps/#send-application-logs-to-cozy-stack", "text": "", "title": "Send application logs to cozy-stack"}, {"location": "cozy-stack/apps/#post-appssluglogs", "text": "Send client-side logs to cozy-stack so they can be stored in the server\u2019s logging system. The job identifier must be sent in the job_id parameter of the query string. The version of the application can be sent in the version parameter.", "title": "POST /apps/:slug/logs"}, {"location": "cozy-stack/apps/#status-codes_2", "text": "204 No Content, when all the log lines have been processed. 400 Bad-Request, when the JSON body is invalid. 404 Not Found, when no apps with the given slug could be found. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or log level does not exist)", "title": "Status codes"}, {"location": "cozy-stack/apps/#request_9", "text": "POST /apps/emails/logs?job_id=1c6ff5a07eb7013bf7e0-18c04daba326 HTTP / 1.1 Accept : application/vnd.api+json [ { \"timestamp\" : \"2022-10-27T17:13:37.293Z\" , \"level\" : \"info\" , \"msg\" : \"Fetching e-mail data...\" }, { \"timestamp\" : \"2022-10-27T17:13:38.382Z\" , \"level\" : \"error\" , \"msg\" : \"Could not find requested e-mail\" } ]", "title": "Request"}, {"location": "cozy-stack/apps/#response_9", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/apps/#access-an-application", "text": "Each application will run on its sub-domain. The sub-domain is the slug used when installing the application ( calendar.cozy.example.org if it was installed via a POST on /apps/calendar). On the main domain ( cozy.example.org ), there will be the registration process, the login form, and it will redirect to home.cozy.example.org for logged-in users.", "title": "Access an application"}, {"location": "cozy-stack/apps/#rationale", "text": "The applications have different roles and permissions. An application is identified when talking to the stack via a token. The token has to be injected in the application, one way or another, and it have to be unaccessible from other apps. If the applications run on the same domain (for example https://cozy.example.org/apps/calendar ), it\u2019s nearly impossible to protect an application to take the token of another application. The security model of the web is based too heavily on Same Origin Policy for that. If the token is put in the html of the index.html page of an app, another app can use the fetch API to get the html page, parse its content and extract the token. We can think of other ways to inject the token (indexeddb, URL, cookies) but none will provide a better isolation. Maybe in a couple years, when the origin spec will be more advanced. So, if having the apps on the same origin is not possible, we have to put them on several origins. One interesting way to do that is using sandboxed iframes. An iframe with the sandbox attribute , and not allow-same-origin in it, will be assigned to a unique origin. The W3C warns: Potentially hostile files should not be served from the same server as the file containing the iframe element. Sandboxing hostile content is of minimal help if an attacker can convince the user to just visit the hostile content directly, rather than in the iframe. To limit the damage that can be caused by hostile HTML content, it should be served from a separate dedicated domain. Using a different domain ensures that scripts in the files are unable to attack the site, even if the user is tricked into visiting those pages directly, without the protection of the sandbox attribute. It may be possible to disable all html pages to have an html content-type, except the home, and having the home loading the apps in a sandboxed iframe, via the srcdoc attribute. But, it will mean that we will have to reinvent nearly everything. Even showing an image can no longer be done via an tag, it will need to use post-message with the home. Such a solution is difficult to implement, is a very fragile (both for the apps developer than for security) and is an hell to debug when it breaks. Clearly, it\u2019s not an acceptable solution. Thus, the only choice is to have several origins, and sub-domains is the best way for that. Of course, it has the downside to be more complicated to deploy (DNS and TLS certificates). But, in the tradeoff between security and ease of administration, we definetively take the security first.", "title": "Rationale"}, {"location": "cozy-stack/apps/#routes_1", "text": "Should we be concerned that all the routes are on the same sub-domain? No, it\u2019s not an issue. There are two types of routes: the ones that are publics and those reserved to the authenticated user. Public routes have no token Private routes are private, they can be accessed only with a valid session cookie, ie by the owner of the instance. Another application can\u2019t use the user cookies to read the token, because of the restrictions of the same origin policy (they are on different domains). And the application can\u2019t use an open proxy to read the private route, because it doesn\u2019t have the user cookies for that (the cookie is marked as httpOnly ).", "title": "Routes"}, {"location": "cozy-stack/assets/", "text": "Table of contents Working with the stack assets \u00b6 The cozy-stack has some assets: templates, CSS, JS, fonts, etc. For the deployment in production, they are bundler in the go code and compiled to the binary. But, it\u2019s also nice for developers to have them in a readable format with a git history: they are also put in the assets directory, and some of them are downloaded from other repositories and listed in assets/.externals . How to work on them on local? \u00b6 In short: $ scripts/build.sh debug-assets $ go run . serve --assets debug-assets/ The first command creates a debug-assets directory, with symlinks for local assets. It also downloads the external assets. The second command starts the cozy-stack with those assets. If you modify one of the assets (local or externals) and reload the page in your browser, you will see the new version. Tip: if you are debugging an external asset, you may find it practical to replace the file in debug-assets by a symlink from where you build this asset. For example: $ rm debug-assets/css/cozy-ui.min.css $ ln -s path/to/cozy-ui/dist/cozy-ui.min.css debug/assets/css/cozy-ui.min.css /dev route \u00b6 In development mode, a /dev route is available to render a template or a mail with given parameter. For example: Emails \u00b6 http://cozy.localhost:8080/dev/mails/alert_account http://cozy.localhost:8080/dev/mails/archiver http://cozy.localhost:8080/dev/mails/confirm_flagship http://cozy.localhost:8080/dev/mails/export_error http://cozy.localhost:8080/dev/mails/import_error http://cozy.localhost:8080/dev/mails/import_success http://cozy.localhost:8080/dev/mails/magic_link http://cozy.localhost:8080/dev/mails/move_confirm http://cozy.localhost:8080/dev/mails/move_error http://cozy.localhost:8080/dev/mails/move_success http://cozy.localhost:8080/dev/mails/new_connection http://cozy.localhost:8080/dev/mails/new_registration http://cozy.localhost:8080/dev/mails/notifications_diskquota http://cozy.localhost:8080/dev/mails/notifications_oauthclients http://cozy.localhost:8080/dev/mails/notifications_sharing http://cozy.localhost:8080/dev/mails/passphrase_hint http://cozy.localhost:8080/dev/mails/passphrase_reset http://cozy.localhost:8080/dev/mails/sharing_request http://cozy.localhost:8080/dev/mails/sharing_to_confirm http://cozy.localhost:8080/dev/mails/support_request http://cozy.localhost:8080/dev/mails/two_factor?TwoFactorPasscode=123456 http://cozy.localhost:8080/dev/mails/two_factor_mail_confirmation http://cozy.localhost:8080/dev/mails/update_email HTML pages \u00b6 http://cozy.localhost:8080/dev/templates/authorize.html http://cozy.localhost:8080/dev/templates/authorize_move.html http://cozy.localhost:8080/dev/templates/authorize_sharing.html http://cozy.localhost:8080/dev/templates/compat.html http://cozy.localhost:8080/dev/templates/confirm_auth.html http://cozy.localhost:8080/dev/templates/confirm_flagship.html?Email=jane@example.com http://cozy.localhost:8080/dev/templates/error.html?Error=oops&Button=Click%20me&ButtonURL=https://cozy.io/ http://cozy.localhost:8080/dev/templates/import.html http://cozy.localhost:8080/dev/templates/install_flagship_app.html http://cozy.localhost:8080/dev/templates/instance_blocked.html?Reason=test http://cozy.localhost:8080/dev/templates/login.html http://cozy.localhost:8080/dev/templates/magic_link_twofactor.html http://cozy.localhost:8080/dev/templates/move_confirm.html?Email=jane@example.com http://cozy.localhost:8080/dev/templates/move_delegated_auth.html http://cozy.localhost:8080/dev/templates/move_in_progress.html http://cozy.localhost:8080/dev/templates/move_link.html?Link=https://jane.mycozy.cloud/&Illustration=no http://cozy.localhost:8080/dev/templates/move_vault.html http://cozy.localhost:8080/dev/templates/need_onboarding.html http://cozy.localhost:8080/dev/templates/new_app_available.html http://cozy.localhost:8080/dev/templates/oidc_login.html http://cozy.localhost:8080/dev/templates/oidc_twofactor.html http://cozy.localhost:8080/dev/templates/passphrase_choose.html http://cozy.localhost:8080/dev/templates/passphrase_reset.html?ShowBackButton=true&HasCiphers=true&HasHint=true http://cozy.localhost:8080/dev/templates/share_by_link_password.html http://cozy.localhost:8080/dev/templates/sharing_discovery.html?PublicName=Jane&RecipientDomain=mycozy.cloud&NotEmailError=true http://cozy.localhost:8080/dev/templates/oauth_clients_limit_exceeded.html http://cozy.localhost:8080/dev/templates/twofactor.html?TrustedDeviceCheckBox=true In production \u00b6 The script scripts/build.sh assets download the externals assets, and transform all the assets (local and externals) to go code. This command is used by the maintainers of cozy-stack, so you should not have to worry about that ;-) Locales \u00b6 The locales are managed on transifex. The .po files are put in assets/locales . The master branch is synchronized with transifex via their github integration. Contexts \u00b6 It\u2019s possible to overload some assets on a context with the cozy-stack config insert-asset command. See its manpage and Customizing a context for more details.", "title": "Working with the stack assets"}, {"location": "cozy-stack/assets/#working-with-the-stack-assets", "text": "The cozy-stack has some assets: templates, CSS, JS, fonts, etc. For the deployment in production, they are bundler in the go code and compiled to the binary. But, it\u2019s also nice for developers to have them in a readable format with a git history: they are also put in the assets directory, and some of them are downloaded from other repositories and listed in assets/.externals .", "title": "Working with the stack assets"}, {"location": "cozy-stack/assets/#how-to-work-on-them-on-local", "text": "In short: $ scripts/build.sh debug-assets $ go run . serve --assets debug-assets/ The first command creates a debug-assets directory, with symlinks for local assets. It also downloads the external assets. The second command starts the cozy-stack with those assets. If you modify one of the assets (local or externals) and reload the page in your browser, you will see the new version. Tip: if you are debugging an external asset, you may find it practical to replace the file in debug-assets by a symlink from where you build this asset. For example: $ rm debug-assets/css/cozy-ui.min.css $ ln -s path/to/cozy-ui/dist/cozy-ui.min.css debug/assets/css/cozy-ui.min.css", "title": "How to work on them on local?"}, {"location": "cozy-stack/assets/#dev-route", "text": "In development mode, a /dev route is available to render a template or a mail with given parameter. For example:", "title": "/dev route"}, {"location": "cozy-stack/assets/#emails", "text": "http://cozy.localhost:8080/dev/mails/alert_account http://cozy.localhost:8080/dev/mails/archiver http://cozy.localhost:8080/dev/mails/confirm_flagship http://cozy.localhost:8080/dev/mails/export_error http://cozy.localhost:8080/dev/mails/import_error http://cozy.localhost:8080/dev/mails/import_success http://cozy.localhost:8080/dev/mails/magic_link http://cozy.localhost:8080/dev/mails/move_confirm http://cozy.localhost:8080/dev/mails/move_error http://cozy.localhost:8080/dev/mails/move_success http://cozy.localhost:8080/dev/mails/new_connection http://cozy.localhost:8080/dev/mails/new_registration http://cozy.localhost:8080/dev/mails/notifications_diskquota http://cozy.localhost:8080/dev/mails/notifications_oauthclients http://cozy.localhost:8080/dev/mails/notifications_sharing http://cozy.localhost:8080/dev/mails/passphrase_hint http://cozy.localhost:8080/dev/mails/passphrase_reset http://cozy.localhost:8080/dev/mails/sharing_request http://cozy.localhost:8080/dev/mails/sharing_to_confirm http://cozy.localhost:8080/dev/mails/support_request http://cozy.localhost:8080/dev/mails/two_factor?TwoFactorPasscode=123456 http://cozy.localhost:8080/dev/mails/two_factor_mail_confirmation http://cozy.localhost:8080/dev/mails/update_email", "title": "Emails"}, {"location": "cozy-stack/assets/#html-pages", "text": "http://cozy.localhost:8080/dev/templates/authorize.html http://cozy.localhost:8080/dev/templates/authorize_move.html http://cozy.localhost:8080/dev/templates/authorize_sharing.html http://cozy.localhost:8080/dev/templates/compat.html http://cozy.localhost:8080/dev/templates/confirm_auth.html http://cozy.localhost:8080/dev/templates/confirm_flagship.html?Email=jane@example.com http://cozy.localhost:8080/dev/templates/error.html?Error=oops&Button=Click%20me&ButtonURL=https://cozy.io/ http://cozy.localhost:8080/dev/templates/import.html http://cozy.localhost:8080/dev/templates/install_flagship_app.html http://cozy.localhost:8080/dev/templates/instance_blocked.html?Reason=test http://cozy.localhost:8080/dev/templates/login.html http://cozy.localhost:8080/dev/templates/magic_link_twofactor.html http://cozy.localhost:8080/dev/templates/move_confirm.html?Email=jane@example.com http://cozy.localhost:8080/dev/templates/move_delegated_auth.html http://cozy.localhost:8080/dev/templates/move_in_progress.html http://cozy.localhost:8080/dev/templates/move_link.html?Link=https://jane.mycozy.cloud/&Illustration=no http://cozy.localhost:8080/dev/templates/move_vault.html http://cozy.localhost:8080/dev/templates/need_onboarding.html http://cozy.localhost:8080/dev/templates/new_app_available.html http://cozy.localhost:8080/dev/templates/oidc_login.html http://cozy.localhost:8080/dev/templates/oidc_twofactor.html http://cozy.localhost:8080/dev/templates/passphrase_choose.html http://cozy.localhost:8080/dev/templates/passphrase_reset.html?ShowBackButton=true&HasCiphers=true&HasHint=true http://cozy.localhost:8080/dev/templates/share_by_link_password.html http://cozy.localhost:8080/dev/templates/sharing_discovery.html?PublicName=Jane&RecipientDomain=mycozy.cloud&NotEmailError=true http://cozy.localhost:8080/dev/templates/oauth_clients_limit_exceeded.html http://cozy.localhost:8080/dev/templates/twofactor.html?TrustedDeviceCheckBox=true", "title": "HTML pages"}, {"location": "cozy-stack/assets/#in-production", "text": "The script scripts/build.sh assets download the externals assets, and transform all the assets (local and externals) to go code. This command is used by the maintainers of cozy-stack, so you should not have to worry about that ;-)", "title": "In production"}, {"location": "cozy-stack/assets/#locales", "text": "The locales are managed on transifex. The .po files are put in assets/locales . The master branch is synchronized with transifex via their github integration.", "title": "Locales"}, {"location": "cozy-stack/assets/#contexts", "text": "It\u2019s possible to overload some assets on a context with the cozy-stack config insert-asset command. See its manpage and Customizing a context for more details.", "title": "Contexts"}, {"location": "cozy-stack/auth/", "text": "Table of contents Authentication and access delegations \u00b6 Introduction \u00b6 In this document, we will cover how to protect the usage of the cozy-stack. When the cozy-stack receives a request, it checks that the request is authorized, and if yes, it processes it and answers it. What about OAuth2? \u00b6 OAuth2 is about delegating an access to resources on a server to another party. It is a framework, not a strictly defined protocol, for organizing the interactions between these 4 actors: the resource owner, the \u201cuser\u201d that can click on buttons the client, the website or application that would like to access the resources the authorization server, whose role is limited to give tokens but is central in OAuth2 interactions the resources server, the server that controls the resources. For cozy, both the authorization server and the resources server roles are played by the cozy-stack. The resource owner is the owner of a cozy instance. The client can be the cozy-desktop app, cozy-mobile, or many other applications. OAuth2, and its extensions, is a large world. At its core, there is 2 things: letting the client get a token issued by the authorization server, and using this token to access to the resources. OAuth2 describe 4 flows, called grant types, for the first part: Authorization code Implicit grant type Client credentials grant type Resource owner credentials grant type. On cozy, only the most typical one is used: authorization code. To start this flow, the client must have a client_id and client_secret . The Cozy stack implements the OAuth2 Dynamic Client Registration Protocol (an extension to OAuth2) to allow the clients to obtain them. OAuth2 has also 3 ways to use a token: in the query-string (even if the spec does not recommended it) in the POST body in the HTTP Authorization header. On cozy, only the HTTP header is supported. OAuth2 has a lot of assumptions. Let\u2019s see some of them and their consequences on Cozy: TLS is very important to secure the communications. in OAuth 1, there was a mechanism to sign the requests. But it was very difficult to get it right for the developers and was abandonned in OAuth2, in favor of using TLS. The Cozy instance are already accessible only in HTTPS, so there is nothing particular to do for that. There is a principle called TOFU, Trust On First Use. It said that if the user will give his permission for delegating access to its resources when the client will try to access them for the first time. Later, the client will be able to keep accessing them even if the user is no longer here to give his permissions. The client can\u2019t make the assumptions about when its tokens will work. The tokens have no meaning for him (like cookies in a browser), they are just something it got from the authorization server and can send with its request. The access token can expire, the user can revoke them, etc. OAuth 2.0 defines no cryptographic methods. But a developer that want to use it will have to put her hands in that. If you want to learn OAuth 2 in details, I recommend the OAuth 2 in Action book . The cozy stack as an authorization server \u00b6 In general, the cozy stack manages the authentication itself. This is what is described below. In some special cases, an integration with other softwares can be mandatory: this is possible to configure via delegated authentication . GET /auth/login \u00b6 Display a form with a password field to let the user authenticates herself to the cozy stack. This endpoint accepts a redirect parameter. If the user is already logged in, she will be redirected immediately. Else, the parameter will be transfered in the POST. This parameter can only contain a link to an application installed on the cozy (thus to a subdomain of the cozy instance). To protect against stealing authorization code with redirection, the fragment is always overriden: GET /auth/login?redirect=https://contacts.cozy.example.org/foo?bar#baz HTTP / 1.1 Host : cozy.example.org Cookie : ... Note : the redirect parameter should be URL-encoded. We haven\u2019t done that to make it clear what the path ( foo ), the query-string ( bar ), and the fragment ( baz ) are. HTTP / 1.1 302 Moved Temporarily Location : https://contacts.cozy.example.org/foo?bar# If the redirect parameter is invalid, the response will be 400 Bad Request . Same for other parameters, the redirection will happen only on success (even if OAuth2 says the authorization server can redirect on errors, it\u2019s very complicated to do it safely, and it is better to avoid this trap). POST /auth/login \u00b6 After the user has typed her passphrase and clicked on Login , a request is made to this endpoint. The redirect parameter is passed inside the body. If it is missing, the redirection will be made against the default target: the home application of this cozy instance. The redirect can be a full URL (like http://cozy-drive.example.org/#/folder ), or just a slug+path+hash (like drive/#/folder ). POST /auth/login HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded passphrase=p4ssw0rd&redirect=https%3A%2F%2Fcontacts.cozy.example.org HTTP / 1.1 302 Moved Temporarily Set-Cookie : ... Location : https://contacts.cozy.example.org/foo When two-factor authentication (2FA) authentication is activated, this endpoint will not directly sent a redirection after this first passphrase step. In such case, a 200 OK response is sent along with a token value in the response (either in JSON if requested or directly in a new HTML form). Along with this token, a 2FA passcode is sent to the user via another transport (email for instance, depending on the user\u2019s preferences). Another request should be sent to /auth/twofactor with a valid pair (token, passcode) , ensuring that the user correctly entered its passphrase and received a fresh passcode by another mean. POST /auth/twofactor \u00b6 POST /auth/twofactor HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded two-factor-token=123123123123&two-factor-passcode=678678&redirect=https%3A%2F%2Fcontacts.cozy.example.org HTTP / 1.1 302 Moved Temporarily Set-Cookie : ... Location : https://contacts.cozy.example.org/foo POST /auth/login/flagship \u00b6 This endpoint is similar to POST /auth/login , but it allows the flagship app to also obtain OAuth access and register tokens without having to make the OAuth dance (which can be awkward for the user). Request \u00b6 POST /auth/login/flagship HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg\" , \"scope\" : \"*\" } Note: if two-factor authentication is enabled on the Cozy, an email will be sent to the user with a code, and this request will return: HTTP / 1.1 401 Unauthorized Content-Type : application/json { \"two_factor_token\" : \"123123123123\" } Then, the client can retry by sending the two-factor token and code: { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"two_factor_token\" : \"123123123123\" , \"two_factor_code\" : \"123456\" } Note: if the two-factor authentication is enabled, and the cloudery has already verified the email address, a parameter email_verified_code can be sent to skip another 2FA code sent by mail. { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"email_verified_code\" : \"987456321\" } Note: if the OAuth client has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app. DELETE /auth/login \u00b6 This can be used to log-out the user. An app token must be passed in the Authorization header, to protect against CSRF attack on this (this can part of bigger attacks like session fixation). DELETE /auth/login HTTP / 1.1 Host : cozy.example.org Cookie : seesioncookie.... Authorization : Bearer app-token DELETE /auth/login/others \u00b6 This can be used to log-out all active sessions except the one used by the request. This allow to disconnect any other users currenctly authenticated on the system. An app token must be passed in the Authorization header, to protect against CSRF attack on this (this can part of bigger attacks like session fixation). DELETE /auth/login/others HTTP / 1.1 Host : cozy.example.org Cookie : seesioncookie.... Authorization : Bearer app-token POST /auth/magic_link \u00b6 If the authentication via magic link is enabled on this instance, this endpoint will send an email to the user with a magic link. If the user clicks on this link, they will be authenticated on the Cozy. GET /auth/magic_link?code=\u2026 \u00b6 When the user has received an email with a magic link, the link goes to the endpoint, where the user will be allowed to enter the Cozy. POST /auth/magic_link/twofactor \u00b6 When two-factor authentication is enabled on a Cozy, this endpoint can be used to create a session. POST /auth/magic_link/flagship \u00b6 This endpoint allows the flagship app to also obtain OAuth access and register tokens without having to make the OAuth dance (which can be awkward for the user). It requires a code sent by email to the user. Request \u00b6 POST /auth/magic_link/flagship HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"magic_code\" : \"ODFhNzkxYTAtYjZiYi0wMTNiLTE1YzQtMThjMDRkYWJhMzI2\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg\" , \"scope\" : \"*\" } Note: if two-factor authentication is enabled on the Cozy, an email will be sent to the user with a code, and this request will return: HTTP / 1.1 401 Unauthorized Content-Type : application/json { \"error\" : \"passphrase is required as second authentication factor\" } Then, the client can retry by sending the two-factor token and code: { \"magic_code\" : \"ODFhNzkxYTAtYjZiYi0wMTNiLTE1YzQtMThjMDRkYWJhMzI2\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" } Note: if the OAuth client has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app. GET /auth/passphrase_reset \u00b6 Display a form for the user to reset its password, in case he has forgotten it for example. If the user is connected, he won\u2019t be shown this form and he will be directly redirected to his cozy. This endpoint accepts a hideBackButton parameter. If this parameter is present and set to true then the passphrase reset page won\u2019t display any button to go back to the login page. This is useful when this page is opened in a different context from the one in which the login page was opened (e.g. a browser vs a mobile native application). It is also possible to use from=settings parameter in the query-string, to go back to the settings app after the password has been reset. It is useful when the user wants to change their email address, as the process for changing this address requires the password. GET /auth/passphrase_reset?hideBackButton=true HTTP / 1.1 Host : cozy.example.org Content-Type : text/html Cookie : ... POST /auth/hint \u00b6 Send the password hint by email. POST /auth/hint HTTP / 1.1 Host : cozy.example.org POST /auth/onboarding/resend \u00b6 Resend the activation link by email to finalize the onboarding. POST /auth/onboarding/resend HTTP / 1.1 Host : cozy.example.org POST /auth/passphrase_reset \u00b6 After the user has clicked on the reset button of the passphrase reset form, it will execute a request to this endpoint. This endpoint will create a token for the user to actually renew his passphrase. The token has a short-live duration of about 15 minutes. After the token is created, it is sent to the user on its mailbox. This endpoint will redirect the user on the login form page. POST /auth/passphrase_reset HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded csrf_token=123456890 GET /auth/passphrase_renew \u00b6 Display a form for the user to enter a new password. This endpoint should be used with a token query parameter. This token makes sure that the user has actually reset its passphrase and should have been sent via its mailbox. GET /auth/passphrase_renew?token=123456789 HTTP / 1.1 Host : cozy.example.org Content-Type : text/html Cookie : ... POST /auth/passphrase_renew \u00b6 After the user has entered its new passphrase in the renew passphrase form, a request is made to this endpoint to renew the passphrase. This endpoint requires a valid token to actually work. In case of a success, the user is redirected to the login form. POST /auth/passphrase_reset HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded csrf_token=123456890&passphrase_reset_token=123456789&passphrase=mynewpassphrase Parameters \u00b6 Form parameter Description passphrase_reset_token the token to authenticate the request csrf_token the token to protect against CSRF attacks passphrase the new password hint the hint to find again the password iterations the number of PBKDF2 iterations key the encrypted master key for bitwarden public_key the public key for the cozy organization private_key the private key for the cozy organization GET /auth/passphrase \u00b6 This page renders a form to set the password for an onboarding instance. This endpoint expects a valid registerToken parameter. In case of success, the instance is marked as onboarded and the user is redirected to his home. If the instance is already onboarded, the user is redirected to his home. It is also possible to give a redirection parameter to redirect the user to another application. GET /auth/passphrase/?registerToken=e0fbe2c5b90cdcdd9b3487b48b480e0b&redirection=drive/%23/files HTTP / 1.1 Host : cozy.example.org Content-Type : text/html GET /auth/confirm \u00b6 An application can ask the user to re-authenticate them-selves before making an important action (like erasing a pin code). To do that, the application will sent the user to this page where the stack will show a form. Two parameters in the query string can be sent: state (mandatory), which can be seen as an identifier for the confirmation redirect (optional), where the user will be redirected after the confirmation. GET /auth/confirm?state=51814f30-5818-0139-9348-543d7eb8149c&redirect=http://banks.cozy.localhost:8080/ HTTP / 1.1 The application can know the user has confirmed their identity by subscribing to a real-time event or by looking at the URL after the redirection. The URL must contain the state given by the app, and a code that can be checked by calling POST /auth/confirm/code (see below). POST /auth/confirm \u00b6 Send the hashed password for confirming the authentication. Redirection \u00b6 HTTP / 1.1 302 Moved Temporarily Location : http://banks.cozy.localhost:8080/?state=51814f30-5818-0139-9348-543d7eb8149c&code=543d7eb8149c Real-time via websockets \u00b6 If it succeeds, a real-time event will be sent: client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.auth.confirmations\"}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"51814f30-5818-0139-9348-543d7eb8149c\", \"type\": \"io.cozy.auth.confirmations\"}} GET /auth/confirm/:code \u00b6 Send the code from the URL to check that the user has really confirmed their identity (and not just typed the URL them-self). GET /auth/confirm/543d7eb8149c HTTP / 1.1 The response will be a 204 No Content if the code is valid (and a 401 else). POST /auth/register \u00b6 This route is used by OAuth2 clients to dynamically register them-selves. See OAuth 2.0 Dynamic Client Registration Protocol for the details. The client must send a JSON request, with at least: redirect_uris , an array of strings with the redirect URIs that the client will use in the authorization flow client_name , human-readable string name of the client to be presented to the end-user during authorization software_id , an identifier of the software used by the client (it should remain the same for all instances of the client software, whereas client_id varies between instances). It can also send the optional fields: client_kind (possible values: web, desktop, mobile, browser, etc.) client_uri , URL string of a web page providing information about the client logo_uri , to display an icon to the user in the authorization flow policy_uri , URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data software_version , a version identifier string for the client software. notification_platform , to activate notifications on the associated device, this field specify the platform used to send notifications: \"android\" : for Android devices with notifications via Firebase Cloud Messaging \"ios\" : for iOS devices with notifications via Firebase Cloud Messaging or APNS/2 \"huawei\" : for huawei devices with Push Kit notification_device_token , the token used to identify the mobile device for notifications. The server gives to the client the previous fields and these informations: client_id client_secret registration_access_token Example: POST /auth/register HTTP / 1.1 Host : cozy.example.org Content-Type : application/json Accept : application/json { \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.1\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" } HTTP / 1.1 201 Created Content-Type : application/json { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"client_secret_expires_at\" : 0 , \"registration_access_token\" : \"J9l-ZhwP[...omitted for brevity...]\" , \"grant_types\" : [ \"authorization_code\" , \"refresh_token\" ], \"response_types\" : [ \"code\" ], \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.1\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" } Linked applications \u00b6 Some OAuth applications are a mobile or desktop version of a Cozy webapp. For them, it\u2019s possible to use a special software_id to make a link between the mobile/desktop application and the webapp. The software_id must be in a registry://slug format, like registry://drive for Cozy-Drive for example. When it is the case, the mobile/desktop will share its permissions with the webapp. It means several things: The mobile/desktop app will have the same permissions that the linked webapp. When a sharing by link is done in the mobile/desktop application, the linked webapp will be able to revoke it later, and vice versa. When the user accepts to give access to its Cozy to the mobile/desktop app, the linked webapp will be installed on the Cozy if it was not already the case. When the linked webapp is uninstalled, the right to access the Cozy for the mobile/desktop app will be revoked. GET /auth/register/:client-id \u00b6 This route is used by the clients to get informations about them-selves. The client has to send its registration access token to be able to use this endpoint. See OAuth 2.0 Dynamic Client Registration Management Protocol for more details. GET /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer J9l-ZhwP... HTTP / 1.1 201 Created Content-Type : application/json { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"client_secret_expires_at\" : 0 , \"grant_types\" : [ \"authorization_code\" , \"refresh_token\" ], \"response_types\" : [ \"code\" ], \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.1\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" } PUT /auth/register/:client-id \u00b6 This route is used by the clients to update informations about them-selves. The client has to send its registration access token to be able to use this endpoint. Note: the client can ask to change its client_secret . To do that, it must send the current client_secret , and the server will respond with the new client_secret . PUT /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP / 1.1 Host : cozy.example.org Accept : application/json Content-Type : application/json Authorization : Bearer J9l-ZhwP... { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.2\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/client-logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" , \"notification_platform\" : \"android\" , \"notification_device_token\" : \"XXXXxxxx...\" } HTTP / 1.1 200 OK Content-Type : application/json { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"IFais2Ah[...omitted for brevity...]\" , \"client_secret_expires_at\" : 0 , \"grant_types\" : [ \"authorization_code\" , \"refresh_token\" ], \"response_types\" : [ \"code\" ], \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.2\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/client-logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" } DELETE /auth/register/:client-id \u00b6 This route is used by the clients to unregister them-selves. The client has to send its registration access token to be able to use this endpoint. DELETE /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP / 1.1 Host : cozy.example.org Authorization : Bearer J9l-ZhwP... HTTP / 1.1 204 No Content POST /auth/clients/:client-id/challenge \u00b6 This route can be used to start the process for certifying that an app is really what it tells to be by using the android/iOS APIs (PlayIntegrity/SafetyNet/AppleAttestation). It returns a nonce that must be used in the certificate. The client must send its registration access token to use this endpoint. POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/challenge HTTP / 1.1 Host : cozy.example.org Authorization : Bearer J9l-ZhwP... HTTP / 1.1 201 Created Content-Type : application/json { \"nonce\" : \"MmE3OTM1ZDItNWY0ZC0xMWVjLTg3NT\" } POST /auth/clients/:client-id/attestation \u00b6 This route can be used to finish the process for certifying that an app is really what it tells to be by using the android/iOS APIs. The client can send its attestation. POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/attestation HTTP / 1.1 Host : cozy.example.org Content-Type : application/json { \"platform\" : \"android\" , \"challenge\" : \"MmE3OTM1ZDItNWY0ZC0xMWVjLTg3NT\" , \"attestation\" : \"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\" } Note: the platform parameter can be \"android\" or \"ios\" . For ios , a \"keyId\" parameter is also required. For android , the \"issuer\" can be \"playintegrity\" to use the Play Integrity API instead of the SafetyNet API. HTTP / 1.1 204 No Content POST /auth/clients/:client-id/flagship \u00b6 This route can be used to send a 6-digits code to manually certify a client as belonging to the flagship app. POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/flagship HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded code=123456&token=123123123123123 HTTP / 1.1 204 No Content GET /auth/authorize \u00b6 When an OAuth2 client wants to get access to the data of the cozy owner, it starts the OAuth2 dance with this step. The user is shown what the client asks and has an accept button if she is OK with that. In case a limit has been set on the Cozy to the number of user-connected OAuth clients, and this limit has been reached already, the user will be presented a screen requesting to either remove some existing clients or, if enabled, increase the limit (e.g. by subscribing to a plan with a greater limit). Once the number of connected clients is brought back under the limit, the OAuth flow will resume and the permissions screen will be displayed. The parameters are: client_id , that identify the client redirect_uri , it has to be exactly the same as the one used in registration state , it\u2019s a protection against CSRF on the client (a random string generated by the client, that it can check when the user will be redirected with the authorization code. It can be used as a key in local storage for storing a state in a SPA). response_type , only code is supported scope , a space separated list of the permissions asked (like io.cozy.files:GET for read-only access to files). GET /auth/authorize?client_id=oauth-client-1&response_type=code&scope=io.cozy.files%3AGET%20io.cozy.contacts&state=Eh6ahshepei5Oojo&redirect_uri=https%3A%2F%2Fclient.org%2F HTTP / 1.1 Host : cozy.example.org Note we warn the user that he is about to share his data with an application which only the callback URI is guaranteed. PKCE extension \u00b6 To improve security, the client can use the PKCE for OAuth 2 . In that case, two additional parameters must be send to GET /auth/authorize : code_challenge : the client creates a code_verifier , and then derive the code_challenge from it. code_challenge_method : it must be S256 (the only supported method). As a reminder, the relation between code_verifier and code_challenge is the following: code_challenge = BASE64URL-ENCODE(SHA256(code_verifier)) And, the code_verifier parameter must be sent to POST /auth/access_token (see below). POST /auth/authorize \u00b6 When the user accepts, her browser send a request to this endpoint: POST /auth/authorize HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded state=Eh6ahshepei5Oojo&client_id=oauth-client-1&scope=io.cozy.files%3AGET%20io.cozy.contacts&csrf_token=johw6Sho&response_type=code&redirect_uri=https%3A%2F%2Fclient.org%2F Note : this endpoint is protected against CSRF attacks. The user is then redirected to the original client, with an access code in the URL: HTTP / 1.1 302 Moved Temporarily Location : https://client.org/?state=Eh6ahshepei5Oojo&code=Aih7ohth# GET /auth/authorize/sharing & POST /auth/authorize/sharing \u00b6 They are similar to /auth/authorize : they also make the user accept an OAuth thing, but it is specialized for sharing. They are a few differences, like the scope format (sharing rules, not permissions) and the redirection after the POST (with sharing= in the query string). GET /auth/authorize/move & POST /auth/authorize/move \u00b6 They are similar to /auth/authorize , but instead of a page that lists the permissions, the user will be asked to type their password to confirm the action (even if they are already logged-in). If the 2FA is activated, the code will be asked too. This strong action seems adequate for authorizing to erase the data in the Cozy before importing data from another Cozy. Request GET \u00b6 GET /auth/authorize/move?state=8d560d60&client_id=oauth-client-2&redirect_uri=https://move.cozycloud.cc/callback/target HTTP / 1.1 Server : target.cozy.example Response GET \u00b6 HTTP / 1.1 200 OK Content-Type : application/html Request POST \u00b6 POST /auth/authorize/move HTTP / 1.1 Server : target.cozy.example Content-Type : application/x-www-form-urlencoded passphrase=hashed&state=8d560d60&client_id=oauth-client-2&csrf_token=johw6Sho&redirect_uri=https%3A%2F%2Fmove.cozycloud.cc%2Fcallback%2Ftarget Response POST \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"redirect\" : \"https://move.cozycloud.cc/callback/target?code=543d7eb8149c&used=123456"a=5000000&state=8d560d60&vault=true\" } POST /auth/access_token \u00b6 Now, the client can check that the state is correct, and if it is the case, ask for an access_token . It can use this route with the code given above. This endpoint is also used to refresh the access token, by sending the refresh_token instead of the code . The parameters are: grant_type , with authorization_code or refresh_token as value code or refresh_token , depending on which grant type is used client_id client_secret Example: POST /auth/access_token HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded Accept : application/json grant_type=authorization_code&code=Aih7ohth&client_id=oauth-client-1&client_secret=Oung7oi5 HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"ooch1Yei\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"ui0Ohch8\" , \"scope\" : \"io.cozy.files:GET io.cozy.contacts\" } POST /auth/session_code \u00b6 This endpoint can be used by the flagship application in order to create a session code: this code can be added to the URL of a cozy application (in the query string, as session_code ) to create a session. The flagship can create this code with its access token, and then use it in a webview to avoid the reauthentication of the user. It can also create the code with the hashed passphrase (and 2FA if needed) to create a session for the authorize page. Note that the difference between a session_code and a magic_code (code in a magic link sent by email) is the behavior when two-factor authentication is enabled. The session_code will open the session while the magic_code will require the password for that. Request (access token variant) \u00b6 POST /auth/session_code HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer eyJpc3Mi... Request (passphrase variant) \u00b6 POST /auth/session_code HTTP / 1.1 Host : cozy.example.org Accept : application/json Content-Type : application/json { \"passphrase\" : \"hashed\" , \"two_factor_token\" : \"123123123123\" , \"two_factor_passcode\" : \"678678\" } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/json { \"session_code\" : \"HzEFM3JREpIB6532fQc1FP2t4YJKt3gI\" } The flagship will then be able to open a webview for https://cozy-home.example.org/?session_code=HzEFM3JREpIB6532fQc1FP2t4YJKt3gI . Response (2FA needed) \u00b6 In case of error where 2FA is needed, the response will be: HTTP / 1.1 403 Forbidden Content-Type : application/json { \"error\" : \"two factor needed\" , \"two_factor_token\" : \"123123123123\" } FAQ \u00b6 What format is used for tokens? The access tokens are formatted as JSON Web Tokens (JWT) , like this: Claim Fullname What it identifies aud Audience Identify the recipient where the token can be used (like access ) iss Issuer Identify the Cozy instance (its domain in fact) iat Issued At Identify when the token was issued (Unix timestamp) sub Subject Identify the client that can use the token scope Scope Identify the scope of actions that the client can accomplish The scope is used for permissions . Other tokens can be JWT with a similar formalism, or be a simple random value (when we want to have a clear revocation process). What happens when the user has lost her passphrase? She can reset it from the command-line, like this: $ cozy-stack instances reset-passphrase cozy.example.org ek0Jah1R A new password is generated and print in the console. Is two-factor authentication (2FA) possible? Yes, it\u2019s possible. Via the cozy-settings application, the two-factor authentication can be activated. Here is how it works in more details: On each connection, when the 2FA is activated, the user is asked for its passphrase first. When entering correct passphrase, the user is then asked for: a TOTP (Timebased One-Time password, RFC 6238) derived from a secret associated with the instance. a short term timestamped MAC with the same validity time-range and also derived from the same secret. The TOTP is valid for a time range of about 5 minutes. When sending a correct and still-valid pair (passcode, token) , the user is granted with authentication cookie. The passcode can be sent to the instance\u2019s owner via email \u2014 more transport shall be added later. POST /auth/tokens/konnectors/:slug \u00b6 This endpoint can be used by the flagship application in order to create a token for the konnector with the given slug. This token can then be used by the client-side konnector to make requests to cozy-stack. The flagship app will need to use its own access token to request the konnector token. Request \u00b6 POST /auth/tokens/konnectors/impots HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer eyJpc3Mi... Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/json \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\" POST /auth/share-by-link/password \u00b6 This route is used when a share by link is protected by password. The password can be sent to this route to create a cookie that will allow to use the sharecode and access the shared page. Request \u00b6 POST /auth/clients/share-by-link/password HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded password=HelloWorld!&perm_id=123456789 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json Set-Cookie : pass123... { \"password\" : \"ok\" } FAQ \u00b6 What format is used for tokens? The access tokens are formatted as JSON Web Tokens (JWT) , like this: Claim Fullname What it identifies aud Audience Identify the recipient where the token can be used (i.e. konn ) iss Issuer Identify the Cozy instance (its domain in fact) iat Issued At Identify when the token was issued (Unix timestamp) sub Subject Identify the client that can use the token (i.e. the konnector slug) scope Scope Konnector tokens don\u2019t have any scope Client-side apps \u00b6 Important : OAuth2 is not used here! The steps looks similar (like obtaining a token), but when going in the details, it doesn\u2019t match. How to register the application? \u00b6 The application is registered at install. See app management for details. How to get a token? \u00b6 When a user access an application, she first loads the HTML page. Inside this page, a token specific to this app is injected (only for private routes), via a templating method. We have prefered our custom solution to the implicit grant type of OAuth2 for 2 reasons: It has a better User Experience. The implicit grant type works with 2 redirections (the application to the stack, and then the stack to the application), and the first one needs JS to detect if the token is present or not in the fragment hash. It has a strong impact on the time to load the application. The implicit grant type of OAuth2 has a severe drawback on security: the token appears in the URL and is shown by the browser. It can also be leaked with the HTTP Referer header. The token will be given only for the authenticated user. For nested subdomains (like calendar.joe.example.net ), the session cookie from the stack is enough (it is for .joe.example.net ). But for flat subdomains (like joe-calendar.example.net ), it\u2019s more complicated. On the first try of the user, she will be redirected to the stack. As she is already logged-in, she will be redirected to the app with a session code (else she can login). This session code can be exchanged to a session cookie. A redirection will still happen to remove the code from the URL (it helps to avoid the code being saved in the browser history). For security reasons, the session code have the following properties: It can only be used once. It is tied to an application ( calendar in our example). It has a very short time span of validity (1 minute). How to use a token? \u00b6 The token can be sent to the cozy-stack as a Bearer token in the Authorization header, like this: GET /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Host : cozy.example.org Authorization : Bearer application-token If the user is authenticated, her cookies will be sent automatically. The cookies are needed for a token to be valid. How to refresh a token? \u00b6 The token is valid only for 24 hours. If the application is opened for more than that, it will need to get a new token. But most applications won\u2019t be kept open for so long and it\u2019s okay if they don\u2019t try to refresh tokens. At worst, the user just had to reload its page and it will work again. The app can know it\u2019s time to get a new token when the stack starts sending 401 Unauthorized responses. In that case, it can fetches the same html page that it was loaded initially, parses it and extracts the new token. Third-party websites \u00b6 How to register the application? \u00b6 If a third-party websites would like to access a cozy, it had to register first. For example, a big company can have data about a user and may want to offer her a way to get her data back in her cozy. When the user is connected on the website of this company, she can give her cozy address. The website will then register on this cozy, using the OAuth2 Dynamic Client Registration Protocol, as explained above . How to get a token? \u00b6 To get an access token, it\u2019s enough to follow the authorization code flow of OAuth2: sending the user to the cozy, on the authorize page if the user approves, she is then redirected back to the client the client gets the access code and can exchange it to an access token. How to use a token? \u00b6 The access token can be sent as a bearer token, in the Authorization header of HTTP: GET /data/io.cozy.contacts/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ How to refresh a token? \u00b6 The access token will be valid only for 24 hours. After that, a new access token must be asked. To do that, just follow the refresh token flow, as explained above . Devices and browser extensions \u00b6 For devices and browser extensions, it is nearly the same than for third-party websites. The main difficulty is the redirect_uri. In OAuth2, the access code is given to the client by redirecting the user to an URL controlled by the client. But devices and browser extensions don\u2019t have an obvious URL for that. The IETF has published an RFC called OAuth 2.0 for Native Apps . Native apps on desktop \u00b6 A desktop native application can start an embedded webserver on localhost. The redirect_uri will be something like http://127.0.0.1:19856/callback . Native apps on mobile \u00b6 On mobile, the native apps can often register a custom URI scheme, like com.example.oauthclient:/ . Just be sure that no other app has registered itself with the same URI. Chrome extensions \u00b6 Chrome extensions can use URL like https://.chromiumapp.org/ for their usage. See https://developer.chrome.com/apps/app_identity#non for more details. It has also a method to simplify the creation of such an URL: chrome.identity.getRedirectURL . Firefox extensions \u00b6 It is possible to use an out of band URN: urn:ietf:wg:oauth:2.0:oob:auto . The token is then extracted from the title of the page. See this addon for google oauth2 as an example. Security considerations \u00b6 The master password, the password known by the user, is derived on the clients to give two keys. The first key is used to login on the stack, the second key is used to do client-side encryption. The derivation for the login password is currently done with the PBKDF2 algorithm (with SHA256), but we have anticipated the possibility of changing to another algorithm if desirable. The derived password is stored on the server in a secure fashion, with a password hashing function. The hashing function and its parameter are stored with the hash, in order to make it possible to change the algorithm and/or the parameters later if we had any suspicion that it became too weak. The initial algorithm is scrypt . The access code is valid only once, and will expire after 5 minutes Dynamically registered applications won\u2019t have access to all possible scopes. For example, an application that has been dynamically registered can\u2019t ask the cozy owner to give it the right to install other applications. This limitation should improve security, as avoiding too powerful scopes to be used with unknown applications. The cozy stack will apply rate limiting to avoid brute-force attacks. The cozy stack offers CORS for most of its services. But it\u2019s disabled for /auth (it doesn\u2019t make sense here) and for the client-side applications (to avoid leaking their tokens). The client should really use HTTPS for its redirect_uri parameter, but it\u2019s allowed to use HTTP for localhost, as in the native desktop app example. OAuth2 says that the state parameter is optional in the authorization code flow. But it is mandatory to use it with Cozy. For more on this subject, here is a list of links: https://www.owasp.org/index.php/Authentication_Cheat_Sheet https://tools.ietf.org/html/rfc6749#page-53 https://tools.ietf.org/html/rfc6819 https://tools.ietf.org/html/draft-ietf-oauth-closing-redirectors-00 http://www.oauthsecurity.com/ Conclusion \u00b6 Security is hard. If you want to share some concerns with us, do not hesitate to send us an email to security AT cozycloud.cc.", "title": "/auth - Authentication & OAuth"}, {"location": "cozy-stack/auth/#authentication-and-access-delegations", "text": "", "title": "Authentication and access delegations"}, {"location": "cozy-stack/auth/#introduction", "text": "In this document, we will cover how to protect the usage of the cozy-stack. When the cozy-stack receives a request, it checks that the request is authorized, and if yes, it processes it and answers it.", "title": "Introduction"}, {"location": "cozy-stack/auth/#what-about-oauth2", "text": "OAuth2 is about delegating an access to resources on a server to another party. It is a framework, not a strictly defined protocol, for organizing the interactions between these 4 actors: the resource owner, the \u201cuser\u201d that can click on buttons the client, the website or application that would like to access the resources the authorization server, whose role is limited to give tokens but is central in OAuth2 interactions the resources server, the server that controls the resources. For cozy, both the authorization server and the resources server roles are played by the cozy-stack. The resource owner is the owner of a cozy instance. The client can be the cozy-desktop app, cozy-mobile, or many other applications. OAuth2, and its extensions, is a large world. At its core, there is 2 things: letting the client get a token issued by the authorization server, and using this token to access to the resources. OAuth2 describe 4 flows, called grant types, for the first part: Authorization code Implicit grant type Client credentials grant type Resource owner credentials grant type. On cozy, only the most typical one is used: authorization code. To start this flow, the client must have a client_id and client_secret . The Cozy stack implements the OAuth2 Dynamic Client Registration Protocol (an extension to OAuth2) to allow the clients to obtain them. OAuth2 has also 3 ways to use a token: in the query-string (even if the spec does not recommended it) in the POST body in the HTTP Authorization header. On cozy, only the HTTP header is supported. OAuth2 has a lot of assumptions. Let\u2019s see some of them and their consequences on Cozy: TLS is very important to secure the communications. in OAuth 1, there was a mechanism to sign the requests. But it was very difficult to get it right for the developers and was abandonned in OAuth2, in favor of using TLS. The Cozy instance are already accessible only in HTTPS, so there is nothing particular to do for that. There is a principle called TOFU, Trust On First Use. It said that if the user will give his permission for delegating access to its resources when the client will try to access them for the first time. Later, the client will be able to keep accessing them even if the user is no longer here to give his permissions. The client can\u2019t make the assumptions about when its tokens will work. The tokens have no meaning for him (like cookies in a browser), they are just something it got from the authorization server and can send with its request. The access token can expire, the user can revoke them, etc. OAuth 2.0 defines no cryptographic methods. But a developer that want to use it will have to put her hands in that. If you want to learn OAuth 2 in details, I recommend the OAuth 2 in Action book .", "title": "What about OAuth2?"}, {"location": "cozy-stack/auth/#the-cozy-stack-as-an-authorization-server", "text": "In general, the cozy stack manages the authentication itself. This is what is described below. In some special cases, an integration with other softwares can be mandatory: this is possible to configure via delegated authentication .", "title": "The cozy stack as an authorization server"}, {"location": "cozy-stack/auth/#get-authlogin", "text": "Display a form with a password field to let the user authenticates herself to the cozy stack. This endpoint accepts a redirect parameter. If the user is already logged in, she will be redirected immediately. Else, the parameter will be transfered in the POST. This parameter can only contain a link to an application installed on the cozy (thus to a subdomain of the cozy instance). To protect against stealing authorization code with redirection, the fragment is always overriden: GET /auth/login?redirect=https://contacts.cozy.example.org/foo?bar#baz HTTP / 1.1 Host : cozy.example.org Cookie : ... Note : the redirect parameter should be URL-encoded. We haven\u2019t done that to make it clear what the path ( foo ), the query-string ( bar ), and the fragment ( baz ) are. HTTP / 1.1 302 Moved Temporarily Location : https://contacts.cozy.example.org/foo?bar# If the redirect parameter is invalid, the response will be 400 Bad Request . Same for other parameters, the redirection will happen only on success (even if OAuth2 says the authorization server can redirect on errors, it\u2019s very complicated to do it safely, and it is better to avoid this trap).", "title": "GET /auth/login"}, {"location": "cozy-stack/auth/#post-authlogin", "text": "After the user has typed her passphrase and clicked on Login , a request is made to this endpoint. The redirect parameter is passed inside the body. If it is missing, the redirection will be made against the default target: the home application of this cozy instance. The redirect can be a full URL (like http://cozy-drive.example.org/#/folder ), or just a slug+path+hash (like drive/#/folder ). POST /auth/login HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded passphrase=p4ssw0rd&redirect=https%3A%2F%2Fcontacts.cozy.example.org HTTP / 1.1 302 Moved Temporarily Set-Cookie : ... Location : https://contacts.cozy.example.org/foo When two-factor authentication (2FA) authentication is activated, this endpoint will not directly sent a redirection after this first passphrase step. In such case, a 200 OK response is sent along with a token value in the response (either in JSON if requested or directly in a new HTML form). Along with this token, a 2FA passcode is sent to the user via another transport (email for instance, depending on the user\u2019s preferences). Another request should be sent to /auth/twofactor with a valid pair (token, passcode) , ensuring that the user correctly entered its passphrase and received a fresh passcode by another mean.", "title": "POST /auth/login"}, {"location": "cozy-stack/auth/#post-authtwofactor", "text": "POST /auth/twofactor HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded two-factor-token=123123123123&two-factor-passcode=678678&redirect=https%3A%2F%2Fcontacts.cozy.example.org HTTP / 1.1 302 Moved Temporarily Set-Cookie : ... Location : https://contacts.cozy.example.org/foo", "title": "POST /auth/twofactor"}, {"location": "cozy-stack/auth/#post-authloginflagship", "text": "This endpoint is similar to POST /auth/login , but it allows the flagship app to also obtain OAuth access and register tokens without having to make the OAuth dance (which can be awkward for the user).", "title": "POST /auth/login/flagship"}, {"location": "cozy-stack/auth/#request", "text": "POST /auth/login/flagship HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" }", "title": "Request"}, {"location": "cozy-stack/auth/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg\" , \"scope\" : \"*\" } Note: if two-factor authentication is enabled on the Cozy, an email will be sent to the user with a code, and this request will return: HTTP / 1.1 401 Unauthorized Content-Type : application/json { \"two_factor_token\" : \"123123123123\" } Then, the client can retry by sending the two-factor token and code: { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"two_factor_token\" : \"123123123123\" , \"two_factor_code\" : \"123456\" } Note: if the two-factor authentication is enabled, and the cloudery has already verified the email address, a parameter email_verified_code can be sent to skip another 2FA code sent by mail. { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"email_verified_code\" : \"987456321\" } Note: if the OAuth client has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app.", "title": "Response"}, {"location": "cozy-stack/auth/#delete-authlogin", "text": "This can be used to log-out the user. An app token must be passed in the Authorization header, to protect against CSRF attack on this (this can part of bigger attacks like session fixation). DELETE /auth/login HTTP / 1.1 Host : cozy.example.org Cookie : seesioncookie.... Authorization : Bearer app-token", "title": "DELETE /auth/login"}, {"location": "cozy-stack/auth/#delete-authloginothers", "text": "This can be used to log-out all active sessions except the one used by the request. This allow to disconnect any other users currenctly authenticated on the system. An app token must be passed in the Authorization header, to protect against CSRF attack on this (this can part of bigger attacks like session fixation). DELETE /auth/login/others HTTP / 1.1 Host : cozy.example.org Cookie : seesioncookie.... Authorization : Bearer app-token", "title": "DELETE /auth/login/others"}, {"location": "cozy-stack/auth/#post-authmagic_link", "text": "If the authentication via magic link is enabled on this instance, this endpoint will send an email to the user with a magic link. If the user clicks on this link, they will be authenticated on the Cozy.", "title": "POST /auth/magic_link"}, {"location": "cozy-stack/auth/#get-authmagic_linkcode", "text": "When the user has received an email with a magic link, the link goes to the endpoint, where the user will be allowed to enter the Cozy.", "title": "GET /auth/magic_link?code=..."}, {"location": "cozy-stack/auth/#post-authmagic_linktwofactor", "text": "When two-factor authentication is enabled on a Cozy, this endpoint can be used to create a session.", "title": "POST /auth/magic_link/twofactor"}, {"location": "cozy-stack/auth/#post-authmagic_linkflagship", "text": "This endpoint allows the flagship app to also obtain OAuth access and register tokens without having to make the OAuth dance (which can be awkward for the user). It requires a code sent by email to the user.", "title": "POST /auth/magic_link/flagship"}, {"location": "cozy-stack/auth/#request_1", "text": "POST /auth/magic_link/flagship HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"magic_code\" : \"ODFhNzkxYTAtYjZiYi0wMTNiLTE1YzQtMThjMDRkYWJhMzI2\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" }", "title": "Request"}, {"location": "cozy-stack/auth/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg\" , \"scope\" : \"*\" } Note: if two-factor authentication is enabled on the Cozy, an email will be sent to the user with a code, and this request will return: HTTP / 1.1 401 Unauthorized Content-Type : application/json { \"error\" : \"passphrase is required as second authentication factor\" } Then, the client can retry by sending the two-factor token and code: { \"magic_code\" : \"ODFhNzkxYTAtYjZiYi0wMTNiLTE1YzQtMThjMDRkYWJhMzI2\" , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" } Note: if the OAuth client has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app.", "title": "Response"}, {"location": "cozy-stack/auth/#get-authpassphrase_reset", "text": "Display a form for the user to reset its password, in case he has forgotten it for example. If the user is connected, he won\u2019t be shown this form and he will be directly redirected to his cozy. This endpoint accepts a hideBackButton parameter. If this parameter is present and set to true then the passphrase reset page won\u2019t display any button to go back to the login page. This is useful when this page is opened in a different context from the one in which the login page was opened (e.g. a browser vs a mobile native application). It is also possible to use from=settings parameter in the query-string, to go back to the settings app after the password has been reset. It is useful when the user wants to change their email address, as the process for changing this address requires the password. GET /auth/passphrase_reset?hideBackButton=true HTTP / 1.1 Host : cozy.example.org Content-Type : text/html Cookie : ...", "title": "GET /auth/passphrase_reset"}, {"location": "cozy-stack/auth/#post-authhint", "text": "Send the password hint by email. POST /auth/hint HTTP / 1.1 Host : cozy.example.org", "title": "POST /auth/hint"}, {"location": "cozy-stack/auth/#post-authonboardingresend", "text": "Resend the activation link by email to finalize the onboarding. POST /auth/onboarding/resend HTTP / 1.1 Host : cozy.example.org", "title": "POST /auth/onboarding/resend"}, {"location": "cozy-stack/auth/#post-authpassphrase_reset", "text": "After the user has clicked on the reset button of the passphrase reset form, it will execute a request to this endpoint. This endpoint will create a token for the user to actually renew his passphrase. The token has a short-live duration of about 15 minutes. After the token is created, it is sent to the user on its mailbox. This endpoint will redirect the user on the login form page. POST /auth/passphrase_reset HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded csrf_token=123456890", "title": "POST /auth/passphrase_reset"}, {"location": "cozy-stack/auth/#get-authpassphrase_renew", "text": "Display a form for the user to enter a new password. This endpoint should be used with a token query parameter. This token makes sure that the user has actually reset its passphrase and should have been sent via its mailbox. GET /auth/passphrase_renew?token=123456789 HTTP / 1.1 Host : cozy.example.org Content-Type : text/html Cookie : ...", "title": "GET /auth/passphrase_renew"}, {"location": "cozy-stack/auth/#post-authpassphrase_renew", "text": "After the user has entered its new passphrase in the renew passphrase form, a request is made to this endpoint to renew the passphrase. This endpoint requires a valid token to actually work. In case of a success, the user is redirected to the login form. POST /auth/passphrase_reset HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded csrf_token=123456890&passphrase_reset_token=123456789&passphrase=mynewpassphrase", "title": "POST /auth/passphrase_renew"}, {"location": "cozy-stack/auth/#parameters", "text": "Form parameter Description passphrase_reset_token the token to authenticate the request csrf_token the token to protect against CSRF attacks passphrase the new password hint the hint to find again the password iterations the number of PBKDF2 iterations key the encrypted master key for bitwarden public_key the public key for the cozy organization private_key the private key for the cozy organization", "title": "Parameters"}, {"location": "cozy-stack/auth/#get-authpassphrase", "text": "This page renders a form to set the password for an onboarding instance. This endpoint expects a valid registerToken parameter. In case of success, the instance is marked as onboarded and the user is redirected to his home. If the instance is already onboarded, the user is redirected to his home. It is also possible to give a redirection parameter to redirect the user to another application. GET /auth/passphrase/?registerToken=e0fbe2c5b90cdcdd9b3487b48b480e0b&redirection=drive/%23/files HTTP / 1.1 Host : cozy.example.org Content-Type : text/html", "title": "GET /auth/passphrase"}, {"location": "cozy-stack/auth/#get-authconfirm", "text": "An application can ask the user to re-authenticate them-selves before making an important action (like erasing a pin code). To do that, the application will sent the user to this page where the stack will show a form. Two parameters in the query string can be sent: state (mandatory), which can be seen as an identifier for the confirmation redirect (optional), where the user will be redirected after the confirmation. GET /auth/confirm?state=51814f30-5818-0139-9348-543d7eb8149c&redirect=http://banks.cozy.localhost:8080/ HTTP / 1.1 The application can know the user has confirmed their identity by subscribing to a real-time event or by looking at the URL after the redirection. The URL must contain the state given by the app, and a code that can be checked by calling POST /auth/confirm/code (see below).", "title": "GET /auth/confirm"}, {"location": "cozy-stack/auth/#post-authconfirm", "text": "Send the hashed password for confirming the authentication.", "title": "POST /auth/confirm"}, {"location": "cozy-stack/auth/#redirection", "text": "HTTP / 1.1 302 Moved Temporarily Location : http://banks.cozy.localhost:8080/?state=51814f30-5818-0139-9348-543d7eb8149c&code=543d7eb8149c", "title": "Redirection"}, {"location": "cozy-stack/auth/#real-time-via-websockets", "text": "If it succeeds, a real-time event will be sent: client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.auth.confirmations\"}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"51814f30-5818-0139-9348-543d7eb8149c\", \"type\": \"io.cozy.auth.confirmations\"}}", "title": "Real-time via websockets"}, {"location": "cozy-stack/auth/#get-authconfirmcode", "text": "Send the code from the URL to check that the user has really confirmed their identity (and not just typed the URL them-self). GET /auth/confirm/543d7eb8149c HTTP / 1.1 The response will be a 204 No Content if the code is valid (and a 401 else).", "title": "GET /auth/confirm/:code"}, {"location": "cozy-stack/auth/#post-authregister", "text": "This route is used by OAuth2 clients to dynamically register them-selves. See OAuth 2.0 Dynamic Client Registration Protocol for the details. The client must send a JSON request, with at least: redirect_uris , an array of strings with the redirect URIs that the client will use in the authorization flow client_name , human-readable string name of the client to be presented to the end-user during authorization software_id , an identifier of the software used by the client (it should remain the same for all instances of the client software, whereas client_id varies between instances). It can also send the optional fields: client_kind (possible values: web, desktop, mobile, browser, etc.) client_uri , URL string of a web page providing information about the client logo_uri , to display an icon to the user in the authorization flow policy_uri , URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data software_version , a version identifier string for the client software. notification_platform , to activate notifications on the associated device, this field specify the platform used to send notifications: \"android\" : for Android devices with notifications via Firebase Cloud Messaging \"ios\" : for iOS devices with notifications via Firebase Cloud Messaging or APNS/2 \"huawei\" : for huawei devices with Push Kit notification_device_token , the token used to identify the mobile device for notifications. The server gives to the client the previous fields and these informations: client_id client_secret registration_access_token Example: POST /auth/register HTTP / 1.1 Host : cozy.example.org Content-Type : application/json Accept : application/json { \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.1\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" } HTTP / 1.1 201 Created Content-Type : application/json { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"client_secret_expires_at\" : 0 , \"registration_access_token\" : \"J9l-ZhwP[...omitted for brevity...]\" , \"grant_types\" : [ \"authorization_code\" , \"refresh_token\" ], \"response_types\" : [ \"code\" ], \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.1\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" }", "title": "POST /auth/register"}, {"location": "cozy-stack/auth/#linked-applications", "text": "Some OAuth applications are a mobile or desktop version of a Cozy webapp. For them, it\u2019s possible to use a special software_id to make a link between the mobile/desktop application and the webapp. The software_id must be in a registry://slug format, like registry://drive for Cozy-Drive for example. When it is the case, the mobile/desktop will share its permissions with the webapp. It means several things: The mobile/desktop app will have the same permissions that the linked webapp. When a sharing by link is done in the mobile/desktop application, the linked webapp will be able to revoke it later, and vice versa. When the user accepts to give access to its Cozy to the mobile/desktop app, the linked webapp will be installed on the Cozy if it was not already the case. When the linked webapp is uninstalled, the right to access the Cozy for the mobile/desktop app will be revoked.", "title": "Linked applications"}, {"location": "cozy-stack/auth/#get-authregisterclient-id", "text": "This route is used by the clients to get informations about them-selves. The client has to send its registration access token to be able to use this endpoint. See OAuth 2.0 Dynamic Client Registration Management Protocol for more details. GET /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer J9l-ZhwP... HTTP / 1.1 201 Created Content-Type : application/json { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"client_secret_expires_at\" : 0 , \"grant_types\" : [ \"authorization_code\" , \"refresh_token\" ], \"response_types\" : [ \"code\" ], \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.1\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" }", "title": "GET /auth/register/:client-id"}, {"location": "cozy-stack/auth/#put-authregisterclient-id", "text": "This route is used by the clients to update informations about them-selves. The client has to send its registration access token to be able to use this endpoint. Note: the client can ask to change its client_secret . To do that, it must send the current client_secret , and the server will respond with the new client_secret . PUT /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP / 1.1 Host : cozy.example.org Accept : application/json Content-Type : application/json Authorization : Bearer J9l-ZhwP... { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" , \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.2\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/client-logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" , \"notification_platform\" : \"android\" , \"notification_device_token\" : \"XXXXxxxx...\" } HTTP / 1.1 200 OK Content-Type : application/json { \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"IFais2Ah[...omitted for brevity...]\" , \"client_secret_expires_at\" : 0 , \"grant_types\" : [ \"authorization_code\" , \"refresh_token\" ], \"response_types\" : [ \"code\" ], \"redirect_uris\" : [ \"https://client.example.org/oauth/callback\" ], \"client_name\" : \"Client\" , \"software_id\" : \"github.com/example/client\" , \"software_version\" : \"2.0.2\" , \"client_kind\" : \"web\" , \"client_uri\" : \"https://client.example.org/\" , \"logo_uri\" : \"https://client.example.org/client-logo.svg\" , \"policy_uri\" : \"https://client/example.org/policy\" }", "title": "PUT /auth/register/:client-id"}, {"location": "cozy-stack/auth/#delete-authregisterclient-id", "text": "This route is used by the clients to unregister them-selves. The client has to send its registration access token to be able to use this endpoint. DELETE /auth/register/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3 HTTP / 1.1 Host : cozy.example.org Authorization : Bearer J9l-ZhwP... HTTP / 1.1 204 No Content", "title": "DELETE /auth/register/:client-id"}, {"location": "cozy-stack/auth/#post-authclientsclient-idchallenge", "text": "This route can be used to start the process for certifying that an app is really what it tells to be by using the android/iOS APIs (PlayIntegrity/SafetyNet/AppleAttestation). It returns a nonce that must be used in the certificate. The client must send its registration access token to use this endpoint. POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/challenge HTTP / 1.1 Host : cozy.example.org Authorization : Bearer J9l-ZhwP... HTTP / 1.1 201 Created Content-Type : application/json { \"nonce\" : \"MmE3OTM1ZDItNWY0ZC0xMWVjLTg3NT\" }", "title": "POST /auth/clients/:client-id/challenge"}, {"location": "cozy-stack/auth/#post-authclientsclient-idattestation", "text": "This route can be used to finish the process for certifying that an app is really what it tells to be by using the android/iOS APIs. The client can send its attestation. POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/attestation HTTP / 1.1 Host : cozy.example.org Content-Type : application/json { \"platform\" : \"android\" , \"challenge\" : \"MmE3OTM1ZDItNWY0ZC0xMWVjLTg3NT\" , \"attestation\" : \"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\" } Note: the platform parameter can be \"android\" or \"ios\" . For ios , a \"keyId\" parameter is also required. For android , the \"issuer\" can be \"playintegrity\" to use the Play Integrity API instead of the SafetyNet API. HTTP / 1.1 204 No Content", "title": "POST /auth/clients/:client-id/attestation"}, {"location": "cozy-stack/auth/#post-authclientsclient-idflagship", "text": "This route can be used to send a 6-digits code to manually certify a client as belonging to the flagship app. POST /auth/clients/64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3/flagship HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded code=123456&token=123123123123123 HTTP / 1.1 204 No Content", "title": "POST /auth/clients/:client-id/flagship"}, {"location": "cozy-stack/auth/#get-authauthorize", "text": "When an OAuth2 client wants to get access to the data of the cozy owner, it starts the OAuth2 dance with this step. The user is shown what the client asks and has an accept button if she is OK with that. In case a limit has been set on the Cozy to the number of user-connected OAuth clients, and this limit has been reached already, the user will be presented a screen requesting to either remove some existing clients or, if enabled, increase the limit (e.g. by subscribing to a plan with a greater limit). Once the number of connected clients is brought back under the limit, the OAuth flow will resume and the permissions screen will be displayed. The parameters are: client_id , that identify the client redirect_uri , it has to be exactly the same as the one used in registration state , it\u2019s a protection against CSRF on the client (a random string generated by the client, that it can check when the user will be redirected with the authorization code. It can be used as a key in local storage for storing a state in a SPA). response_type , only code is supported scope , a space separated list of the permissions asked (like io.cozy.files:GET for read-only access to files). GET /auth/authorize?client_id=oauth-client-1&response_type=code&scope=io.cozy.files%3AGET%20io.cozy.contacts&state=Eh6ahshepei5Oojo&redirect_uri=https%3A%2F%2Fclient.org%2F HTTP / 1.1 Host : cozy.example.org Note we warn the user that he is about to share his data with an application which only the callback URI is guaranteed.", "title": "GET /auth/authorize"}, {"location": "cozy-stack/auth/#pkce-extension", "text": "To improve security, the client can use the PKCE for OAuth 2 . In that case, two additional parameters must be send to GET /auth/authorize : code_challenge : the client creates a code_verifier , and then derive the code_challenge from it. code_challenge_method : it must be S256 (the only supported method). As a reminder, the relation between code_verifier and code_challenge is the following: code_challenge = BASE64URL-ENCODE(SHA256(code_verifier)) And, the code_verifier parameter must be sent to POST /auth/access_token (see below).", "title": "PKCE extension"}, {"location": "cozy-stack/auth/#post-authauthorize", "text": "When the user accepts, her browser send a request to this endpoint: POST /auth/authorize HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded state=Eh6ahshepei5Oojo&client_id=oauth-client-1&scope=io.cozy.files%3AGET%20io.cozy.contacts&csrf_token=johw6Sho&response_type=code&redirect_uri=https%3A%2F%2Fclient.org%2F Note : this endpoint is protected against CSRF attacks. The user is then redirected to the original client, with an access code in the URL: HTTP / 1.1 302 Moved Temporarily Location : https://client.org/?state=Eh6ahshepei5Oojo&code=Aih7ohth#", "title": "POST /auth/authorize"}, {"location": "cozy-stack/auth/#get-authauthorizesharing-post-authauthorizesharing", "text": "They are similar to /auth/authorize : they also make the user accept an OAuth thing, but it is specialized for sharing. They are a few differences, like the scope format (sharing rules, not permissions) and the redirection after the POST (with sharing= in the query string).", "title": "GET /auth/authorize/sharing & POST /auth/authorize/sharing"}, {"location": "cozy-stack/auth/#get-authauthorizemove-post-authauthorizemove", "text": "They are similar to /auth/authorize , but instead of a page that lists the permissions, the user will be asked to type their password to confirm the action (even if they are already logged-in). If the 2FA is activated, the code will be asked too. This strong action seems adequate for authorizing to erase the data in the Cozy before importing data from another Cozy.", "title": "GET /auth/authorize/move & POST /auth/authorize/move"}, {"location": "cozy-stack/auth/#request-get", "text": "GET /auth/authorize/move?state=8d560d60&client_id=oauth-client-2&redirect_uri=https://move.cozycloud.cc/callback/target HTTP / 1.1 Server : target.cozy.example", "title": "Request GET"}, {"location": "cozy-stack/auth/#response-get", "text": "HTTP / 1.1 200 OK Content-Type : application/html", "title": "Response GET"}, {"location": "cozy-stack/auth/#request-post", "text": "POST /auth/authorize/move HTTP / 1.1 Server : target.cozy.example Content-Type : application/x-www-form-urlencoded passphrase=hashed&state=8d560d60&client_id=oauth-client-2&csrf_token=johw6Sho&redirect_uri=https%3A%2F%2Fmove.cozycloud.cc%2Fcallback%2Ftarget", "title": "Request POST"}, {"location": "cozy-stack/auth/#response-post", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"redirect\" : \"https://move.cozycloud.cc/callback/target?code=543d7eb8149c&used=123456"a=5000000&state=8d560d60&vault=true\" }", "title": "Response POST"}, {"location": "cozy-stack/auth/#post-authaccess_token", "text": "Now, the client can check that the state is correct, and if it is the case, ask for an access_token . It can use this route with the code given above. This endpoint is also used to refresh the access token, by sending the refresh_token instead of the code . The parameters are: grant_type , with authorization_code or refresh_token as value code or refresh_token , depending on which grant type is used client_id client_secret Example: POST /auth/access_token HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded Accept : application/json grant_type=authorization_code&code=Aih7ohth&client_id=oauth-client-1&client_secret=Oung7oi5 HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"ooch1Yei\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"ui0Ohch8\" , \"scope\" : \"io.cozy.files:GET io.cozy.contacts\" }", "title": "POST /auth/access_token"}, {"location": "cozy-stack/auth/#post-authsession_code", "text": "This endpoint can be used by the flagship application in order to create a session code: this code can be added to the URL of a cozy application (in the query string, as session_code ) to create a session. The flagship can create this code with its access token, and then use it in a webview to avoid the reauthentication of the user. It can also create the code with the hashed passphrase (and 2FA if needed) to create a session for the authorize page. Note that the difference between a session_code and a magic_code (code in a magic link sent by email) is the behavior when two-factor authentication is enabled. The session_code will open the session while the magic_code will require the password for that.", "title": "POST /auth/session_code"}, {"location": "cozy-stack/auth/#request-access-token-variant", "text": "POST /auth/session_code HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer eyJpc3Mi...", "title": "Request (access token variant)"}, {"location": "cozy-stack/auth/#request-passphrase-variant", "text": "POST /auth/session_code HTTP / 1.1 Host : cozy.example.org Accept : application/json Content-Type : application/json { \"passphrase\" : \"hashed\" , \"two_factor_token\" : \"123123123123\" , \"two_factor_passcode\" : \"678678\" }", "title": "Request (passphrase variant)"}, {"location": "cozy-stack/auth/#response_2", "text": "HTTP / 1.1 201 Created Content-Type : application/json { \"session_code\" : \"HzEFM3JREpIB6532fQc1FP2t4YJKt3gI\" } The flagship will then be able to open a webview for https://cozy-home.example.org/?session_code=HzEFM3JREpIB6532fQc1FP2t4YJKt3gI .", "title": "Response"}, {"location": "cozy-stack/auth/#response-2fa-needed", "text": "In case of error where 2FA is needed, the response will be: HTTP / 1.1 403 Forbidden Content-Type : application/json { \"error\" : \"two factor needed\" , \"two_factor_token\" : \"123123123123\" }", "title": "Response (2FA needed)"}, {"location": "cozy-stack/auth/#faq", "text": "What format is used for tokens? The access tokens are formatted as JSON Web Tokens (JWT) , like this: Claim Fullname What it identifies aud Audience Identify the recipient where the token can be used (like access ) iss Issuer Identify the Cozy instance (its domain in fact) iat Issued At Identify when the token was issued (Unix timestamp) sub Subject Identify the client that can use the token scope Scope Identify the scope of actions that the client can accomplish The scope is used for permissions . Other tokens can be JWT with a similar formalism, or be a simple random value (when we want to have a clear revocation process). What happens when the user has lost her passphrase? She can reset it from the command-line, like this: $ cozy-stack instances reset-passphrase cozy.example.org ek0Jah1R A new password is generated and print in the console. Is two-factor authentication (2FA) possible? Yes, it\u2019s possible. Via the cozy-settings application, the two-factor authentication can be activated. Here is how it works in more details: On each connection, when the 2FA is activated, the user is asked for its passphrase first. When entering correct passphrase, the user is then asked for: a TOTP (Timebased One-Time password, RFC 6238) derived from a secret associated with the instance. a short term timestamped MAC with the same validity time-range and also derived from the same secret. The TOTP is valid for a time range of about 5 minutes. When sending a correct and still-valid pair (passcode, token) , the user is granted with authentication cookie. The passcode can be sent to the instance\u2019s owner via email \u2014 more transport shall be added later.", "title": "FAQ"}, {"location": "cozy-stack/auth/#post-authtokenskonnectorsslug", "text": "This endpoint can be used by the flagship application in order to create a token for the konnector with the given slug. This token can then be used by the client-side konnector to make requests to cozy-stack. The flagship app will need to use its own access token to request the konnector token.", "title": "POST /auth/tokens/konnectors/:slug"}, {"location": "cozy-stack/auth/#request_2", "text": "POST /auth/tokens/konnectors/impots HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer eyJpc3Mi...", "title": "Request"}, {"location": "cozy-stack/auth/#response_3", "text": "HTTP / 1.1 201 Created Content-Type : application/json \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\"", "title": "Response"}, {"location": "cozy-stack/auth/#post-authshare-by-linkpassword", "text": "This route is used when a share by link is protected by password. The password can be sent to this route to create a cookie that will allow to use the sharecode and access the shared page.", "title": "POST /auth/share-by-link/password"}, {"location": "cozy-stack/auth/#request_3", "text": "POST /auth/clients/share-by-link/password HTTP / 1.1 Host : cozy.example.org Content-Type : application/x-www-form-urlencoded password=HelloWorld!&perm_id=123456789", "title": "Request"}, {"location": "cozy-stack/auth/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/json Set-Cookie : pass123... { \"password\" : \"ok\" }", "title": "Response"}, {"location": "cozy-stack/auth/#faq_1", "text": "What format is used for tokens? The access tokens are formatted as JSON Web Tokens (JWT) , like this: Claim Fullname What it identifies aud Audience Identify the recipient where the token can be used (i.e. konn ) iss Issuer Identify the Cozy instance (its domain in fact) iat Issued At Identify when the token was issued (Unix timestamp) sub Subject Identify the client that can use the token (i.e. the konnector slug) scope Scope Konnector tokens don\u2019t have any scope", "title": "FAQ"}, {"location": "cozy-stack/auth/#client-side-apps", "text": "Important : OAuth2 is not used here! The steps looks similar (like obtaining a token), but when going in the details, it doesn\u2019t match.", "title": "Client-side apps"}, {"location": "cozy-stack/auth/#how-to-register-the-application", "text": "The application is registered at install. See app management for details.", "title": "How to register the application?"}, {"location": "cozy-stack/auth/#how-to-get-a-token", "text": "When a user access an application, she first loads the HTML page. Inside this page, a token specific to this app is injected (only for private routes), via a templating method. We have prefered our custom solution to the implicit grant type of OAuth2 for 2 reasons: It has a better User Experience. The implicit grant type works with 2 redirections (the application to the stack, and then the stack to the application), and the first one needs JS to detect if the token is present or not in the fragment hash. It has a strong impact on the time to load the application. The implicit grant type of OAuth2 has a severe drawback on security: the token appears in the URL and is shown by the browser. It can also be leaked with the HTTP Referer header. The token will be given only for the authenticated user. For nested subdomains (like calendar.joe.example.net ), the session cookie from the stack is enough (it is for .joe.example.net ). But for flat subdomains (like joe-calendar.example.net ), it\u2019s more complicated. On the first try of the user, she will be redirected to the stack. As she is already logged-in, she will be redirected to the app with a session code (else she can login). This session code can be exchanged to a session cookie. A redirection will still happen to remove the code from the URL (it helps to avoid the code being saved in the browser history). For security reasons, the session code have the following properties: It can only be used once. It is tied to an application ( calendar in our example). It has a very short time span of validity (1 minute).", "title": "How to get a token?"}, {"location": "cozy-stack/auth/#how-to-use-a-token", "text": "The token can be sent to the cozy-stack as a Bearer token in the Authorization header, like this: GET /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Host : cozy.example.org Authorization : Bearer application-token If the user is authenticated, her cookies will be sent automatically. The cookies are needed for a token to be valid.", "title": "How to use a token?"}, {"location": "cozy-stack/auth/#how-to-refresh-a-token", "text": "The token is valid only for 24 hours. If the application is opened for more than that, it will need to get a new token. But most applications won\u2019t be kept open for so long and it\u2019s okay if they don\u2019t try to refresh tokens. At worst, the user just had to reload its page and it will work again. The app can know it\u2019s time to get a new token when the stack starts sending 401 Unauthorized responses. In that case, it can fetches the same html page that it was loaded initially, parses it and extracts the new token.", "title": "How to refresh a token?"}, {"location": "cozy-stack/auth/#third-party-websites", "text": "", "title": "Third-party websites"}, {"location": "cozy-stack/auth/#how-to-register-the-application_1", "text": "If a third-party websites would like to access a cozy, it had to register first. For example, a big company can have data about a user and may want to offer her a way to get her data back in her cozy. When the user is connected on the website of this company, she can give her cozy address. The website will then register on this cozy, using the OAuth2 Dynamic Client Registration Protocol, as explained above .", "title": "How to register the application?"}, {"location": "cozy-stack/auth/#how-to-get-a-token_1", "text": "To get an access token, it\u2019s enough to follow the authorization code flow of OAuth2: sending the user to the cozy, on the authorize page if the user approves, she is then redirected back to the client the client gets the access code and can exchange it to an access token.", "title": "How to get a token?"}, {"location": "cozy-stack/auth/#how-to-use-a-token_1", "text": "The access token can be sent as a bearer token, in the Authorization header of HTTP: GET /data/io.cozy.contacts/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Host : cozy.example.org Accept : application/json Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ", "title": "How to use a token?"}, {"location": "cozy-stack/auth/#how-to-refresh-a-token_1", "text": "The access token will be valid only for 24 hours. After that, a new access token must be asked. To do that, just follow the refresh token flow, as explained above .", "title": "How to refresh a token?"}, {"location": "cozy-stack/auth/#devices-and-browser-extensions", "text": "For devices and browser extensions, it is nearly the same than for third-party websites. The main difficulty is the redirect_uri. In OAuth2, the access code is given to the client by redirecting the user to an URL controlled by the client. But devices and browser extensions don\u2019t have an obvious URL for that. The IETF has published an RFC called OAuth 2.0 for Native Apps .", "title": "Devices and browser extensions"}, {"location": "cozy-stack/auth/#native-apps-on-desktop", "text": "A desktop native application can start an embedded webserver on localhost. The redirect_uri will be something like http://127.0.0.1:19856/callback .", "title": "Native apps on desktop"}, {"location": "cozy-stack/auth/#native-apps-on-mobile", "text": "On mobile, the native apps can often register a custom URI scheme, like com.example.oauthclient:/ . Just be sure that no other app has registered itself with the same URI.", "title": "Native apps on mobile"}, {"location": "cozy-stack/auth/#chrome-extensions", "text": "Chrome extensions can use URL like https://.chromiumapp.org/ for their usage. See https://developer.chrome.com/apps/app_identity#non for more details. It has also a method to simplify the creation of such an URL: chrome.identity.getRedirectURL .", "title": "Chrome extensions"}, {"location": "cozy-stack/auth/#firefox-extensions", "text": "It is possible to use an out of band URN: urn:ietf:wg:oauth:2.0:oob:auto . The token is then extracted from the title of the page. See this addon for google oauth2 as an example.", "title": "Firefox extensions"}, {"location": "cozy-stack/auth/#security-considerations", "text": "The master password, the password known by the user, is derived on the clients to give two keys. The first key is used to login on the stack, the second key is used to do client-side encryption. The derivation for the login password is currently done with the PBKDF2 algorithm (with SHA256), but we have anticipated the possibility of changing to another algorithm if desirable. The derived password is stored on the server in a secure fashion, with a password hashing function. The hashing function and its parameter are stored with the hash, in order to make it possible to change the algorithm and/or the parameters later if we had any suspicion that it became too weak. The initial algorithm is scrypt . The access code is valid only once, and will expire after 5 minutes Dynamically registered applications won\u2019t have access to all possible scopes. For example, an application that has been dynamically registered can\u2019t ask the cozy owner to give it the right to install other applications. This limitation should improve security, as avoiding too powerful scopes to be used with unknown applications. The cozy stack will apply rate limiting to avoid brute-force attacks. The cozy stack offers CORS for most of its services. But it\u2019s disabled for /auth (it doesn\u2019t make sense here) and for the client-side applications (to avoid leaking their tokens). The client should really use HTTPS for its redirect_uri parameter, but it\u2019s allowed to use HTTP for localhost, as in the native desktop app example. OAuth2 says that the state parameter is optional in the authorization code flow. But it is mandatory to use it with Cozy. For more on this subject, here is a list of links: https://www.owasp.org/index.php/Authentication_Cheat_Sheet https://tools.ietf.org/html/rfc6749#page-53 https://tools.ietf.org/html/rfc6819 https://tools.ietf.org/html/draft-ietf-oauth-closing-redirectors-00 http://www.oauthsecurity.com/", "title": "Security considerations"}, {"location": "cozy-stack/auth/#conclusion", "text": "Security is hard. If you want to share some concerns with us, do not hesitate to send us an email to security AT cozycloud.cc.", "title": "Conclusion"}, {"location": "cozy-stack/bitwarden/", "text": "Table of contents Bitwarden \u00b6 Cozy-stack exposes an API compatible with Bitwarden on /bitwarden . The author of the unofficial Bitwarden-ruby server did some reverse engineering and wrote a short API documentation . Setup \u00b6 The signup is disabled, there is one account per Cozy instance, with the email me@ . When the user chooses his/her password (onboarding), an encryption key is also generated to keep safe the secrets in the bitwarden vault. A cozy organization is also created: it will be used to share some passwords with the stack, to be used for the konnectors. The bitwarden clients can connect to the cozy-stack APIs by setting their URL to https:///bitwarden . Routes for accounts and connect \u00b6 POST /bitwarden/api/accounts/prelogin & POST /bitwarden/identity/accounts/prelogin \u00b6 It allows the client to know the number of KDF iterations to apply when hashing the master password. It can also tell if the login via OIDC is mandatory, if the vault is empty (when both conditions are true, the onboarding process is a bit different), and if flat or nested subdomains are used. There are 2 routes for the same endpoint, as Bitwarden has moved from the first to the second, and we want to ensure a smooth migration for clients. Request \u00b6 POST /bitwarden/identity/accounts/prelogin HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"email\" : \"me@alice.example.com\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Kdf\" : 0 , \"KdfIterations\" : 10000 , \"OIDC\" : false , \"HasCiphers\" : true , \"FlatSubdomains\" : true } POST /bitwarden/identity/connect/token \u00b6 Request (initial connection) \u00b6 POST /bitwarden/identity/connect/token HTTP / 1.1 Host : alice.example.com Content-Type : application/x-www-form-urlencoded grant_type=password& username=me@alice.example.com& password=r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=& scope=api offline_access& client_id=browser& deviceType=3& deviceIdentifier=aac2e34a-44db-42ab-a733-5322dd582c3d& deviceName=firefox& clientName=Cozy& devicePushToken= If authentication with two factors is enabled on the instance and the user not logged through a web session, this request will fail with a 400 status, but it will send an email with the code. The request can be retried with an additional paramter: twoFactorToken . Note: the clientName parameter is optional, and is not sent by the official bitwarden clients (a default value is used). Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"client_id\" : \"f05671e159450b44d5c78cebbd0260b5\" , \"registration_access_token\" : \"J9l-ZhwP[...omitted for brevity...]\" , \"access_token\" : \"eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)\" , \"expires_in\" : 3600 , \"token_type\" : \"Bearer\" , \"refresh_token\" : \"28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf\" , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null } Request (refresh token) \u00b6 POST /bitwarden/identity/connect/token HTTP / 1.1 Host : alice.example.com Content-Type : application/x-www-form-urlencoded grant_type=refresh_token& client_id=browser& refresh_token=28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)\" , \"expires_in\" : 3600 , \"token_type\" : \"Bearer\" , \"refresh_token\" : \"28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf\" , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" } POST /bitwarden/api/accounts/password-hint \u00b6 Request \u00b6 POST /bitwarden/api/accounts/password-hint HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"email\" : \"me@alice.example.com\" } Response \u00b6 HTTP / 1.1 200 OK GET /bitwarden/api/accounts/profile \u00b6 Request \u00b6 GET /bitwarden/api/accounts/profile HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : null , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [], \"Object\" : \"profile\" } PUT /bitwarden/api/accounts/profile \u00b6 This route allows to change the profile (currently, only the hint for the master password). It can also be called with a POST (I think it is used by the web vault). Request \u00b6 PUT /bitwarden/api/accounts/profile HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"masterPasswordHint\" : \"blah blah blah\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : \"blah blah blah\" , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [], \"Object\" : \"profile\" } POST /bitwarden/api/accounts/keys \u00b6 This route is used to save a key pair (public and private keys), to be used with organizations. Request \u00b6 POST /bitwarden/api/accounts/keys HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"encryptedPrivateKey\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"publicKey\" : \"MIIBIjANBgkqhkiG9w...AQAB\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : null , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [], \"Object\" : \"profile\" } POST /bitwarden/api/accounts/security-stamp \u00b6 It allows to set a new security stamp, which has the effect to disconnect all the clients. It can be used, for example, if the encryption key is changed to avoid the clients to corrupt the vault with ciphers encrypted with the old key. Request \u00b6 POST /bitwarden/api/accounts/security-stamp HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"masterPasswordHash\" : \"r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=\" } Response \u00b6 HTTP / 1.1 204 No Content GET /bitwarden/api/accounts/revision-date \u00b6 It returns the date of the last change on the server, as a number of milliseconds since epoch (sic). It is used by the clients to know if they have to do a sync or if they are already up-to-date. Request \u00b6 GET /bitwarden/api/accounts/revision-date HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK 1569571388892 PUT /bitwarden/api/settings/domains \u00b6 This route is also available via a POST , for compatibility with the web vault. Request \u00b6 PUT /bitwarden/api/settings/domains HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"equivalentDomains\" : [ [ \"stackoverflow.com\" , \"serverfault.com\" , \"superuser.com\" ] ], \"globalEquivalentDomains\" : [ 42 , 69 ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"EquivalentDomains\" : [ [ \"stackoverflow.com\" , \"serverfault.com\" , \"superuser.com\" ] ], \"GlobalEquivalentDomains\" : [ { \"Type\" : 2 , \"Domains\" : [ \"ameritrade.com\" , \"tdameritrade.com\" ], \"Excluded\" : false }, { \"Type\" : 3 , \"Domains\" : [ \"bankofamerica.com\" , \"bofa.com\" , \"mbna.com\" , \"usecfo.com\" ], \"Excluded\" : false }, { \"Type\" : 42 , \"Domains\" : [ \"playstation.com\" , \"sonyentertainmentnetwork.com\" ], \"Excluded\" : true }, { \"Type\" : 69 , \"Domains\" : [ \"morganstanley.com\" , \"morganstanleyclientserv.com\" ], \"Excluded\" : true } ], \"Object\" : \"domains\" } GET /bitwarden/api/settings/domains \u00b6 Request \u00b6 GET /bitwarden/api/settings/domains HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"EquivalentDomains\" : [ [ \"stackoverflow.com\" , \"serverfault.com\" , \"superuser.com\" ] ], \"GlobalEquivalentDomains\" : [ { \"Type\" : 2 , \"Domains\" : [ \"ameritrade.com\" , \"tdameritrade.com\" ], \"Excluded\" : false }, { \"Type\" : 3 , \"Domains\" : [ \"bankofamerica.com\" , \"bofa.com\" , \"mbna.com\" , \"usecfo.com\" ], \"Excluded\" : false }, { \"Type\" : 42 , \"Domains\" : [ \"playstation.com\" , \"sonyentertainmentnetwork.com\" ], \"Excluded\" : true }, { \"Type\" : 69 , \"Domains\" : [ \"morganstanley.com\" , \"morganstanleyclientserv.com\" ], \"Excluded\" : true } ], \"Object\" : \"domains\" } Route for sync \u00b6 GET /bitwarden/api/sync \u00b6 The main action of the client is a one-way sync, which just fetches all objects from the server and updates its local database. Request \u00b6 GET /bitwarden/api/sync HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Profile\" : { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : null , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [ { \"Id\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Name\" : \"Cozy\" , \"Key\" : \"4.HUzVDQVAFc4JOpW3/j/QwZeET0mXOiDW5s/HdpxLZ2GFnGcxOm1FE4XD2p7XTSwORXO/Lo8y0A87UhXKEXzfHZmpJR04pbpUPr4NJbjRKv/cSkNFlvm0rIUw/m0Jkft/gew9v3QfkVSGdSZk5XIimwkTQ5WM+WCStxbQJIKAH+AoEA5q6t9mpNNlTAQvMgqs8u7CJwSjeZ7qbabfEUVX1HIPgxC3BtVUkySRSws/gUNeMwY23kAJJQYT+uuMooZUr7umU6YkEHG2RQZwCCjVHX4czxZRWsVo/xQOYoNr7DjgCf92D7OrJlFmDtQjzSy2BjotN6vn+1SwtHbeDILWaQ==\" , \"BillingEmail\" : \"me@cozy.localhost\" , \"Plan\" : \"TeamsAnnually\" , \"PlanType\" : 5 , \"Seats\" : 2 , \"MaxCollections\" : 1 , \"MaxStorageGb\" : 1 , \"SelfHost\" : true , \"Use2fa\" : true , \"UseDirectory\" : false , \"UseEvents\" : false , \"UseGroups\" : false , \"UseTotp\" : true , \"UsersGetPremium\" : true , \"Enabled\" : true , \"Status\" : 2 , \"Type\" : 2 , \"Object\" : \"profileOrganization\" } ], \"Object\" : \"profile\" }, \"Folders\" : [ { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.tqb+y2z4ChCYHj4romVwGQ==|E8+D7aR5CNnd+jF7fdb9ow==|wELCxyy341G2F+w8bTb87PAUi6sdXeIFTFb4N8tk3E0=\" , \"RevisionDate\" : \"2017-11-13T16:20:56.5633333\" , \"Object\" : \"folder\" } ], \"Ciphers\" : [ { \"FolderId\" : null , \"Favorite\" : false , \"Edit\" : true , \"Id\" : \"0f01a66f-7802-42bc-9647-a82600f11e10\" , \"OrganizationId\" : null , \"Type\" : 1 , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.6DmdNKlm3a+9k/5DFg+pTg==|7q1Arwz/ZfKEx+fksV3yo0HMQdypHJvyiix6hzgF3gY=|7lSXqjfq5rD3/3ofNZVpgv1ags696B2XXJryiGjDZvk=\" , \"Match\" : null } ], \"Username\" : \"2.4Dwitdv4Br85MABzhMJ4hg==|0BJtHtXbfZWwQXbFcBn0aA==|LM4VC+qNpezmub1f4l1TMLDb9g/Q+sIis2vDbU32ZGA=\" , \"Password\" : \"2.OOlWRBGib6G8WRvBOziKzQ==|Had/obAdd2/6y4qzM1Kc/A==|LtHXwZc5PkiReFhkzvEHIL01NrsWGvintQbmqwxoXSI=\" , \"Totp\" : null }, \"Name\" : \"2.zAgCKbTvGowtaRn1er5WGA==|oVaVLIjfBQoRr5EvHTwfhQ==|lHSTUO5Rgfkjl3J/zGJVRfL8Ab5XrepmyMv9iZL5JBE=\" , \"Notes\" : \"2.NLkXMHtgR8u9azASR4XPOQ==|6/9QPcnoeQJDKBZTjcBAjVYJ7U/ArTch0hUSHZns6v8=|p55cl9FQK/Hef+7yzM7Cfe0w07q5hZI9tTbxupZepyM=\" , \"Fields\" : null , \"Attachments\" : null , \"OrganizationUseTotp\" : false , \"RevisionDate\" : \"2017-11-09T14:37:52.9033333\" , \"Object\" : \"cipher\" } ], \"Collections\" : [ { \"Id\" : \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" , \"OrganizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Name\" : \"2.PowfE263ZLz7+Jqrpuezqw==|OzuXDsJnQdfa/eMKxsms6Q==|RpEB7qqs26X9dqa+KaxSE5+52TFVs4dAdfU7DCu3QXM=\" , \"Object\" : \"collection\" , \"ReadOnly\" : false } ], \"Domains\" : { \"EquivalentDomains\" : null , \"GlobalEquivalentDomains\" : null , \"Object\" : \"domains\" }, \"Object\" : \"sync\" } Routes for ciphers \u00b6 GET /bitwarden/api/ciphers \u00b6 It retrieves the list of ciphers. Request \u00b6 GET /bitwarden/api/ciphers HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } ], \"Object\" : \"list\" } POST /bitwarden/api/ciphers \u00b6 When a new item (login, secure note, etc.) is created on a device, it is sent to the server with its fields encrypted via this route. Request \u00b6 POST /bitwarden/api/ciphers HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"type\" : 1 , \"favorite\" : false , \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"folderId\" : null , \"organizationId\" : null , \"notes\" : null , \"login\" : { \"uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"totp\" : null } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } POST /bitwarden/api/ciphers/create \u00b6 This route also allows to create a cipher, but this time, it is for a cipher shared with an organization. Request \u00b6 POST /bitwarden/api/ciphers/create HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"cipher\" : { \"type\" : 1 , \"favorite\" : false , \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"folderId\" : null , \"organizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"notes\" : null , \"login\" : { \"uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"totp\" : null } }, \"collectionIds\" : [ \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } GET /bitwarden/api/ciphers/:id and /bitwarden/api/ciphers/:id/details \u00b6 Request \u00b6 GET /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } PUT /bitwarden/api/ciphers/:id \u00b6 This route is used to change a cipher. It can also be called via POST /bitwarden/api/ciphers/:id (I think it is used by the web vault). Request \u00b6 PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"type\" : 2 , \"favorite\" : true , \"name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"folderId\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"organizationId\" : null , \"notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"secureNote\" : { \"type\" : 0 } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 2 , \"Favorite\" : true , \"Name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"FolderId\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"OrganizationId\" : null , \"Notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"SecureNote\" : { \"Type\" : 0 }, \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } POST /bitwarden/api/ciphers/:id/share \u00b6 This route is used to share a cipher with an organization. The fields must be encrypted with the organization key. Request \u00b6 POST /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/share HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"cipher\" : { \"type\" : 2 , \"favorite\" : true , \"name\" : \"2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=\" , \"organizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"notes\" : \"2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=\" , \"secureNote\" : { \"type\" : 0 } }, \"collectionIds\" : [ \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 2 , \"Favorite\" : true , \"Name\" : \"2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=\" , \"OrganizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Notes\" : \"2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=\" , \"SecureNote\" : { \"Type\" : 0 }, \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } DELETE /bitwarden/api/ciphers/:id \u00b6 This route is used to delete a cipher. It can also be called via POST /bitwarden/api/ciphers/:id/delete (I think it is used by the web vault). Request \u00b6 DELETE /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK DELETE /bitwarden/api/ciphers \u00b6 This route is used to delete ciphers in bulk. It can also be called via POST /bitwarden/api/ciphers/delete . Request \u00b6 DELETE /bitwarden/api/ciphers HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ids\" : [ \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"205c22f0-8642-0139-c874-543d7eb8149c\" ] } Response \u00b6 HTTP / 1.1 200 OK PUT /bitwarden/api/ciphers/:id/delete \u00b6 This route is used to soft delete a cipher, by adding a deletedDate attribute on it. Request \u00b6 PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/delete HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 204 No Content PUT /bitwarden/api/ciphers/delete \u00b6 This route is used to soft delete ciphers in bulk. Request \u00b6 PUT /bitwarden/api/ciphers/delete HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ids\" : [ \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"205c22f0-8642-0139-c874-543d7eb8149c\" ] } Response \u00b6 HTTP / 1.1 200 OK PUT /bitwarden/api/ciphers/:id/restore \u00b6 This route is used to restore a soft-deleted cipher, by removing the deletedDate attribute. Request \u00b6 PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/restore HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 204 No Content PUT /bitwarden/api/ciphers/restore \u00b6 This route is used to restore ciphers in bulk. Request \u00b6 PUT /bitwarden/api/ciphers/restore HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ids\" : [ \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"205c22f0-8642-0139-c874-543d7eb8149c\" ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2021-04-23T12:58:01Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false }, { \"Object\" : \"cipher\" , \"Id\" : \"205c22f0-8642-0139-c874-543d7eb8149c\" , \"Type\" : 2 , \"Favorite\" : true , \"Name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"RevisionDate\" : \"2021-04-23T12:58:01Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } ], \"Object\" : \"list\" } POST /bitwarden/api/ciphers/import \u00b6 This route can be used to import several ciphers and folders in bulk. In folderRelationships , the key is the index of the cipher in the ciphers list, and the value is the index of the folder in the folders list. Request \u00b6 POST /bitwarden/api/ciphers/import HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ciphers\" : [{ \"type\" : 2 , \"favorite\" : true , \"name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"folderId\" : null , \"organizationId\" : null , \"notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"secureNote\" : { \"type\" : 0 } }, { \"type\" : 1 , \"favorite\" : false , \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"folderId\" : null , \"organizationId\" : null , \"notes\" : null , \"login\" : { \"uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"totp\" : null } }], \"folders\" : [{ \"name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" }], \"folderRelationships\" : [ { \"key\" : 1 , \"value\" : 0 } ] } Response \u00b6 HTTP / 1.1 204 No Content Routes for folders \u00b6 GET /bitwarden/api/folders \u00b6 It retrieves the list of folders. Request \u00b6 GET /bitwarden/api/folders HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" } ], \"Object\" : \"list\" } POST /bitwarden/api/folders \u00b6 It adds a new folder on the server. The name is encrypted on client-side. Request \u00b6 POST /bitwarden/api/folders HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" } GET /bitwarden/api/folders/:id \u00b6 Request \u00b6 GET /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" } PUT /bitwarden/api/folders/:id \u00b6 This route is used to rename a folder. It can also be called via POST /bitwarden/api/folders/:id (I think it is used by the web vault). Request \u00b6 PUT /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" } DELETE /bitwarden/api/folders/:id \u00b6 This route is used to delete a folder. It can also be called via POST /bitwarden/api/folders/:id/delete (I think it is used by the web vault). Request \u00b6 DELETE /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Organizations and Collections \u00b6 GET /bitwarden/organizations/cozy \u00b6 This route can be used to get information about the Cozy Organization. It requires a permission on the whole com.bitwarden.organizations doctype to access it. In particular, it gives the key to encrypt/decrypt the ciphers in this organization (encoded in base64). Request \u00b6 GET /bitwarden/organizations/cozy HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"organizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"collectionId\" : \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" , \"organizationKey\" : \"oWeRYokoCMFsAja6lrp3RQ1PYOrex4tgAMECP4nX+a4IXdijbejQscvWqy9bMgLsX0HRc2igqBRMWdsPuFK0PQ==\" } POST /bitwarden/api/organizations \u00b6 This route can be used to create an organization, with a collection. Request \u00b6 POST /bitwarden/api/organizations HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"name\" : \"Family\" , \"key\" : \"4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=\" , \"collectionName\" : \"2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M=\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"724db920-cc4b-0139-6ab2-543d7eb8149c\" , \"Name\" : \"Family\" , \"Key\" : \"4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=\" , \"BillingEmail\" : \"me@cozy.localhost\" , \"Plan\" : \"TeamsAnnually\" , \"PlanType\" : 9 , \"Seats\" : 10 , \"MaxCollections\" : 1 , \"MaxStorageGb\" : 1 , \"SelfHost\" : true , \"Use2fa\" : true , \"UseDirectory\" : false , \"UseEvents\" : false , \"UseGroups\" : false , \"UseTotp\" : true , \"UseApi\" : false , \"UsePolicies\" : false , \"UseSSO\" : false , \"UseResetPass\" : false , \"HasPublicAndPrivateKeys\" : false , \"ResetPasswordEnrolled\" : false , \"UsersGetPremium\" : true , \"Enabled\" : true , \"Status\" : 2 , \"Type\" : 2 , \"Object\" : \"profileOrganization\" } GET /bitwarden/api/organizations/:id \u00b6 This route can be used to fetch information about an organization. Request \u00b6 GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"724db920-cc4b-0139-6ab2-543d7eb8149c\" , \"Name\" : \"Family\" , \"Key\" : \"4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=\" , \"BillingEmail\" : \"me@cozy.localhost\" , \"Plan\" : \"TeamsAnnually\" , \"PlanType\" : 9 , \"Seats\" : 10 , \"MaxCollections\" : 1 , \"MaxStorageGb\" : 1 , \"SelfHost\" : true , \"Use2fa\" : true , \"UseDirectory\" : false , \"UseEvents\" : false , \"UseGroups\" : false , \"UseTotp\" : true , \"UseApi\" : false , \"UsePolicies\" : false , \"UseSSO\" : false , \"UseResetPass\" : false , \"HasPublicAndPrivateKeys\" : false , \"ResetPasswordEnrolled\" : false , \"UsersGetPremium\" : true , \"Enabled\" : true , \"Status\" : 2 , \"Type\" : 2 , \"Object\" : \"profileOrganization\" } GET /bitwarden/api/organizations/:id/collections \u00b6 This route can be used to fetch information about the collections inside an organization. Request \u00b6 GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/collections HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Id\" : \"62080a40-d75d-0139-21f1-543d7eb8149c\" , \"OrganizationId\" : \"724db920-cc4b-0139-6ab2-543d7eb8149c\" , \"Name\" : \"2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M=\" , \"Object\" : \"collection\" } ], \"Object\" : \"list\" } DELETE /bitwarden/api/organizations/:id \u00b6 This route can be used to delete an organization by its owner. Request \u00b6 DELETE /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"masterPasswordHash\" : \"r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=\" } Response \u00b6 HTTP / 1.1 200 OK GET /bitwarden/api/organizations/:id/users \u00b6 This route returns the list of users in the given organization. Request \u00b6 GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Object\" : \"organizationUserUserDetails\" , \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"UserId\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Type\" : 0 , \"Status\" : 2 , \"AccessAll\" : true , \"Name\" : \"Alice\" , \"Email\" : \"alice@example.com\" }, { \"Object\" : \"organizationUserUserDetails\" , \"Id\" : \"89d99af0db1c0139605b543d7eb8149c\" , \"UserId\" : \"89d99af0db1c0139605b543d7eb8149c\" , \"Type\" : 2 , \"Status\" : 1 , \"AccessAll\" : true , \"Name\" : \"Bob\" , \"Email\" : \"bob@example.com\" } ], \"Object\" : \"list\" } POST /bitwarden/api/organizations/:id/users/:user-id/confirm \u00b6 This route is used by the owner of an organization to confirm that another user can use this sharing. The caller must check the fingerprint of the new member and encrypt the organization key with their public key. Request \u00b6 POST /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users/89d99af0db1c0139605b543d7eb8149c/confirm HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"key\" : \"4.UT/TVY6qmAjNdax2WT9JcA97wSWvEudAlqpjfxrFUieOoGA88MxzbYjpCXajEST/PehD1I7KC93jwthng772extu+lLHSd/Ce+a5Qw8+pRxL7je8QgS8gmP0FhfRLc4bl5hUMTfQcUDiuiiNaDez6E9czOzk9iuVaGpEjK4YAYgQy25m3eGc+DTPv8206NJZ/lr8CpPyhwUHjtDhlOZnDWAf+a28x2EAj1ogZKKJGAUcRENitV8Joa7OGRO6dmxtTTnWOuPDk5DajGgzpIQURNuotVHcpBtCL8HzNAduQ9vtrPKJtyAsHRdjau2SwEnaLZmxAvp7d9VG3t5nDYtgWA==\" } Response \u00b6 HTTP / 1.1 200 OK GET /bitwarden/api/users/:id/public-key \u00b6 This route gives the public key of a user. Request \u00b6 GET /bitwarden/api/users/89d99af0db1c0139605b543d7eb8149c/public-key HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"UserId\" : \"89d99af0db1c0139605b543d7eb8149c\" , \"PublicKey\" : \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1LwbnLsT8w2OBPR/zy/zRQNH+jZzD6v4qUGAJg0NfoUkBSgtq9yjor2GgeRtdf8VuNTn1kcNrUIU4f9vE3ppNJgmUss4O29OP9/ATqtC/4ri4UCWTV0DPCF4gRU1SbgTg9O3yC2UYWmrs47SgU0wwT+f5AjfDC7GzhjyX68UYIIIeKSMZasjcy+wIPVAW0hYhcEoK3Coq2O1wVwM+b2fXPIMzn38onUTbMCrkVY+FzGg6NtZbKzPvVZ0iyfQ6BxvttqSViNPOpyz7gryDhgYKokV+kwj5ARDZWL6ml73U2lL7uapk5meNKZf8w7TJGepFiewGLm08VMht6lnIZBuDQIDAQAB\" } DELETE /bitwarden/contacts/:id \u00b6 This route can be used to refuse to give access to a user to shared ciphers. The contact will be deleted, and they will be revoked from all sharings. Request \u00b6 GET /bitwarden/contacts/89d99af0db1c0139605b543d7eb8149c HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 204 No-Content Icons \u00b6 GET /bitwarden/icons/:domain/icon.png \u00b6 This route returns an icon for the given domain, that can be used by the bitwarden clients. No authorization token is required. If no favicon has been found for the domain, a fallback will be used, depending of the fallback parameter in the query-string: default : a default icon is returned 404 : just a 404 - Not found error. Request \u00b6 GET /bitwarden/icons/cozy.io/icon.png HTTP / 1.1 Host : alice.example.com Hub \u00b6 The hub is a way to get notifications in real-time about cipher and folder changes. POST /bitwarden/notifications/hub/negotiate \u00b6 Before connecting to the hub, the client make a request to this endpoint to know what are the transports and formats supported by the server. Request \u00b6 POST /bitwarden/notifications/hub/negotiate HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"connectionId\" : \"NzhhYjU4NjgtZTA1NC0xMWU5LWIzNzAtM2I1YzM3YWQyOTc1Cg\" , \"availableTransports\" : [ { \"Transport\" : \"WebSockets\" , \"Formats\" : [ \"Binary\" ] } ] } GET /bitwarden/notifications/hub \u00b6 This endpoint is used for WebSockets to get the notifications in real-time. The client must do 3 things, in this order: Make the HTTP request, with the token in the query string ( access_token ) Upgrade the connection to WebSockets Send JSON payload with {\"protocol\": \"messagepack\", \"version\": 1} .", "title": "/bitwarden - Bitwarden"}, {"location": "cozy-stack/bitwarden/#bitwarden", "text": "Cozy-stack exposes an API compatible with Bitwarden on /bitwarden . The author of the unofficial Bitwarden-ruby server did some reverse engineering and wrote a short API documentation .", "title": "Bitwarden"}, {"location": "cozy-stack/bitwarden/#setup", "text": "The signup is disabled, there is one account per Cozy instance, with the email me@ . When the user chooses his/her password (onboarding), an encryption key is also generated to keep safe the secrets in the bitwarden vault. A cozy organization is also created: it will be used to share some passwords with the stack, to be used for the konnectors. The bitwarden clients can connect to the cozy-stack APIs by setting their URL to https:///bitwarden .", "title": "Setup"}, {"location": "cozy-stack/bitwarden/#routes-for-accounts-and-connect", "text": "", "title": "Routes for accounts and connect"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiaccountsprelogin-post-bitwardenidentityaccountsprelogin", "text": "It allows the client to know the number of KDF iterations to apply when hashing the master password. It can also tell if the login via OIDC is mandatory, if the vault is empty (when both conditions are true, the onboarding process is a bit different), and if flat or nested subdomains are used. There are 2 routes for the same endpoint, as Bitwarden has moved from the first to the second, and we want to ensure a smooth migration for clients.", "title": "POST /bitwarden/api/accounts/prelogin & POST /bitwarden/identity/accounts/prelogin"}, {"location": "cozy-stack/bitwarden/#request", "text": "POST /bitwarden/identity/accounts/prelogin HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"email\" : \"me@alice.example.com\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Kdf\" : 0 , \"KdfIterations\" : 10000 , \"OIDC\" : false , \"HasCiphers\" : true , \"FlatSubdomains\" : true }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenidentityconnecttoken", "text": "", "title": "POST /bitwarden/identity/connect/token"}, {"location": "cozy-stack/bitwarden/#request-initial-connection", "text": "POST /bitwarden/identity/connect/token HTTP / 1.1 Host : alice.example.com Content-Type : application/x-www-form-urlencoded grant_type=password& username=me@alice.example.com& password=r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=& scope=api offline_access& client_id=browser& deviceType=3& deviceIdentifier=aac2e34a-44db-42ab-a733-5322dd582c3d& deviceName=firefox& clientName=Cozy& devicePushToken= If authentication with two factors is enabled on the instance and the user not logged through a web session, this request will fail with a 400 status, but it will send an email with the code. The request can be retried with an additional paramter: twoFactorToken . Note: the clientName parameter is optional, and is not sent by the official bitwarden clients (a default value is used).", "title": "Request (initial connection)"}, {"location": "cozy-stack/bitwarden/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"client_id\" : \"f05671e159450b44d5c78cebbd0260b5\" , \"registration_access_token\" : \"J9l-ZhwP[...omitted for brevity...]\" , \"access_token\" : \"eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)\" , \"expires_in\" : 3600 , \"token_type\" : \"Bearer\" , \"refresh_token\" : \"28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf\" , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#request-refresh-token", "text": "POST /bitwarden/identity/connect/token HTTP / 1.1 Host : alice.example.com Content-Type : application/x-www-form-urlencoded grant_type=refresh_token& client_id=browser& refresh_token=28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf", "title": "Request (refresh token)"}, {"location": "cozy-stack/bitwarden/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)\" , \"expires_in\" : 3600 , \"token_type\" : \"Bearer\" , \"refresh_token\" : \"28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf\" , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiaccountspassword-hint", "text": "", "title": "POST /bitwarden/api/accounts/password-hint"}, {"location": "cozy-stack/bitwarden/#request_1", "text": "POST /bitwarden/api/accounts/password-hint HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"email\" : \"me@alice.example.com\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_3", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiaccountsprofile", "text": "", "title": "GET /bitwarden/api/accounts/profile"}, {"location": "cozy-stack/bitwarden/#request_2", "text": "GET /bitwarden/api/accounts/profile HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : null , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [], \"Object\" : \"profile\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapiaccountsprofile", "text": "This route allows to change the profile (currently, only the hint for the master password). It can also be called with a POST (I think it is used by the web vault).", "title": "PUT /bitwarden/api/accounts/profile"}, {"location": "cozy-stack/bitwarden/#request_3", "text": "PUT /bitwarden/api/accounts/profile HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"masterPasswordHint\" : \"blah blah blah\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : \"blah blah blah\" , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [], \"Object\" : \"profile\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiaccountskeys", "text": "This route is used to save a key pair (public and private keys), to be used with organizations.", "title": "POST /bitwarden/api/accounts/keys"}, {"location": "cozy-stack/bitwarden/#request_4", "text": "POST /bitwarden/api/accounts/keys HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"encryptedPrivateKey\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"publicKey\" : \"MIIBIjANBgkqhkiG9w...AQAB\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_6", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : null , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [], \"Object\" : \"profile\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiaccountssecurity-stamp", "text": "It allows to set a new security stamp, which has the effect to disconnect all the clients. It can be used, for example, if the encryption key is changed to avoid the clients to corrupt the vault with ciphers encrypted with the old key.", "title": "POST /bitwarden/api/accounts/security-stamp"}, {"location": "cozy-stack/bitwarden/#request_5", "text": "POST /bitwarden/api/accounts/security-stamp HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"masterPasswordHash\" : \"r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_7", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiaccountsrevision-date", "text": "It returns the date of the last change on the server, as a number of milliseconds since epoch (sic). It is used by the clients to know if they have to do a sync or if they are already up-to-date.", "title": "GET /bitwarden/api/accounts/revision-date"}, {"location": "cozy-stack/bitwarden/#request_6", "text": "GET /bitwarden/api/accounts/revision-date HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_8", "text": "HTTP / 1.1 200 OK 1569571388892", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapisettingsdomains", "text": "This route is also available via a POST , for compatibility with the web vault.", "title": "PUT /bitwarden/api/settings/domains"}, {"location": "cozy-stack/bitwarden/#request_7", "text": "PUT /bitwarden/api/settings/domains HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"equivalentDomains\" : [ [ \"stackoverflow.com\" , \"serverfault.com\" , \"superuser.com\" ] ], \"globalEquivalentDomains\" : [ 42 , 69 ] }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_9", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"EquivalentDomains\" : [ [ \"stackoverflow.com\" , \"serverfault.com\" , \"superuser.com\" ] ], \"GlobalEquivalentDomains\" : [ { \"Type\" : 2 , \"Domains\" : [ \"ameritrade.com\" , \"tdameritrade.com\" ], \"Excluded\" : false }, { \"Type\" : 3 , \"Domains\" : [ \"bankofamerica.com\" , \"bofa.com\" , \"mbna.com\" , \"usecfo.com\" ], \"Excluded\" : false }, { \"Type\" : 42 , \"Domains\" : [ \"playstation.com\" , \"sonyentertainmentnetwork.com\" ], \"Excluded\" : true }, { \"Type\" : 69 , \"Domains\" : [ \"morganstanley.com\" , \"morganstanleyclientserv.com\" ], \"Excluded\" : true } ], \"Object\" : \"domains\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapisettingsdomains", "text": "", "title": "GET /bitwarden/api/settings/domains"}, {"location": "cozy-stack/bitwarden/#request_8", "text": "GET /bitwarden/api/settings/domains HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_10", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"EquivalentDomains\" : [ [ \"stackoverflow.com\" , \"serverfault.com\" , \"superuser.com\" ] ], \"GlobalEquivalentDomains\" : [ { \"Type\" : 2 , \"Domains\" : [ \"ameritrade.com\" , \"tdameritrade.com\" ], \"Excluded\" : false }, { \"Type\" : 3 , \"Domains\" : [ \"bankofamerica.com\" , \"bofa.com\" , \"mbna.com\" , \"usecfo.com\" ], \"Excluded\" : false }, { \"Type\" : 42 , \"Domains\" : [ \"playstation.com\" , \"sonyentertainmentnetwork.com\" ], \"Excluded\" : true }, { \"Type\" : 69 , \"Domains\" : [ \"morganstanley.com\" , \"morganstanleyclientserv.com\" ], \"Excluded\" : true } ], \"Object\" : \"domains\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#route-for-sync", "text": "", "title": "Route for sync"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapisync", "text": "The main action of the client is a one-way sync, which just fetches all objects from the server and updates its local database.", "title": "GET /bitwarden/api/sync"}, {"location": "cozy-stack/bitwarden/#request_9", "text": "GET /bitwarden/api/sync HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_11", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Profile\" : { \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Name\" : \"Alice\" , \"Email\" : \"me@alice.example.com\" , \"EmailVerified\" : false , \"Premium\" : false , \"MasterPasswordHint\" : null , \"Culture\" : \"en-US\" , \"TwoFactorEnabled\" : false , \"Key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"PrivateKey\" : null , \"SecurityStamp\" : \"5d203c3f-bc89-499e-85c4-4431248e1196\" , \"Organizations\" : [ { \"Id\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Name\" : \"Cozy\" , \"Key\" : \"4.HUzVDQVAFc4JOpW3/j/QwZeET0mXOiDW5s/HdpxLZ2GFnGcxOm1FE4XD2p7XTSwORXO/Lo8y0A87UhXKEXzfHZmpJR04pbpUPr4NJbjRKv/cSkNFlvm0rIUw/m0Jkft/gew9v3QfkVSGdSZk5XIimwkTQ5WM+WCStxbQJIKAH+AoEA5q6t9mpNNlTAQvMgqs8u7CJwSjeZ7qbabfEUVX1HIPgxC3BtVUkySRSws/gUNeMwY23kAJJQYT+uuMooZUr7umU6YkEHG2RQZwCCjVHX4czxZRWsVo/xQOYoNr7DjgCf92D7OrJlFmDtQjzSy2BjotN6vn+1SwtHbeDILWaQ==\" , \"BillingEmail\" : \"me@cozy.localhost\" , \"Plan\" : \"TeamsAnnually\" , \"PlanType\" : 5 , \"Seats\" : 2 , \"MaxCollections\" : 1 , \"MaxStorageGb\" : 1 , \"SelfHost\" : true , \"Use2fa\" : true , \"UseDirectory\" : false , \"UseEvents\" : false , \"UseGroups\" : false , \"UseTotp\" : true , \"UsersGetPremium\" : true , \"Enabled\" : true , \"Status\" : 2 , \"Type\" : 2 , \"Object\" : \"profileOrganization\" } ], \"Object\" : \"profile\" }, \"Folders\" : [ { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.tqb+y2z4ChCYHj4romVwGQ==|E8+D7aR5CNnd+jF7fdb9ow==|wELCxyy341G2F+w8bTb87PAUi6sdXeIFTFb4N8tk3E0=\" , \"RevisionDate\" : \"2017-11-13T16:20:56.5633333\" , \"Object\" : \"folder\" } ], \"Ciphers\" : [ { \"FolderId\" : null , \"Favorite\" : false , \"Edit\" : true , \"Id\" : \"0f01a66f-7802-42bc-9647-a82600f11e10\" , \"OrganizationId\" : null , \"Type\" : 1 , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.6DmdNKlm3a+9k/5DFg+pTg==|7q1Arwz/ZfKEx+fksV3yo0HMQdypHJvyiix6hzgF3gY=|7lSXqjfq5rD3/3ofNZVpgv1ags696B2XXJryiGjDZvk=\" , \"Match\" : null } ], \"Username\" : \"2.4Dwitdv4Br85MABzhMJ4hg==|0BJtHtXbfZWwQXbFcBn0aA==|LM4VC+qNpezmub1f4l1TMLDb9g/Q+sIis2vDbU32ZGA=\" , \"Password\" : \"2.OOlWRBGib6G8WRvBOziKzQ==|Had/obAdd2/6y4qzM1Kc/A==|LtHXwZc5PkiReFhkzvEHIL01NrsWGvintQbmqwxoXSI=\" , \"Totp\" : null }, \"Name\" : \"2.zAgCKbTvGowtaRn1er5WGA==|oVaVLIjfBQoRr5EvHTwfhQ==|lHSTUO5Rgfkjl3J/zGJVRfL8Ab5XrepmyMv9iZL5JBE=\" , \"Notes\" : \"2.NLkXMHtgR8u9azASR4XPOQ==|6/9QPcnoeQJDKBZTjcBAjVYJ7U/ArTch0hUSHZns6v8=|p55cl9FQK/Hef+7yzM7Cfe0w07q5hZI9tTbxupZepyM=\" , \"Fields\" : null , \"Attachments\" : null , \"OrganizationUseTotp\" : false , \"RevisionDate\" : \"2017-11-09T14:37:52.9033333\" , \"Object\" : \"cipher\" } ], \"Collections\" : [ { \"Id\" : \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" , \"OrganizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Name\" : \"2.PowfE263ZLz7+Jqrpuezqw==|OzuXDsJnQdfa/eMKxsms6Q==|RpEB7qqs26X9dqa+KaxSE5+52TFVs4dAdfU7DCu3QXM=\" , \"Object\" : \"collection\" , \"ReadOnly\" : false } ], \"Domains\" : { \"EquivalentDomains\" : null , \"GlobalEquivalentDomains\" : null , \"Object\" : \"domains\" }, \"Object\" : \"sync\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#routes-for-ciphers", "text": "", "title": "Routes for ciphers"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiciphers", "text": "It retrieves the list of ciphers.", "title": "GET /bitwarden/api/ciphers"}, {"location": "cozy-stack/bitwarden/#request_10", "text": "GET /bitwarden/api/ciphers HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_12", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } ], \"Object\" : \"list\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiciphers", "text": "When a new item (login, secure note, etc.) is created on a device, it is sent to the server with its fields encrypted via this route.", "title": "POST /bitwarden/api/ciphers"}, {"location": "cozy-stack/bitwarden/#request_11", "text": "POST /bitwarden/api/ciphers HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"type\" : 1 , \"favorite\" : false , \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"folderId\" : null , \"organizationId\" : null , \"notes\" : null , \"login\" : { \"uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"totp\" : null } }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_13", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapicipherscreate", "text": "This route also allows to create a cipher, but this time, it is for a cipher shared with an organization.", "title": "POST /bitwarden/api/ciphers/create"}, {"location": "cozy-stack/bitwarden/#request_12", "text": "POST /bitwarden/api/ciphers/create HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"cipher\" : { \"type\" : 1 , \"favorite\" : false , \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"folderId\" : null , \"organizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"notes\" : null , \"login\" : { \"uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"totp\" : null } }, \"collectionIds\" : [ \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" ] }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_14", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiciphersid-and-bitwardenapiciphersiddetails", "text": "", "title": "GET /bitwarden/api/ciphers/:id and /bitwarden/api/ciphers/:id/details"}, {"location": "cozy-stack/bitwarden/#request_13", "text": "GET /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_15", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapiciphersid", "text": "This route is used to change a cipher. It can also be called via POST /bitwarden/api/ciphers/:id (I think it is used by the web vault).", "title": "PUT /bitwarden/api/ciphers/:id"}, {"location": "cozy-stack/bitwarden/#request_14", "text": "PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"type\" : 2 , \"favorite\" : true , \"name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"folderId\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"organizationId\" : null , \"notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"secureNote\" : { \"type\" : 0 } }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_16", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 2 , \"Favorite\" : true , \"Name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"FolderId\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"OrganizationId\" : null , \"Notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"SecureNote\" : { \"Type\" : 0 }, \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiciphersidshare", "text": "This route is used to share a cipher with an organization. The fields must be encrypted with the organization key.", "title": "POST /bitwarden/api/ciphers/:id/share"}, {"location": "cozy-stack/bitwarden/#request_15", "text": "POST /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/share HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"cipher\" : { \"type\" : 2 , \"favorite\" : true , \"name\" : \"2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=\" , \"organizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"notes\" : \"2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=\" , \"secureNote\" : { \"type\" : 0 } }, \"collectionIds\" : [ \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" ] }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_17", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 2 , \"Favorite\" : true , \"Name\" : \"2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=\" , \"OrganizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"Notes\" : \"2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=\" , \"SecureNote\" : { \"Type\" : 0 }, \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2017-11-07T22:12:22.235914Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#delete-bitwardenapiciphersid", "text": "This route is used to delete a cipher. It can also be called via POST /bitwarden/api/ciphers/:id/delete (I think it is used by the web vault).", "title": "DELETE /bitwarden/api/ciphers/:id"}, {"location": "cozy-stack/bitwarden/#request_16", "text": "DELETE /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_18", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/bitwarden/#delete-bitwardenapiciphers", "text": "This route is used to delete ciphers in bulk. It can also be called via POST /bitwarden/api/ciphers/delete .", "title": "DELETE /bitwarden/api/ciphers"}, {"location": "cozy-stack/bitwarden/#request_17", "text": "DELETE /bitwarden/api/ciphers HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ids\" : [ \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"205c22f0-8642-0139-c874-543d7eb8149c\" ] }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_19", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapiciphersiddelete", "text": "This route is used to soft delete a cipher, by adding a deletedDate attribute on it.", "title": "PUT /bitwarden/api/ciphers/:id/delete"}, {"location": "cozy-stack/bitwarden/#request_18", "text": "PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/delete HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_20", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapiciphersdelete", "text": "This route is used to soft delete ciphers in bulk.", "title": "PUT /bitwarden/api/ciphers/delete"}, {"location": "cozy-stack/bitwarden/#request_19", "text": "PUT /bitwarden/api/ciphers/delete HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ids\" : [ \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"205c22f0-8642-0139-c874-543d7eb8149c\" ] }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_21", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapiciphersidrestore", "text": "This route is used to restore a soft-deleted cipher, by removing the deletedDate attribute.", "title": "PUT /bitwarden/api/ciphers/:id/restore"}, {"location": "cozy-stack/bitwarden/#request_20", "text": "PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/restore HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_22", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapiciphersrestore", "text": "This route is used to restore ciphers in bulk.", "title": "PUT /bitwarden/api/ciphers/restore"}, {"location": "cozy-stack/bitwarden/#request_21", "text": "PUT /bitwarden/api/ciphers/restore HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ids\" : [ \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"205c22f0-8642-0139-c874-543d7eb8149c\" ] }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_23", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Object\" : \"cipher\" , \"Id\" : \"4c2869dd-0e1c-499f-b116-a824016df251\" , \"Type\" : 1 , \"Favorite\" : false , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : null , \"Login\" : { \"Uris\" : [ { \"Uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"Match\" : null } ] }, \"Username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"Password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"Totp\" : null , \"Fields\" : null , \"Attachments\" : null , \"RevisionDate\" : \"2021-04-23T12:58:01Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false }, { \"Object\" : \"cipher\" , \"Id\" : \"205c22f0-8642-0139-c874-543d7eb8149c\" , \"Type\" : 2 , \"Favorite\" : true , \"Name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"FolderId\" : null , \"OrganizationId\" : null , \"Notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"RevisionDate\" : \"2021-04-23T12:58:01Z\" , \"Edit\" : true , \"OrganizationUseTotp\" : false } ], \"Object\" : \"list\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiciphersimport", "text": "This route can be used to import several ciphers and folders in bulk. In folderRelationships , the key is the index of the cipher in the ciphers list, and the value is the index of the folder in the folders list.", "title": "POST /bitwarden/api/ciphers/import"}, {"location": "cozy-stack/bitwarden/#request_22", "text": "POST /bitwarden/api/ciphers/import HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"ciphers\" : [{ \"type\" : 2 , \"favorite\" : true , \"name\" : \"2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=\" , \"folderId\" : null , \"organizationId\" : null , \"notes\" : \"2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=\" , \"secureNote\" : { \"type\" : 0 } }, { \"type\" : 1 , \"favorite\" : false , \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"folderId\" : null , \"organizationId\" : null , \"notes\" : null , \"login\" : { \"uri\" : \"2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=\" , \"username\" : \"2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=\" , \"password\" : \"2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=\" , \"totp\" : null } }], \"folders\" : [{ \"name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" }], \"folderRelationships\" : [ { \"key\" : 1 , \"value\" : 0 } ] }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_24", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/bitwarden/#routes-for-folders", "text": "", "title": "Routes for folders"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapifolders", "text": "It retrieves the list of folders.", "title": "GET /bitwarden/api/folders"}, {"location": "cozy-stack/bitwarden/#request_23", "text": "GET /bitwarden/api/folders HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_25", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" } ], \"Object\" : \"list\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapifolders", "text": "It adds a new folder on the server. The name is encrypted on client-side.", "title": "POST /bitwarden/api/folders"}, {"location": "cozy-stack/bitwarden/#request_24", "text": "POST /bitwarden/api/folders HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_26", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapifoldersid", "text": "", "title": "GET /bitwarden/api/folders/:id"}, {"location": "cozy-stack/bitwarden/#request_25", "text": "GET /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_27", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#put-bitwardenapifoldersid", "text": "This route is used to rename a folder. It can also be called via POST /bitwarden/api/folders/:id (I think it is used by the web vault).", "title": "PUT /bitwarden/api/folders/:id"}, {"location": "cozy-stack/bitwarden/#request_26", "text": "PUT /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_28", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"14220912-d002-471d-a364-a82a010cb8f2\" , \"Name\" : \"2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=\" , \"RevisionDate\" : \"2017-11-13T16:18:23.3078169Z\" , \"Object\" : \"folder\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#delete-bitwardenapifoldersid", "text": "This route is used to delete a folder. It can also be called via POST /bitwarden/api/folders/:id/delete (I think it is used by the web vault).", "title": "DELETE /bitwarden/api/folders/:id"}, {"location": "cozy-stack/bitwarden/#request_27", "text": "DELETE /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_29", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/bitwarden/#organizations-and-collections", "text": "", "title": "Organizations and Collections"}, {"location": "cozy-stack/bitwarden/#get-bitwardenorganizationscozy", "text": "This route can be used to get information about the Cozy Organization. It requires a permission on the whole com.bitwarden.organizations doctype to access it. In particular, it gives the key to encrypt/decrypt the ciphers in this organization (encoded in base64).", "title": "GET /bitwarden/organizations/cozy"}, {"location": "cozy-stack/bitwarden/#request_28", "text": "GET /bitwarden/organizations/cozy HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_30", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"organizationId\" : \"38ac39d0-d48d-11e9-91bf-f37e45d48c79\" , \"collectionId\" : \"385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d\" , \"organizationKey\" : \"oWeRYokoCMFsAja6lrp3RQ1PYOrex4tgAMECP4nX+a4IXdijbejQscvWqy9bMgLsX0HRc2igqBRMWdsPuFK0PQ==\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiorganizations", "text": "This route can be used to create an organization, with a collection.", "title": "POST /bitwarden/api/organizations"}, {"location": "cozy-stack/bitwarden/#request_29", "text": "POST /bitwarden/api/organizations HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"name\" : \"Family\" , \"key\" : \"4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=\" , \"collectionName\" : \"2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M=\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_31", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"724db920-cc4b-0139-6ab2-543d7eb8149c\" , \"Name\" : \"Family\" , \"Key\" : \"4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=\" , \"BillingEmail\" : \"me@cozy.localhost\" , \"Plan\" : \"TeamsAnnually\" , \"PlanType\" : 9 , \"Seats\" : 10 , \"MaxCollections\" : 1 , \"MaxStorageGb\" : 1 , \"SelfHost\" : true , \"Use2fa\" : true , \"UseDirectory\" : false , \"UseEvents\" : false , \"UseGroups\" : false , \"UseTotp\" : true , \"UseApi\" : false , \"UsePolicies\" : false , \"UseSSO\" : false , \"UseResetPass\" : false , \"HasPublicAndPrivateKeys\" : false , \"ResetPasswordEnrolled\" : false , \"UsersGetPremium\" : true , \"Enabled\" : true , \"Status\" : 2 , \"Type\" : 2 , \"Object\" : \"profileOrganization\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiorganizationsid", "text": "This route can be used to fetch information about an organization.", "title": "GET /bitwarden/api/organizations/:id"}, {"location": "cozy-stack/bitwarden/#request_30", "text": "GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_32", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Id\" : \"724db920-cc4b-0139-6ab2-543d7eb8149c\" , \"Name\" : \"Family\" , \"Key\" : \"4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=\" , \"BillingEmail\" : \"me@cozy.localhost\" , \"Plan\" : \"TeamsAnnually\" , \"PlanType\" : 9 , \"Seats\" : 10 , \"MaxCollections\" : 1 , \"MaxStorageGb\" : 1 , \"SelfHost\" : true , \"Use2fa\" : true , \"UseDirectory\" : false , \"UseEvents\" : false , \"UseGroups\" : false , \"UseTotp\" : true , \"UseApi\" : false , \"UsePolicies\" : false , \"UseSSO\" : false , \"UseResetPass\" : false , \"HasPublicAndPrivateKeys\" : false , \"ResetPasswordEnrolled\" : false , \"UsersGetPremium\" : true , \"Enabled\" : true , \"Status\" : 2 , \"Type\" : 2 , \"Object\" : \"profileOrganization\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiorganizationsidcollections", "text": "This route can be used to fetch information about the collections inside an organization.", "title": "GET /bitwarden/api/organizations/:id/collections"}, {"location": "cozy-stack/bitwarden/#request_31", "text": "GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/collections HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_33", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Id\" : \"62080a40-d75d-0139-21f1-543d7eb8149c\" , \"OrganizationId\" : \"724db920-cc4b-0139-6ab2-543d7eb8149c\" , \"Name\" : \"2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M=\" , \"Object\" : \"collection\" } ], \"Object\" : \"list\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#delete-bitwardenapiorganizationsid", "text": "This route can be used to delete an organization by its owner.", "title": "DELETE /bitwarden/api/organizations/:id"}, {"location": "cozy-stack/bitwarden/#request_32", "text": "DELETE /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"masterPasswordHash\" : \"r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_34", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiorganizationsidusers", "text": "This route returns the list of users in the given organization.", "title": "GET /bitwarden/api/organizations/:id/users"}, {"location": "cozy-stack/bitwarden/#request_33", "text": "GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_35", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Data\" : [ { \"Object\" : \"organizationUserUserDetails\" , \"Id\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"UserId\" : \"0fbfc68d-ba11-416a-ac8a-a82600f0e601\" , \"Type\" : 0 , \"Status\" : 2 , \"AccessAll\" : true , \"Name\" : \"Alice\" , \"Email\" : \"alice@example.com\" }, { \"Object\" : \"organizationUserUserDetails\" , \"Id\" : \"89d99af0db1c0139605b543d7eb8149c\" , \"UserId\" : \"89d99af0db1c0139605b543d7eb8149c\" , \"Type\" : 2 , \"Status\" : 1 , \"AccessAll\" : true , \"Name\" : \"Bob\" , \"Email\" : \"bob@example.com\" } ], \"Object\" : \"list\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#post-bitwardenapiorganizationsidusersuser-idconfirm", "text": "This route is used by the owner of an organization to confirm that another user can use this sharing. The caller must check the fingerprint of the new member and encrypt the organization key with their public key.", "title": "POST /bitwarden/api/organizations/:id/users/:user-id/confirm"}, {"location": "cozy-stack/bitwarden/#request_34", "text": "POST /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users/89d99af0db1c0139605b543d7eb8149c/confirm HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"key\" : \"4.UT/TVY6qmAjNdax2WT9JcA97wSWvEudAlqpjfxrFUieOoGA88MxzbYjpCXajEST/PehD1I7KC93jwthng772extu+lLHSd/Ce+a5Qw8+pRxL7je8QgS8gmP0FhfRLc4bl5hUMTfQcUDiuiiNaDez6E9czOzk9iuVaGpEjK4YAYgQy25m3eGc+DTPv8206NJZ/lr8CpPyhwUHjtDhlOZnDWAf+a28x2EAj1ogZKKJGAUcRENitV8Joa7OGRO6dmxtTTnWOuPDk5DajGgzpIQURNuotVHcpBtCL8HzNAduQ9vtrPKJtyAsHRdjau2SwEnaLZmxAvp7d9VG3t5nDYtgWA==\" }", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_36", "text": "HTTP / 1.1 200 OK", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardenapiusersidpublic-key", "text": "This route gives the public key of a user.", "title": "GET /bitwarden/api/users/:id/public-key"}, {"location": "cozy-stack/bitwarden/#request_35", "text": "GET /bitwarden/api/users/89d99af0db1c0139605b543d7eb8149c/public-key HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_37", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"UserId\" : \"89d99af0db1c0139605b543d7eb8149c\" , \"PublicKey\" : \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1LwbnLsT8w2OBPR/zy/zRQNH+jZzD6v4qUGAJg0NfoUkBSgtq9yjor2GgeRtdf8VuNTn1kcNrUIU4f9vE3ppNJgmUss4O29OP9/ATqtC/4ri4UCWTV0DPCF4gRU1SbgTg9O3yC2UYWmrs47SgU0wwT+f5AjfDC7GzhjyX68UYIIIeKSMZasjcy+wIPVAW0hYhcEoK3Coq2O1wVwM+b2fXPIMzn38onUTbMCrkVY+FzGg6NtZbKzPvVZ0iyfQ6BxvttqSViNPOpyz7gryDhgYKokV+kwj5ARDZWL6ml73U2lL7uapk5meNKZf8w7TJGepFiewGLm08VMht6lnIZBuDQIDAQAB\" }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#delete-bitwardencontactsid", "text": "This route can be used to refuse to give access to a user to shared ciphers. The contact will be deleted, and they will be revoked from all sharings.", "title": "DELETE /bitwarden/contacts/:id"}, {"location": "cozy-stack/bitwarden/#request_36", "text": "GET /bitwarden/contacts/89d99af0db1c0139605b543d7eb8149c HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_38", "text": "HTTP / 1.1 204 No-Content", "title": "Response"}, {"location": "cozy-stack/bitwarden/#icons", "text": "", "title": "Icons"}, {"location": "cozy-stack/bitwarden/#get-bitwardeniconsdomainiconpng", "text": "This route returns an icon for the given domain, that can be used by the bitwarden clients. No authorization token is required. If no favicon has been found for the domain, a fallback will be used, depending of the fallback parameter in the query-string: default : a default icon is returned 404 : just a 404 - Not found error.", "title": "GET /bitwarden/icons/:domain/icon.png"}, {"location": "cozy-stack/bitwarden/#request_37", "text": "GET /bitwarden/icons/cozy.io/icon.png HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#hub", "text": "The hub is a way to get notifications in real-time about cipher and folder changes.", "title": "Hub"}, {"location": "cozy-stack/bitwarden/#post-bitwardennotificationshubnegotiate", "text": "Before connecting to the hub, the client make a request to this endpoint to know what are the transports and formats supported by the server.", "title": "POST /bitwarden/notifications/hub/negotiate"}, {"location": "cozy-stack/bitwarden/#request_38", "text": "POST /bitwarden/notifications/hub/negotiate HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/bitwarden/#response_39", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"connectionId\" : \"NzhhYjU4NjgtZTA1NC0xMWU5LWIzNzAtM2I1YzM3YWQyOTc1Cg\" , \"availableTransports\" : [ { \"Transport\" : \"WebSockets\" , \"Formats\" : [ \"Binary\" ] } ] }", "title": "Response"}, {"location": "cozy-stack/bitwarden/#get-bitwardennotificationshub", "text": "This endpoint is used for WebSockets to get the notifications in real-time. The client must do 3 things, in this order: Make the HTTP request, with the token in the query string ( access_token ) Upgrade the connection to WebSockets Send JSON payload with {\"protocol\": \"messagepack\", \"version\": 1} .", "title": "GET /bitwarden/notifications/hub"}, {"location": "cozy-stack/client-app-dev/", "text": "Table of contents Develop a client-side application \u00b6 Using cozy-app-dev \u00b6 This document describe a tool to run an environment in order to develop client-side application on the cozy-stack. We provide two different ways to run this environment, either manually where you have to install part of the dependencies yourself or via a Docker image in which all dependencies are packed. This environment will provide a running instance a http server serving both a specified directory of your application on app.cozy.localhost:8080 and the cozy-stack on cozy.localhost:8080 (you can change the hostname and port if you want, see below). The default passphrase will be \u201ccozy\u201d Manually \u00b6 To run the scripts/cozy-app-dev.sh directly on you system, you\u2019ll need to following dependencies: go curl git couchdb2 : you need at least a running instance of CouchDB 2 Examples: $ ./scripts/cozy-app-dev.sh -d ~/code/myapp If your CouchDB 2 instance is not running on localhost:5984 , you can specify another host and port with the variable COUCHDB_URL like so: $ COUCHDB_URL = http://couchdb.local:1234/ ./scripts/cozy-app-dev.sh -d ~/code/myapp You can have more informations about the usage of this script with the following command: $ ./scripts/cozy-app-dev.sh -h With Docker \u00b6 If you do not want to install the required dependencies, we provide a Docker image which encapsulates the dev script and all its dependencies. To download the latest version, you can run this command: docker pull cozy/cozy-app-dev If you work behind a corporate proxy, and Docker is configured to inject proxy configuration into the containers, you need to ensure that both localhost and cozy.localhost are configured not to use the proxy. Following is the minimal ~/.docker/config.json configuration that has been shown to work: { \"proxies\" : { \"default\" : { \"httpProxy\" : \"MY_CORPORATE_PROXY\" , \"httpsProxy\" : \"MY_CORPORATE_PROXY\" , \"noProxy\" : \"localhost,cozy.localhost\" } } } To run a ephemeral instance, on the $HOME/myapp directory, use the following command (warning: all the data stored by your application in couchdb and the VFS won\u2019t remain after): $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /myapp\" :/data/cozy-app \\ cozy/cozy-app-dev To keep your data even when stopping the container, run the following command: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /myapp\" :/data/cozy-app \\ -v \" $( pwd ) /db\" :/usr/local/couchdb/data \\ -v \" $( pwd ) /storage\" :/data/cozy-storage \\ cozy/cozy-app-dev You can mount your yaml config file, to change the log level for example: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /myapp\" :/data/cozy-app \\ -v \" $HOME /cozy.yaml\" :/etc/cozy/cozy.yaml \\ cozy/cozy-app-dev A MailHog is running inside docker to catch emails. You can view the emails sent by the stack in a web interface on http://cozy.localhost:8025/ You can also expose the couchdb port (listening in the container on 5984) in order to access its admin page. For instance add -p 1234:5984 to access to the admin interface on http://localhost:1234/_utils . Make sure you application is built into $HOME/myapp (it should have an index.html and a manifest.webapp files), otherwise it will not work. As an example, for the Drive application , it should be $HOME/drive/build . If you want to use several applications (for testing the intents for example), you can mount several directories inside /data/cozy-app like this: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /appone\" :/data/cozy-app/appone \\ -v \" $HOME /apptwo\" :/data/cozy-app/apptwo \\ cozy/cozy-app-dev Good practices for your application \u00b6 When an application makes a request to the stack, like loading a list of contacts, it sends two informations that will be used by the stack to allow or deny the access: the user session cookie a token that identifies the application (only when the user is connected). So, the application needs such a token. It also needs to know where to send the requests for the stack (it can be guessed, but with the nested vs flat subdomains structures, it\u2019s better to get the information from the stack). To do that, when the application loads its HTML index file, the stack will parse it as a template and will insert the relevant values. The configuration can be injected as a JSON with {{.CozyData}} . If you need more control or have some compatibility issues, it is possible to inject the individual values with: {{.Token}} will be replaced by the token for the application. {{.Domain}} will be replaced by the stack hostname. {{.Locale}} will be replaced by the locale for the instance. {{.AppName}} : will be replaced by the application name. {{.AppSlug}} : will be replaced by the application slug. {{.AppNamePrefix}} : will be replaced by the application name prefix. {{.AppEditor}} : will be replaced by the application\u2019s editor. {{.IconPath}} : will be replaced by the application\u2019s icon path. {{.SubDomain}} will be replaced by flat or nested . {{.Tracking}} will be replaced by a value to indicate if tracking is enabled. {{.Capabilities}} will be replaced by JSON with the capabilities . {{.Flags}} will be replaced by JSON with the feature flags . There are also some helpers to inject asset tags or URLs: {{.CozyBar}} will be replaced by the JavaScript to inject the cozy-bar. {{.CozyClientJS}} will be replaced by the JavaScript to inject the cozy-client-js. {{.CozyFonts}} will be replaced by the fonts.css used to inject the web fonts (Lato and Lato bold by default). {{.ThemeCSS}} will be replaced by the theme.css . It is empty by default, but can be overrided by using contexts . See contexts and dynamic assets for more informations. {{.Favicon}} will be replaced by the favicon served by the stack. {{.DefaultWallpaper}} will be replaced by the URL to the default wallpaper. So, the index.html should probably looks like: < html lang = \"{{.Locale}}\" > < head > < meta charset = \"utf-8\" > < title > My Awesome App for Cozy < meta name = \"viewport\" content = \"width=device-width, initial-scale=1\" > < meta name = \"theme-color\" content = \"#ffffff\" > < link rel = \"manifest\" href = \"/manifest.json\" crossOrigin = \"use-credentials\" > < link rel = \"stylesheet\" href = \"my-app.css\" > {{.ThemeCSS}} {{.CozyClientJS}} {{.CozyBar}} < body > < div role = \"application\" data-cozy = \"{{.CozyData}}\" > < script src = \"my-app.js\" > And my-app.js : \"use strict\" ; document . addEventListener ( \"DOMContentLoaded\" , () => { const app = document . querySelector ( \"[role=application]\" ); const data = app . dataset ; cozy . client . init ( data . cozy ); cozy . bar . init ({ appEditor : data . cozy . app . editor , appName : data . cozy . app . name , iconPath : data . cozy . app . icon , lang : data . cozy . locale }); // ... });", "title": "Develop a client-side app"}, {"location": "cozy-stack/client-app-dev/#develop-a-client-side-application", "text": "", "title": "Develop a client-side application"}, {"location": "cozy-stack/client-app-dev/#using-cozy-app-dev", "text": "This document describe a tool to run an environment in order to develop client-side application on the cozy-stack. We provide two different ways to run this environment, either manually where you have to install part of the dependencies yourself or via a Docker image in which all dependencies are packed. This environment will provide a running instance a http server serving both a specified directory of your application on app.cozy.localhost:8080 and the cozy-stack on cozy.localhost:8080 (you can change the hostname and port if you want, see below). The default passphrase will be \u201ccozy\u201d", "title": "Using cozy-app-dev"}, {"location": "cozy-stack/client-app-dev/#manually", "text": "To run the scripts/cozy-app-dev.sh directly on you system, you\u2019ll need to following dependencies: go curl git couchdb2 : you need at least a running instance of CouchDB 2 Examples: $ ./scripts/cozy-app-dev.sh -d ~/code/myapp If your CouchDB 2 instance is not running on localhost:5984 , you can specify another host and port with the variable COUCHDB_URL like so: $ COUCHDB_URL = http://couchdb.local:1234/ ./scripts/cozy-app-dev.sh -d ~/code/myapp You can have more informations about the usage of this script with the following command: $ ./scripts/cozy-app-dev.sh -h", "title": "Manually"}, {"location": "cozy-stack/client-app-dev/#with-docker", "text": "If you do not want to install the required dependencies, we provide a Docker image which encapsulates the dev script and all its dependencies. To download the latest version, you can run this command: docker pull cozy/cozy-app-dev If you work behind a corporate proxy, and Docker is configured to inject proxy configuration into the containers, you need to ensure that both localhost and cozy.localhost are configured not to use the proxy. Following is the minimal ~/.docker/config.json configuration that has been shown to work: { \"proxies\" : { \"default\" : { \"httpProxy\" : \"MY_CORPORATE_PROXY\" , \"httpsProxy\" : \"MY_CORPORATE_PROXY\" , \"noProxy\" : \"localhost,cozy.localhost\" } } } To run a ephemeral instance, on the $HOME/myapp directory, use the following command (warning: all the data stored by your application in couchdb and the VFS won\u2019t remain after): $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /myapp\" :/data/cozy-app \\ cozy/cozy-app-dev To keep your data even when stopping the container, run the following command: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /myapp\" :/data/cozy-app \\ -v \" $( pwd ) /db\" :/usr/local/couchdb/data \\ -v \" $( pwd ) /storage\" :/data/cozy-storage \\ cozy/cozy-app-dev You can mount your yaml config file, to change the log level for example: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /myapp\" :/data/cozy-app \\ -v \" $HOME /cozy.yaml\" :/etc/cozy/cozy.yaml \\ cozy/cozy-app-dev A MailHog is running inside docker to catch emails. You can view the emails sent by the stack in a web interface on http://cozy.localhost:8025/ You can also expose the couchdb port (listening in the container on 5984) in order to access its admin page. For instance add -p 1234:5984 to access to the admin interface on http://localhost:1234/_utils . Make sure you application is built into $HOME/myapp (it should have an index.html and a manifest.webapp files), otherwise it will not work. As an example, for the Drive application , it should be $HOME/drive/build . If you want to use several applications (for testing the intents for example), you can mount several directories inside /data/cozy-app like this: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ -v \" $HOME /appone\" :/data/cozy-app/appone \\ -v \" $HOME /apptwo\" :/data/cozy-app/apptwo \\ cozy/cozy-app-dev", "title": "With Docker"}, {"location": "cozy-stack/client-app-dev/#good-practices-for-your-application", "text": "When an application makes a request to the stack, like loading a list of contacts, it sends two informations that will be used by the stack to allow or deny the access: the user session cookie a token that identifies the application (only when the user is connected). So, the application needs such a token. It also needs to know where to send the requests for the stack (it can be guessed, but with the nested vs flat subdomains structures, it\u2019s better to get the information from the stack). To do that, when the application loads its HTML index file, the stack will parse it as a template and will insert the relevant values. The configuration can be injected as a JSON with {{.CozyData}} . If you need more control or have some compatibility issues, it is possible to inject the individual values with: {{.Token}} will be replaced by the token for the application. {{.Domain}} will be replaced by the stack hostname. {{.Locale}} will be replaced by the locale for the instance. {{.AppName}} : will be replaced by the application name. {{.AppSlug}} : will be replaced by the application slug. {{.AppNamePrefix}} : will be replaced by the application name prefix. {{.AppEditor}} : will be replaced by the application\u2019s editor. {{.IconPath}} : will be replaced by the application\u2019s icon path. {{.SubDomain}} will be replaced by flat or nested . {{.Tracking}} will be replaced by a value to indicate if tracking is enabled. {{.Capabilities}} will be replaced by JSON with the capabilities . {{.Flags}} will be replaced by JSON with the feature flags . There are also some helpers to inject asset tags or URLs: {{.CozyBar}} will be replaced by the JavaScript to inject the cozy-bar. {{.CozyClientJS}} will be replaced by the JavaScript to inject the cozy-client-js. {{.CozyFonts}} will be replaced by the fonts.css used to inject the web fonts (Lato and Lato bold by default). {{.ThemeCSS}} will be replaced by the theme.css . It is empty by default, but can be overrided by using contexts . See contexts and dynamic assets for more informations. {{.Favicon}} will be replaced by the favicon served by the stack. {{.DefaultWallpaper}} will be replaced by the URL to the default wallpaper. So, the index.html should probably looks like: < html lang = \"{{.Locale}}\" > < head > < meta charset = \"utf-8\" > < title > My Awesome App for Cozy < meta name = \"viewport\" content = \"width=device-width, initial-scale=1\" > < meta name = \"theme-color\" content = \"#ffffff\" > < link rel = \"manifest\" href = \"/manifest.json\" crossOrigin = \"use-credentials\" > < link rel = \"stylesheet\" href = \"my-app.css\" > {{.ThemeCSS}} {{.CozyClientJS}} {{.CozyBar}} < body > < div role = \"application\" data-cozy = \"{{.CozyData}}\" > < script src = \"my-app.js\" > And my-app.js : \"use strict\" ; document . addEventListener ( \"DOMContentLoaded\" , () => { const app = document . querySelector ( \"[role=application]\" ); const data = app . dataset ; cozy . client . init ( data . cozy ); cozy . bar . init ({ appEditor : data . cozy . app . editor , appName : data . cozy . app . name , iconPath : data . cozy . app . icon , lang : data . cozy . locale }); // ... });", "title": "Good practices for your application"}, {"location": "cozy-stack/config/", "text": "Table of contents Configuration \u00b6 Main Configuration file \u00b6 You can configure your cozy-stack using a configuration file. By default, cozy-stack comes with a file named cozy.example.yaml . If you need to edit the configuration, we recommend to only copy the needed part in a new file. This new file should be named cozy.yaml , cozy.yml , or cozy.json depending on the format of your chosing, and should be present in one of these directories (ordered by priority): ./.cozy $HOME/.cozy /etc/cozy The path of the configuration file can also be define from an absolute path given by the --config (or -c ) flag of the cozy-stack command . Note that is is possible to have an additional configuration file, with the .local suffix. For example, it can be used to have /etc/cozy/cozy.yml managed by a package manager, and /etc/cozy/cozy.yml.local for things that a user can customize. Templating and Environment Variables \u00b6 It is possible to pass environnment variable to this configuration using the template language of golang , delimited by {{ and }} . The environment variables are available in the .Env variable. For instance the text {{.Env.COUCHDB_PASSPHRASE }} will be replaced by the value of the COUCHDB_PASSPHRASE environment variable. The template is evaluated at startup of the stack. Values and Example \u00b6 To see the detail of the available parameters available, you can see an example of configuration in the cozy.example.yaml file at the root of this repository. This file contains all the parameters and fields that can be used to configure the stack with some example values. Some fields can be overriden by the flags of the cozy-stack serve command . Stack endpoints \u00b6 By default, cozy-stack use plain-text & local socket for client ( localhost:8080 ) and admin ( localhost:6060 ) communications. If you want to control a remote stack or using TLS to secure communications, you can configure your cozy-stack client with the following CLI arguments or environment variables. Argument Env variable Default value Usage --host / --admin-host COZY_HOST / COZY_ADMIN_HOST localhost [http[s]://][:] --port / --admin-port COZY_PORT / COZY_ADMIN_PORT 8080 / 6060 COZY_HOST_TIMEOUT / COZY_ADMIN_TIMOUT 15s HTTP timeout to use Must be a valid golang duration like 10s or 1m COZY_HOST_VALIDATE / COZY_ADMIN_VALIDATE true Enable HTTPS certificate validation Can also be set via host URL query part, like https://localhost:6060?validate=false COZY_HOST_CA / COZY_ADMIN_CA none CA file to use for HTTPS certificate validation Can also be set via host URL query part, like https://localhost:6060?ca= COZY_HOST_CERT / COZY_ADMIN_CERT none Client certificate to use Can also be set via host URL query part, like https://localhost:6060?cert= COZY_HOST_KEY / COZY_ADMIN_KEY none Client certificate to use Can also be set via host URL query part, like https://localhost:6060?key= COZY_HOST_FINGERPRINT / COZY_ADMIN_FINGERPRINT none Hex-encoded SHA-256 key pinning to use Can also be set via host URL query part, like https://localhost:6060?fp= You can get the fingerprint of a given certificate with openssl x509 -in -pubkey \\| openssl pkey -pubin -outform der \\| openssl dgst -sha256 -hex or directly from a private key with openssl pkey -in -pubout -outform der \\| openssl dgst -sha256 -hex Administration secret \u00b6 To access to the administration API (the /admin/* routes), a secret passphrase should be stored in a cozy-admin-passphrase . This file should be in one of the configuration directories, along with the main config file. The passphrase is stored in a salted-hashed representation using scrypt. To generate this file, you can use the cozy-stack config passwd [filepath] command. This command will ask you for a passphrase and will create the cozy-admin-passphrase at the specified path. You can use the COZY_ADMIN_PASSPHRASE (or COZY_ADMIN_PASSWORD ) env variable if you do not want to type the passphrase each time you call cozy-stack . Example \u00b6 $ mkdir ~/.cozy && cozy-stack config passwd ~/.cozy/cozy-admin-passphrase Hashed passphrase will be writtent in ~/.cozy/cozy-admin-passphrase Passphrase: Confirmation: $ cat ~/.cozy/cozy-admin-passphrase scrypt $16384$8$1$936 bd62faf633b5f946f653c21161a9b $4 e0d11dfa5fc1676ed329938b11a6584d30e603e0d06b8a63a99e8cec392d682 Temporary files \u00b6 The stack can use some temporary directories and files (execution of Image Magick, konnectors and services for example). And they can take several GB for the case of importing a Cozy. If needed, it is possible to configure the directory where they will be created via the TMPDIR environment variable. Multiple CouchDB clusters \u00b6 With a large number of instances, a single CouchDB cluster may not be enough. Most cozy-stack administrators can ignore this section, but if you need this advanced settings, let\u2019s see how to configure it. We start with a classical configuration for a single cluster: couchdb : url : http://cluster1:5984/ The first step is to add the new cluster, but still forces the creation on the first cluster for the moment: couchdb : url : http://cluster1:5984/ clusters : - url : http://cluster1:5984/ instance_creation : true - url : http://cluster2:5984/ instance_creation : false Then, we can restart the cozy-stack and everything will work the same, except that the stack now knows how to use an instance on the new cluster. We can now use the second cluster for instance creations instead of the first: couchdb : url : http://cluster1:5984/ clusters : - url : http://cluster1:5984/ instance_creation : false - url : http://cluster2:5984/ instance_creation : true Notes: if several CouchDB clusters are configured to accept creations, a new instance will be put in a CouchDB cluster taken randomly each instance document will keep the list index of the CouchDB cluster used for its databases, so don\u2019t remove a cluster in the middle of the list! OnlyOffice \u00b6 An integration between Cozy and OnlyOffice has been made. It allows the collaborative edition of office documents in the browser. There are some pre-requistes. OnlyOffice Docs must be installed on a server ( The community edition is free but limited to 20 connections and doesn\u2019t have the mobile mode). It can be the same server as the stack, but it is tricky as the default port of the stack and of the spellchecker of OnlyOffice is 8080 for both. The stack and the OnlyOffice components must be able to make HTTP requests to each other. And, for security, these requests can be signed via some shared secrets, called inbox and outbox secrets in OnlyOffice configuration. In the local.json configuration file of OnlyOffice, we need: services.CoAuthoring.token.enable.browser : true services.CoAuthoring.token.enable.request.inbox : true services.CoAuthoring.token.enable.request.outbox : true services.CoAuthoring.secret.inbox : a random secret services.CoAuthoring.secret.outbox : another random secret In the cozy configuration file, we need to add a section with: office : default : onlyoffice_url : https://onlyoffice.example.net/ onlyoffice_inbox_secret : inbox_secret onlyoffice_outbox_secret : outbox_secret Don\u2019t forget to restart all the services after having made the changes to the configuration files. And you should be able to edit office documents in your browser via the Drive application. Customizing a context \u00b6 Intro \u00b6 In the config file of cozy-stack, it\u2019s possible to declare some contexts, that are a way to regroup some cozy instances to give similar configuration. For example, it is possible to give a default_redirection that will be used when the user logs into their cozy. You can find more example in the example config file. Assets \u00b6 The visual appearance of a cozy instance can be customized via some assets (CSS, JS, images). These assets can be inserted from the command-line with the cozy-stack assets add command. Here are a small list of assets that you may want to customize: /styles/theme.css : a CSS file where you can override the colors and put other CSS rules /favicon.ico : the old-school favicon /icon.svg : the favicon in SVG format /icon-192.png and /icon-512.png : the two variants of the favicon /apple-touch-icon.png : the same but for Apple /images/default-avatar.png : the image to use as the default avatar. /images/default-wallpaper.jpg : the image to use as the default wallpapper on the home. /images/icon-cozy-home.svg : the home icon used and displayed by the cozy-bar. /images/icon-cozy-home-inverted.svg : the home icon used and displayed by the cozy-bar when using the theme inverted.", "title": "Configuration file"}, {"location": "cozy-stack/config/#configuration", "text": "", "title": "Configuration"}, {"location": "cozy-stack/config/#main-configuration-file", "text": "You can configure your cozy-stack using a configuration file. By default, cozy-stack comes with a file named cozy.example.yaml . If you need to edit the configuration, we recommend to only copy the needed part in a new file. This new file should be named cozy.yaml , cozy.yml , or cozy.json depending on the format of your chosing, and should be present in one of these directories (ordered by priority): ./.cozy $HOME/.cozy /etc/cozy The path of the configuration file can also be define from an absolute path given by the --config (or -c ) flag of the cozy-stack command . Note that is is possible to have an additional configuration file, with the .local suffix. For example, it can be used to have /etc/cozy/cozy.yml managed by a package manager, and /etc/cozy/cozy.yml.local for things that a user can customize.", "title": "Main Configuration file"}, {"location": "cozy-stack/config/#templating-and-environment-variables", "text": "It is possible to pass environnment variable to this configuration using the template language of golang , delimited by {{ and }} . The environment variables are available in the .Env variable. For instance the text {{.Env.COUCHDB_PASSPHRASE }} will be replaced by the value of the COUCHDB_PASSPHRASE environment variable. The template is evaluated at startup of the stack.", "title": "Templating and Environment Variables"}, {"location": "cozy-stack/config/#values-and-example", "text": "To see the detail of the available parameters available, you can see an example of configuration in the cozy.example.yaml file at the root of this repository. This file contains all the parameters and fields that can be used to configure the stack with some example values. Some fields can be overriden by the flags of the cozy-stack serve command .", "title": "Values and Example"}, {"location": "cozy-stack/config/#stack-endpoints", "text": "By default, cozy-stack use plain-text & local socket for client ( localhost:8080 ) and admin ( localhost:6060 ) communications. If you want to control a remote stack or using TLS to secure communications, you can configure your cozy-stack client with the following CLI arguments or environment variables. Argument Env variable Default value Usage --host / --admin-host COZY_HOST / COZY_ADMIN_HOST localhost [http[s]://][:] --port / --admin-port COZY_PORT / COZY_ADMIN_PORT 8080 / 6060 COZY_HOST_TIMEOUT / COZY_ADMIN_TIMOUT 15s HTTP timeout to use Must be a valid golang duration like 10s or 1m COZY_HOST_VALIDATE / COZY_ADMIN_VALIDATE true Enable HTTPS certificate validation Can also be set via host URL query part, like https://localhost:6060?validate=false COZY_HOST_CA / COZY_ADMIN_CA none CA file to use for HTTPS certificate validation Can also be set via host URL query part, like https://localhost:6060?ca= COZY_HOST_CERT / COZY_ADMIN_CERT none Client certificate to use Can also be set via host URL query part, like https://localhost:6060?cert= COZY_HOST_KEY / COZY_ADMIN_KEY none Client certificate to use Can also be set via host URL query part, like https://localhost:6060?key= COZY_HOST_FINGERPRINT / COZY_ADMIN_FINGERPRINT none Hex-encoded SHA-256 key pinning to use Can also be set via host URL query part, like https://localhost:6060?fp= You can get the fingerprint of a given certificate with openssl x509 -in -pubkey \\| openssl pkey -pubin -outform der \\| openssl dgst -sha256 -hex or directly from a private key with openssl pkey -in -pubout -outform der \\| openssl dgst -sha256 -hex", "title": "Stack endpoints"}, {"location": "cozy-stack/config/#administration-secret", "text": "To access to the administration API (the /admin/* routes), a secret passphrase should be stored in a cozy-admin-passphrase . This file should be in one of the configuration directories, along with the main config file. The passphrase is stored in a salted-hashed representation using scrypt. To generate this file, you can use the cozy-stack config passwd [filepath] command. This command will ask you for a passphrase and will create the cozy-admin-passphrase at the specified path. You can use the COZY_ADMIN_PASSPHRASE (or COZY_ADMIN_PASSWORD ) env variable if you do not want to type the passphrase each time you call cozy-stack .", "title": "Administration secret"}, {"location": "cozy-stack/config/#example", "text": "$ mkdir ~/.cozy && cozy-stack config passwd ~/.cozy/cozy-admin-passphrase Hashed passphrase will be writtent in ~/.cozy/cozy-admin-passphrase Passphrase: Confirmation: $ cat ~/.cozy/cozy-admin-passphrase scrypt $16384$8$1$936 bd62faf633b5f946f653c21161a9b $4 e0d11dfa5fc1676ed329938b11a6584d30e603e0d06b8a63a99e8cec392d682", "title": "Example"}, {"location": "cozy-stack/config/#temporary-files", "text": "The stack can use some temporary directories and files (execution of Image Magick, konnectors and services for example). And they can take several GB for the case of importing a Cozy. If needed, it is possible to configure the directory where they will be created via the TMPDIR environment variable.", "title": "Temporary files"}, {"location": "cozy-stack/config/#multiple-couchdb-clusters", "text": "With a large number of instances, a single CouchDB cluster may not be enough. Most cozy-stack administrators can ignore this section, but if you need this advanced settings, let\u2019s see how to configure it. We start with a classical configuration for a single cluster: couchdb : url : http://cluster1:5984/ The first step is to add the new cluster, but still forces the creation on the first cluster for the moment: couchdb : url : http://cluster1:5984/ clusters : - url : http://cluster1:5984/ instance_creation : true - url : http://cluster2:5984/ instance_creation : false Then, we can restart the cozy-stack and everything will work the same, except that the stack now knows how to use an instance on the new cluster. We can now use the second cluster for instance creations instead of the first: couchdb : url : http://cluster1:5984/ clusters : - url : http://cluster1:5984/ instance_creation : false - url : http://cluster2:5984/ instance_creation : true Notes: if several CouchDB clusters are configured to accept creations, a new instance will be put in a CouchDB cluster taken randomly each instance document will keep the list index of the CouchDB cluster used for its databases, so don\u2019t remove a cluster in the middle of the list!", "title": "Multiple CouchDB clusters"}, {"location": "cozy-stack/config/#onlyoffice", "text": "An integration between Cozy and OnlyOffice has been made. It allows the collaborative edition of office documents in the browser. There are some pre-requistes. OnlyOffice Docs must be installed on a server ( The community edition is free but limited to 20 connections and doesn\u2019t have the mobile mode). It can be the same server as the stack, but it is tricky as the default port of the stack and of the spellchecker of OnlyOffice is 8080 for both. The stack and the OnlyOffice components must be able to make HTTP requests to each other. And, for security, these requests can be signed via some shared secrets, called inbox and outbox secrets in OnlyOffice configuration. In the local.json configuration file of OnlyOffice, we need: services.CoAuthoring.token.enable.browser : true services.CoAuthoring.token.enable.request.inbox : true services.CoAuthoring.token.enable.request.outbox : true services.CoAuthoring.secret.inbox : a random secret services.CoAuthoring.secret.outbox : another random secret In the cozy configuration file, we need to add a section with: office : default : onlyoffice_url : https://onlyoffice.example.net/ onlyoffice_inbox_secret : inbox_secret onlyoffice_outbox_secret : outbox_secret Don\u2019t forget to restart all the services after having made the changes to the configuration files. And you should be able to edit office documents in your browser via the Drive application.", "title": "OnlyOffice"}, {"location": "cozy-stack/config/#customizing-a-context", "text": "", "title": "Customizing a context"}, {"location": "cozy-stack/config/#intro", "text": "In the config file of cozy-stack, it\u2019s possible to declare some contexts, that are a way to regroup some cozy instances to give similar configuration. For example, it is possible to give a default_redirection that will be used when the user logs into their cozy. You can find more example in the example config file.", "title": "Intro"}, {"location": "cozy-stack/config/#assets", "text": "The visual appearance of a cozy instance can be customized via some assets (CSS, JS, images). These assets can be inserted from the command-line with the cozy-stack assets add command. Here are a small list of assets that you may want to customize: /styles/theme.css : a CSS file where you can override the colors and put other CSS rules /favicon.ico : the old-school favicon /icon.svg : the favicon in SVG format /icon-192.png and /icon-512.png : the two variants of the favicon /apple-touch-icon.png : the same but for Apple /images/default-avatar.png : the image to use as the default avatar. /images/default-wallpaper.jpg : the image to use as the default wallpapper on the home. /images/icon-cozy-home.svg : the home icon used and displayed by the cozy-bar. /images/icon-cozy-home-inverted.svg : the home icon used and displayed by the cozy-bar when using the theme inverted.", "title": "Assets"}, {"location": "cozy-stack/connection-check/", "text": "Table of contents Connection check URI \u00b6 Connection-check \u00b6 This endpoint respond with HTTP 204 No Content and can be used to test connectivity to cozy instance. It is primarily used by the flagship mobile application. Request \u00b6 GET /connection_check HTTP / 1.1 Host : alice.cozy.example.net Response \u00b6 HTTP/1.1 204", "title": "/connection_check - Connection check"}, {"location": "cozy-stack/connection-check/#connection-check-uri", "text": "", "title": "Connection check URI"}, {"location": "cozy-stack/connection-check/#connection-check", "text": "This endpoint respond with HTTP 204 No Content and can be used to test connectivity to cozy instance. It is primarily used by the flagship mobile application.", "title": "Connection-check"}, {"location": "cozy-stack/connection-check/#request", "text": "GET /connection_check HTTP / 1.1 Host : alice.cozy.example.net", "title": "Request"}, {"location": "cozy-stack/connection-check/#response", "text": "HTTP/1.1 204", "title": "Response"}, {"location": "cozy-stack/contacts/", "text": "Table of contents Contacts \u00b6 Routes \u00b6 POST /contacts/myself \u00b6 This endpoint returns the information about the io.cozy.contacts document for the owner of this instance, the \u201cmyself\u201d contact. If the document does not exist, it is recreated with some basic fields. A permission on the io.cozy.contacts document is required. Request \u00b6 POST /contacts/myself HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.contacts\" , \"id\" : \"bf91cce0-ef48-0137-2638-543d7eb8149c\" , \"attributes\" : { \"fullname\" : \"Alice\" , \"email\" : [ { \"address\" : \"alice@example.com\" , \"primary\" : true } ] }, \"meta\" : { \"rev\" : \"1-6516671ec\" } } }", "title": "/contacts - Contacts"}, {"location": "cozy-stack/contacts/#contacts", "text": "", "title": "Contacts"}, {"location": "cozy-stack/contacts/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/contacts/#post-contactsmyself", "text": "This endpoint returns the information about the io.cozy.contacts document for the owner of this instance, the \u201cmyself\u201d contact. If the document does not exist, it is recreated with some basic fields. A permission on the io.cozy.contacts document is required.", "title": "POST /contacts/myself"}, {"location": "cozy-stack/contacts/#request", "text": "POST /contacts/myself HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/contacts/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.contacts\" , \"id\" : \"bf91cce0-ef48-0137-2638-543d7eb8149c\" , \"attributes\" : { \"fullname\" : \"Alice\" , \"email\" : [ { \"address\" : \"alice@example.com\" , \"primary\" : true } ] }, \"meta\" : { \"rev\" : \"1-6516671ec\" } } }", "title": "Response"}, {"location": "cozy-stack/couchdb-quirks/", "text": "CouchDB Quirks \u00b6 Mango indexes \u00b6 Exists operator \u00b6 The $exists operator can be used with a mango index for the true value, but not for the false value. For false , a more heavy solution is required: a partial index . Index selection \u00b6 CouchDB may accept or refuse to use a mango index for a query, with obsure reasons. In general, you can follow these two rules of thumb: An index on the fields foo, bar, baz can be used only to fetch documents where foo , bar , and baz exist. It means that a query that filters only on the value on foo won\u2019t use the mango index, because it can miss a document where foo has the expected value but without bar or baz . If you know that all the documents that you want have the bar and baz fields, you can just add two filters $exists: true (one for bar , the other for baz ). You should use exactly the same sequence of fields for creating the index and the sort operator of the query. If you have an index on os, browser, ip for the io.cozy.sessions.logins , and you want to have all the documents for a login from windows , sorted by browser , you can use the index, but you should use os, browser, ip for the sort (or at least os, browser , even if it is seems to weird to sort on os when all the sorted documents will have the same value, windows ). Please note that using use_index on a request, the results will be sorted by default according to this rule. So, you can omit the sort operator on the query (except if you want the descending order). Warnings for slow requests \u00b6 When requesting a mango index, CouchDB can use an index. But there are also cases where no index can be used, or where the index is not optimal. Let\u2019s see the different scenarios: CouchDB doesn\u2019t use an index, it will respond with a warning, and cozy-stack will transform this warning in an error, as developers should really avoid this issue CouchDB can use an index for the selector but not for the sort, it will respond with an error, and the cozy-stack will just forward the error CouchDB can use an index, but will still look at much more documents in the index that what will be in the response (it happens with $or and $in operators, which should be avoided), CouchDB 3+ will send a warning and the cozy-stack will forward the documents and the warning to the client. Comparison of strings \u00b6 Comparison of strings is done using ICU which implements the Unicode Collation Algorithm, giving a dictionary sorting of keys. This can give surprising results if you were expecting ASCII ordering. Note that: All symbols sort before numbers and letters (even the \u201chigh\u201d symbols like tilde, 0x7e ) Differing sequences of letters are compared without regard to case, so a < aa but also A < aa and a < AA Identical sequences of letters are compared with regard to case, with lowercase before uppercase, so a < A . Old revisions \u00b6 CouchDB keeps for each document a list of its revision (or more exactly a tree with replication and conflicts). It\u2019s possible to ask the list of the old revisions of a document with GET /db/{docid}?revs_info=true . It works only if the document has not been deleted. For a deleted document, a trick is to query the changes feed to know the last revision of the document, and to recreate the document from this revision. With an old revision, it\u2019s possible to get the content of the document at this revision with GET /db/{docid}?rev={rev} if the database was not compacted. On CouchDB 2.x, compacts happen automatically on all databases from times to times. A purge operation consists to remove the tombstone for the deleted documents. It is a manual operation, triggered by a POST /db/_purge . Conflicts \u00b6 It is possible to create a conflict on CouchDB like it does for the replication by using new_edits: false , but it is not well documented to say the least. The more accurate description was in the old wiki, that no longer exists . Here is a copy of what it said: The replicator uses a special mode of _bulk_docs. The documents it writes to the destination database already have revision IDs that need to be preserved for the two databases to be in sync (otherwise it would not be possible to tell that the two represent the same revision.) To prevent the database from assigning them new revision IDs, a \u201cnew_edits\u201d:false property is added to the JSON request body. Note that this changes the interpretation of the _rev parameter in each document: rather than being the parent revision ID to be matched against, it\u2019s the existing revision ID that will be saved as-is into the database. And since it\u2019s important to retain revision history when adding to the database, each document body in this mode should have a _revisions property that lists its revision history; the format of this property is described on the HTTP document API. For example: curl -X POST -d '{\"new_edits\":false,\"docs\":[{\"_id\":\"person\",\"_rev\":\"2-3595405\",\"_revisions\":{\"start\":2,\"ids\":[\"3595405\",\"877727288\"]},\"name\":\"jim\"}]}' \"$OTHER_DB/_bulk_docs\" This command will replicate one of the revisions created above, into a separate database OTHER_DB . It will have the same revision ID as in DB , 2-3595405 , and it will be known to have a parent revision with ID 1-877727288 . (Even though OTHER_DB will not have the body of that revision, the history will help it detect conflicts in future replications.) As with _all_or_nothing, this mode can create conflicts; in fact, this is where the conflicts created by replication come from. In short, it\u2019s a PUT /doc/{id}?new_edits=false with _rev the new revision of the document, and _revisions the parents of this revision in the revisions tree of this document. Conflict example \u00b6 Here is an example of a CouchDB conflict. Let\u2019s assume the following document with the revision history [1-abc, 2-def] saved in database: { \"_id\": foo, \"_rev\": 2-def, \"bar\": \"tender\", \"_revisions\": { \"ids\": [ \"def\", \"abc\" ] } } The _revisions block is returned when passing revs=true to the query and gives all the revision ids, which the revision part after the dash. For instance, in 2-def , 2 is called the \u201cgeneration\u201d and def the \u201cid\u201d. We update the document with a POST /bulk_docs query, with the following content: { \"docs\": [ { \"_id\": \"foo\", \"_rev\": \"3-ghi\", \"_revisions\": { \"start\": 3, \"ids\": [\"ghi\", \"xyz\", \"abc\"] } , \"bar\": \"racuda\" } ], \"new_edits\": false } This produces a conflict bewteen 2-def and 2-xyz : the former was first saved in database, but we forced the latter to be a new child of 1-abc . Hence, this document will have two revisions branches: 1-abc, 2-def and 1-abc, 2-xyz, 3-ghi . Sharing \u00b6 In the sharing protocol , we implement this behaviour as we follow the CouchDB replication model. However, we prevent CouchDB conflicts for files and directories: see this explanation Design docs in _all_docs \u00b6 When querying GET /{db}/_all_docs , the response include the design docs. It\u2019s quite difficult to filter them, particulary when pagination is involved. We have added an endpoint GET /data/:doctype/_normal_docs to the stack to help client side applications to deal with this.", "title": " /data - CouchDB Quirks"}, {"location": "cozy-stack/couchdb-quirks/#couchdb-quirks", "text": "", "title": "CouchDB Quirks"}, {"location": "cozy-stack/couchdb-quirks/#mango-indexes", "text": "", "title": "Mango indexes"}, {"location": "cozy-stack/couchdb-quirks/#exists-operator", "text": "The $exists operator can be used with a mango index for the true value, but not for the false value. For false , a more heavy solution is required: a partial index .", "title": "Exists operator"}, {"location": "cozy-stack/couchdb-quirks/#index-selection", "text": "CouchDB may accept or refuse to use a mango index for a query, with obsure reasons. In general, you can follow these two rules of thumb: An index on the fields foo, bar, baz can be used only to fetch documents where foo , bar , and baz exist. It means that a query that filters only on the value on foo won\u2019t use the mango index, because it can miss a document where foo has the expected value but without bar or baz . If you know that all the documents that you want have the bar and baz fields, you can just add two filters $exists: true (one for bar , the other for baz ). You should use exactly the same sequence of fields for creating the index and the sort operator of the query. If you have an index on os, browser, ip for the io.cozy.sessions.logins , and you want to have all the documents for a login from windows , sorted by browser , you can use the index, but you should use os, browser, ip for the sort (or at least os, browser , even if it is seems to weird to sort on os when all the sorted documents will have the same value, windows ). Please note that using use_index on a request, the results will be sorted by default according to this rule. So, you can omit the sort operator on the query (except if you want the descending order).", "title": "Index selection"}, {"location": "cozy-stack/couchdb-quirks/#warnings-for-slow-requests", "text": "When requesting a mango index, CouchDB can use an index. But there are also cases where no index can be used, or where the index is not optimal. Let\u2019s see the different scenarios: CouchDB doesn\u2019t use an index, it will respond with a warning, and cozy-stack will transform this warning in an error, as developers should really avoid this issue CouchDB can use an index for the selector but not for the sort, it will respond with an error, and the cozy-stack will just forward the error CouchDB can use an index, but will still look at much more documents in the index that what will be in the response (it happens with $or and $in operators, which should be avoided), CouchDB 3+ will send a warning and the cozy-stack will forward the documents and the warning to the client.", "title": "Warnings for slow requests"}, {"location": "cozy-stack/couchdb-quirks/#comparison-of-strings", "text": "Comparison of strings is done using ICU which implements the Unicode Collation Algorithm, giving a dictionary sorting of keys. This can give surprising results if you were expecting ASCII ordering. Note that: All symbols sort before numbers and letters (even the \u201chigh\u201d symbols like tilde, 0x7e ) Differing sequences of letters are compared without regard to case, so a < aa but also A < aa and a < AA Identical sequences of letters are compared with regard to case, with lowercase before uppercase, so a < A .", "title": "Comparison of strings"}, {"location": "cozy-stack/couchdb-quirks/#old-revisions", "text": "CouchDB keeps for each document a list of its revision (or more exactly a tree with replication and conflicts). It\u2019s possible to ask the list of the old revisions of a document with GET /db/{docid}?revs_info=true . It works only if the document has not been deleted. For a deleted document, a trick is to query the changes feed to know the last revision of the document, and to recreate the document from this revision. With an old revision, it\u2019s possible to get the content of the document at this revision with GET /db/{docid}?rev={rev} if the database was not compacted. On CouchDB 2.x, compacts happen automatically on all databases from times to times. A purge operation consists to remove the tombstone for the deleted documents. It is a manual operation, triggered by a POST /db/_purge .", "title": "Old revisions"}, {"location": "cozy-stack/couchdb-quirks/#conflicts", "text": "It is possible to create a conflict on CouchDB like it does for the replication by using new_edits: false , but it is not well documented to say the least. The more accurate description was in the old wiki, that no longer exists . Here is a copy of what it said: The replicator uses a special mode of _bulk_docs. The documents it writes to the destination database already have revision IDs that need to be preserved for the two databases to be in sync (otherwise it would not be possible to tell that the two represent the same revision.) To prevent the database from assigning them new revision IDs, a \u201cnew_edits\u201d:false property is added to the JSON request body. Note that this changes the interpretation of the _rev parameter in each document: rather than being the parent revision ID to be matched against, it\u2019s the existing revision ID that will be saved as-is into the database. And since it\u2019s important to retain revision history when adding to the database, each document body in this mode should have a _revisions property that lists its revision history; the format of this property is described on the HTTP document API. For example: curl -X POST -d '{\"new_edits\":false,\"docs\":[{\"_id\":\"person\",\"_rev\":\"2-3595405\",\"_revisions\":{\"start\":2,\"ids\":[\"3595405\",\"877727288\"]},\"name\":\"jim\"}]}' \"$OTHER_DB/_bulk_docs\" This command will replicate one of the revisions created above, into a separate database OTHER_DB . It will have the same revision ID as in DB , 2-3595405 , and it will be known to have a parent revision with ID 1-877727288 . (Even though OTHER_DB will not have the body of that revision, the history will help it detect conflicts in future replications.) As with _all_or_nothing, this mode can create conflicts; in fact, this is where the conflicts created by replication come from. In short, it\u2019s a PUT /doc/{id}?new_edits=false with _rev the new revision of the document, and _revisions the parents of this revision in the revisions tree of this document.", "title": "Conflicts"}, {"location": "cozy-stack/couchdb-quirks/#conflict-example", "text": "Here is an example of a CouchDB conflict. Let\u2019s assume the following document with the revision history [1-abc, 2-def] saved in database: { \"_id\": foo, \"_rev\": 2-def, \"bar\": \"tender\", \"_revisions\": { \"ids\": [ \"def\", \"abc\" ] } } The _revisions block is returned when passing revs=true to the query and gives all the revision ids, which the revision part after the dash. For instance, in 2-def , 2 is called the \u201cgeneration\u201d and def the \u201cid\u201d. We update the document with a POST /bulk_docs query, with the following content: { \"docs\": [ { \"_id\": \"foo\", \"_rev\": \"3-ghi\", \"_revisions\": { \"start\": 3, \"ids\": [\"ghi\", \"xyz\", \"abc\"] } , \"bar\": \"racuda\" } ], \"new_edits\": false } This produces a conflict bewteen 2-def and 2-xyz : the former was first saved in database, but we forced the latter to be a new child of 1-abc . Hence, this document will have two revisions branches: 1-abc, 2-def and 1-abc, 2-xyz, 3-ghi .", "title": "Conflict example"}, {"location": "cozy-stack/couchdb-quirks/#sharing", "text": "In the sharing protocol , we implement this behaviour as we follow the CouchDB replication model. However, we prevent CouchDB conflicts for files and directories: see this explanation", "title": "Sharing"}, {"location": "cozy-stack/couchdb-quirks/#design-docs-in-_all_docs", "text": "When querying GET /{db}/_all_docs , the response include the design docs. It\u2019s quite difficult to filter them, particulary when pagination is involved. We have added an endpoint GET /data/:doctype/_normal_docs to the stack to help client side applications to deal with this.", "title": "Design docs in _all_docs"}, {"location": "cozy-stack/data-system/", "text": "Table of contents Data System \u00b6 Typing \u00b6 The notion of document type does not exist in Couchdb. Cozy-stack introduce this notion through a special _type field. This type name cannot contain / , and it should be unique among all developers, it is recommended to use the Java naming convention with a domain you own. All CozyCloud types will be prefixed by io.cozy and be pluralized. Example: /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee Where, io.cozy. is the developer specific prefix, events the actual type, and 6494e0ac-dfcb-11e5-88c1-472e84a9cbee the document\u2019s unique id . Access a document \u00b6 Request \u00b6 GET /data/:type/:id HTTP / 1.1 GET /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Response OK \u00b6 HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json Etag : \"3-6494e0ac6494e0ac\" { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"3-6494e0ac6494e0ac\" , \"startdate\" : \"20160823T150000Z\" , \"enddate\" : \"20160923T160000Z\" , \"summary\" : \"A long month\" , \"description\" : \"I could go on and on and on ....\" } Response Error \u00b6 HTTP / 1.1 404 Not Found Content-Length : ... Content-Type : application/json { \"status\" : 404 , \"error\" : \"not_found\" , \"reason\" : \"deleted\" , \"title\" : \"Event deleted\" , \"details\" : \"Event 6494e0ac-dfcb-11e5-88c1-472e84a9cbee was deleted\" , \"links\" : { \"about\" : \"https://cozy.github.io/cozy-stack/errors.md#deleted\" } } Possible errors \u00b6 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 500 internal server error Access multiple documents at once \u00b6 Request \u00b6 POST /data/:type/_all_docs HTTP / 1.1 POST /data/io.cozy.files/_all_docs?include_docs=true HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"keys\" : [ \"7f46ed4ed2a775494da3b0b44e00314f\" , \"7f46ed4ed2a775494da3b0b44e003b18\" ] } Response OK \u00b6 HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json Etag : \"3-6494e0ac6494e0ac\" { \"total_rows\" : 11 , \"rows\" : [ { \"id\" : \"7f46ed4ed2a775494da3b0b44e00314f\" , \"key\" : \"7f46ed4ed2a775494da3b0b44e00314f\" , \"value\" : { \"rev\" : \"1-870e58f8a1b2130c3a41e767f9c7d93a\" }, \"doc\" : { \"_id\" : \"7f46ed4ed2a775494da3b0b44e00314f\" , \"_rev\" : \"1-870e58f8a1b2130c3a41e767f9c7d93a\" , \"type\" : \"directory\" , \"name\" : \"Uploaded from Cozy Photos\" , \"dir_id\" : \"7f46ed4ed2a775494da3b0b44e0027df\" , \"created_at\" : \"2017-07-04T06:49:12.844631837Z\" , \"updated_at\" : \"2017-07-04T06:49:12.844631837Z\" , \"tags\" : [], \"path\" : \"/Photos/Uploaded from Cozy Photos\" } }, { \"key\" : \"7f46ed4ed2a775494da3b0b44e003b18\" , \"error\" : \"not_found\" } ] } possible errors \u00b6 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 500 internal server error Details \u00b6 When some keys don\u2019t match an existing document, the response still has a status 200 and the errors are included in the rows field (see above, same behavior as CouchDB ). Create a document \u00b6 Request \u00b6 POST /data/:type/ HTTP / 1.1 POST /data/io.cozy.events/ HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T150000\" } Response OK \u00b6 HTTP / 1.1 201 Created Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"1-6494e0ac6494e0ac\" , \"data\" : { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"1-6494e0ac6494e0ac\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T150000\" } } possible errors \u00b6 400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 500 internal server error Details \u00b6 A doc cannot contain an _id field, if so an error 400 is returned A doc cannot contain any field starting with _ , those are reserved for future cozy & couchdb api evolution Update an existing document \u00b6 Request \u00b6 PUT /data/:type/:id HTTP / 1.1 PUT /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"1-6494e0ac6494e0ac\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" } Response OK \u00b6 HTTP / 1.1 200 OK Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"2-056f5f44046ecafc08a2bc2b9c229e20\" , \"data\" : { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"2-056f5f44046ecafc08a2bc2b9c229e20\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" } } Possible errors \u00b6 400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 409 Conflict (see Conflict prevention section below) 500 internal server error Conflict prevention \u00b6 The client MUST give a _rev field in the document. If this field is different from the one in the current version of the document, an error 409 Conflict will be returned. Details \u00b6 If no id is provided in URL, an error 400 is returned If the id provided in URL is not the same than the one in document, an error 400 is returned. Create a document with a fixed id \u00b6 Request \u00b6 PUT /data/:type/:id HTTP / 1.1 PUT /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" } Response OK \u00b6 HTTP / 1.1 200 OK Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"1-056f5f44046ecafc08a2bc2b9c229e20\" , \"data\" : { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"1-056f5f44046ecafc08a2bc2b9c229e20\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" } } Possible errors \u00b6 400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 409 Conflict (see Conflict prevention section below) 500 internal server error Details \u00b6 No id should be provide in the document itself Delete a document \u00b6 Request \u00b6 DELETE /data/:type/:id?rev=:rev HTTP / 1.1 DELETE /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee?rev=1-82a7144c9ec228c9a851b8a1c1aa225b HTTP / 1.1 Accept : application/json Response OK \u00b6 HTTP / 1.1 200 OK Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"2-056f5f44046ecafc08a2bc2b9c229e20\" , \"_deleted\" : true } Possible errors \u00b6 400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 409 Conflict (see Conflict prevention section below) 500 internal server error Conflict prevention \u00b6 It is possible to use either a rev query string parameter or a HTTP If-Match header to prevent conflict on deletion: If none is passed or they are different, an error 400 is returned If only one is passed or they are equals, the document will only be deleted if its _rev match the passed one. Otherwise, an error 409 is returned. Details \u00b6 If no id is provided in URL, an error 400 is returned List all the documents (recommended & paginated way) \u00b6 We have added a non-standard _normal_docs endpoint since _all_docs endpoint sends the design docs in the response and that it makes it hard to use pagination on it. This _normal_docs endpoint skip the design docs (and does not count them in the total_rows ). It accepts three parameters in the query string: limit (default: 100), skip (default: 0), and bookmark (default: \u2018\u2019). The response format looks like a _find response with mango. And, like for _find , the limit cannot be more than 1000. The pagination is also the same: both bookmark and skip can be used, but bookmark is recommended for performances. Request \u00b6 GET /data/io.cozy.events/_normal_docs?limit=100&bookmark=g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76 HTTP / 1.1 Accept : application/json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"rows\" : [ { \"_id\" : \"16e458537602f5ef2a710089dffd9453\" , \"_rev\" : \"1-967a00dff5e02add41819138abb3284d\" , \"field\" : \"value\" }, { \"_id\" : \"f4ca7773ddea715afebc4b4b15d4f0b3\" , \"_rev\" : \"2-7051cbe5c8faecd085a3fa619e6e6337\" , \"field\" : \"other-value\" }, ... ], \"total_rows\" : 202 , \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76\" } List all the documents (alternative & not pagginated way) \u00b6 You can use _all_docs endpoint to get the list of all the documents. In some cases the use of this route is legitimate, but we recommend to avoid it as much as possible. The stack also supports a Fields query parameter to only include those fields in the response (with an uppercase F to avoid collusion with a possible future fields by CouchDB), and a DesignDocs query parameter to skip design docs. Example: ?Fields=name,metadata.title,tags&DesignDocs=false . Request \u00b6 GET /data/io.cozy.events/_all_docs?include_docs=true HTTP / 1.1 Accept : application/json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"offset\" : 0 , \"rows\" : [ { \"id\" : \"16e458537602f5ef2a710089dffd9453\" , \"key\" : \"16e458537602f5ef2a710089dffd9453\" , \"value\" : { \"rev\" : \"1-967a00dff5e02add41819138abb3284d\" }, \"doc\" : { \"field\" : \"value\" } }, { \"id\" : \"f4ca7773ddea715afebc4b4b15d4f0b3\" , \"key\" : \"f4ca7773ddea715afebc4b4b15d4f0b3\" , \"value\" : { \"rev\" : \"2-7051cbe5c8faecd085a3fa619e6e6337\" }, \"doc\" : { \"field\" : \"other-value\" } } ], \"total_rows\" : 2 } Details \u00b6 See _all_docs in couchdb docs List the known doctypes \u00b6 A permission on io.cozy.doctypes for GET is needed to query this endoint. Request \u00b6 GET /data/_all_doctypes HTTP / 1.1 Accept : application/json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json [ \"io.cozy.files\" , \"io.cozy.jobs\" , \"io.cozy.triggers\" , \"io.cozy.settings\" ] Others \u00b6 The creation and usage of Mango indexes is possible. CouchDB behaviors are not always straight forward: see some quirks for more details. Access a design document \u00b6 A design document is a special CouchDB document that represents a view or Mango index definition. Request \u00b6 GET /data/:type/_design/:ddoc HTTP / 1.1 GET /data/io.cozy.events/_design/c4a8fa4a4660b8eed43137881500265c HTTP / 1.1 Response OK \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"_id\" : \"_design/c4a8fa4a4660b8eed43137881500265c\" , \"_rev\" : \"1-56cf55098fc69450f84a22a632ffafb9\" , \"language\" : \"query\" , \"views\" : { \"by-startdate-and-enddate\" : { \"map\" : { \"fields\" : { \"startdate\" : \"asc\" , \"enddate\" : \"asc\" , }, \"partial_filter_selector\" : {} }, \"reduce\" : \"_count\" , \"options\" : { \"def\" : { \"fields\" : [ \"startdate\" , \"enddate\" , \"metadata.datetime\" ] } } } } } Access all design documents for a doctype \u00b6 Request \u00b6 GET /data/:type/_design_docs HTTP / 1.1 GET /data/io.cozy.events/_design_docs HTTP / 1.1 Response OK \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"total_rows\" : 123 , \"offset\" : 57 , \"rows\" : [ ... ] } Delete a design document \u00b6 Request \u00b6 DELETE /data/:type/_design/:ddoc HTTP / 1.1 DELETE /data/io.cozy.events/_design/c4a8fa4a4660b8eed43137881500265c?rev=1-1aa097a2eef904db9b1842342e6c6f50 HTTP / 1.1 Response OK \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"ok\" : true , \"id\" : \"_design/c4a8fa4a4660b8eed43137881500265c\" , \"rev\" : \"2-2ad11c9dc32df12a4b24f994807408ba\" } Copy a design document \u00b6 This is useful to duplicate a view or Mango index definition, without having to recompute the whole B-Tree. The original and the copy will both use the same index on disk. Request \u00b6 POST /data/:type/_design/:ddoc/copy HTTP / 1.1 POST /data/io.cozy.events/_design/c4a8fa4a4660b8eed43137881500265c/copy?rev=1-1aa097a2eef904db9b1842342e6c6f50 HTTP / 1.1 Destination : _design/d7349ab71c0859c408a725ebbfd453b18aa94ec7 Response OK \u00b6 HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true , \"id\" : \"_design/d7349ab71c0859c408a725ebbfd453b18aa94ec7\" , \"rev\" : \"1-1aa097a2eef904db9b1842342e6c6f50\" } Delete a database \u00b6 Request \u00b6 DELETE /data/:type/ HTTP / 1.1 DELETE /data/io.cozy.events/ HTTP / 1.1 Response OK \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"ok\" : true , \"deleted\" : true }", "title": "/data - Data System"}, {"location": "cozy-stack/data-system/#data-system", "text": "", "title": "Data System"}, {"location": "cozy-stack/data-system/#typing", "text": "The notion of document type does not exist in Couchdb. Cozy-stack introduce this notion through a special _type field. This type name cannot contain / , and it should be unique among all developers, it is recommended to use the Java naming convention with a domain you own. All CozyCloud types will be prefixed by io.cozy and be pluralized. Example: /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee Where, io.cozy. is the developer specific prefix, events the actual type, and 6494e0ac-dfcb-11e5-88c1-472e84a9cbee the document\u2019s unique id .", "title": "Typing"}, {"location": "cozy-stack/data-system/#access-a-document", "text": "", "title": "Access a document"}, {"location": "cozy-stack/data-system/#request", "text": "GET /data/:type/:id HTTP / 1.1 GET /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok", "text": "HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json Etag : \"3-6494e0ac6494e0ac\" { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"3-6494e0ac6494e0ac\" , \"startdate\" : \"20160823T150000Z\" , \"enddate\" : \"20160923T160000Z\" , \"summary\" : \"A long month\" , \"description\" : \"I could go on and on and on ....\" }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#response-error", "text": "HTTP / 1.1 404 Not Found Content-Length : ... Content-Type : application/json { \"status\" : 404 , \"error\" : \"not_found\" , \"reason\" : \"deleted\" , \"title\" : \"Event deleted\" , \"details\" : \"Event 6494e0ac-dfcb-11e5-88c1-472e84a9cbee was deleted\" , \"links\" : { \"about\" : \"https://cozy.github.io/cozy-stack/errors.md#deleted\" } }", "title": "Response Error"}, {"location": "cozy-stack/data-system/#possible-errors", "text": "401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 500 internal server error", "title": "Possible errors"}, {"location": "cozy-stack/data-system/#access-multiple-documents-at-once", "text": "", "title": "Access multiple documents at once"}, {"location": "cozy-stack/data-system/#request_1", "text": "POST /data/:type/_all_docs HTTP / 1.1 POST /data/io.cozy.files/_all_docs?include_docs=true HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"keys\" : [ \"7f46ed4ed2a775494da3b0b44e00314f\" , \"7f46ed4ed2a775494da3b0b44e003b18\" ] }", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_1", "text": "HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json Etag : \"3-6494e0ac6494e0ac\" { \"total_rows\" : 11 , \"rows\" : [ { \"id\" : \"7f46ed4ed2a775494da3b0b44e00314f\" , \"key\" : \"7f46ed4ed2a775494da3b0b44e00314f\" , \"value\" : { \"rev\" : \"1-870e58f8a1b2130c3a41e767f9c7d93a\" }, \"doc\" : { \"_id\" : \"7f46ed4ed2a775494da3b0b44e00314f\" , \"_rev\" : \"1-870e58f8a1b2130c3a41e767f9c7d93a\" , \"type\" : \"directory\" , \"name\" : \"Uploaded from Cozy Photos\" , \"dir_id\" : \"7f46ed4ed2a775494da3b0b44e0027df\" , \"created_at\" : \"2017-07-04T06:49:12.844631837Z\" , \"updated_at\" : \"2017-07-04T06:49:12.844631837Z\" , \"tags\" : [], \"path\" : \"/Photos/Uploaded from Cozy Photos\" } }, { \"key\" : \"7f46ed4ed2a775494da3b0b44e003b18\" , \"error\" : \"not_found\" } ] }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#possible-errors_1", "text": "401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 500 internal server error", "title": "possible errors"}, {"location": "cozy-stack/data-system/#details", "text": "When some keys don\u2019t match an existing document, the response still has a status 200 and the errors are included in the rows field (see above, same behavior as CouchDB ).", "title": "Details"}, {"location": "cozy-stack/data-system/#create-a-document", "text": "", "title": "Create a document"}, {"location": "cozy-stack/data-system/#request_2", "text": "POST /data/:type/ HTTP / 1.1 POST /data/io.cozy.events/ HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T150000\" }", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_2", "text": "HTTP / 1.1 201 Created Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"1-6494e0ac6494e0ac\" , \"data\" : { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"1-6494e0ac6494e0ac\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T150000\" } }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#possible-errors_2", "text": "400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 500 internal server error", "title": "possible errors"}, {"location": "cozy-stack/data-system/#details_1", "text": "A doc cannot contain an _id field, if so an error 400 is returned A doc cannot contain any field starting with _ , those are reserved for future cozy & couchdb api evolution", "title": "Details"}, {"location": "cozy-stack/data-system/#update-an-existing-document", "text": "", "title": "Update an existing document"}, {"location": "cozy-stack/data-system/#request_3", "text": "PUT /data/:type/:id HTTP / 1.1 PUT /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"1-6494e0ac6494e0ac\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" }", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_3", "text": "HTTP / 1.1 200 OK Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"2-056f5f44046ecafc08a2bc2b9c229e20\" , \"data\" : { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"2-056f5f44046ecafc08a2bc2b9c229e20\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" } }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#possible-errors_3", "text": "400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 409 Conflict (see Conflict prevention section below) 500 internal server error", "title": "Possible errors"}, {"location": "cozy-stack/data-system/#conflict-prevention", "text": "The client MUST give a _rev field in the document. If this field is different from the one in the current version of the document, an error 409 Conflict will be returned.", "title": "Conflict prevention"}, {"location": "cozy-stack/data-system/#details_2", "text": "If no id is provided in URL, an error 400 is returned If the id provided in URL is not the same than the one in document, an error 400 is returned.", "title": "Details"}, {"location": "cozy-stack/data-system/#create-a-document-with-a-fixed-id", "text": "", "title": "Create a document with a fixed id"}, {"location": "cozy-stack/data-system/#request_4", "text": "PUT /data/:type/:id HTTP / 1.1 PUT /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee HTTP / 1.1 Content-Length : ... Content-Type : application/json Accept : application/json { \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" }", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_4", "text": "HTTP / 1.1 200 OK Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"1-056f5f44046ecafc08a2bc2b9c229e20\" , \"data\" : { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"_rev\" : \"1-056f5f44046ecafc08a2bc2b9c229e20\" , \"startdate\" : \"20160712T150000\" , \"enddate\" : \"20160712T200000\" } }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#possible-errors_4", "text": "400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 409 Conflict (see Conflict prevention section below) 500 internal server error", "title": "Possible errors"}, {"location": "cozy-stack/data-system/#details_3", "text": "No id should be provide in the document itself", "title": "Details"}, {"location": "cozy-stack/data-system/#delete-a-document", "text": "", "title": "Delete a document"}, {"location": "cozy-stack/data-system/#request_5", "text": "DELETE /data/:type/:id?rev=:rev HTTP / 1.1 DELETE /data/io.cozy.events/6494e0ac-dfcb-11e5-88c1-472e84a9cbee?rev=1-82a7144c9ec228c9a851b8a1c1aa225b HTTP / 1.1 Accept : application/json", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_5", "text": "HTTP / 1.1 200 OK Content-Length : ... Content-Type : application/json { \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"type\" : \"io.cozy.events\" , \"ok\" : true , \"rev\" : \"2-056f5f44046ecafc08a2bc2b9c229e20\" , \"_deleted\" : true }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#possible-errors_5", "text": "400 bad request 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 404 not_found reason: missing reason: deleted 409 Conflict (see Conflict prevention section below) 500 internal server error", "title": "Possible errors"}, {"location": "cozy-stack/data-system/#conflict-prevention_1", "text": "It is possible to use either a rev query string parameter or a HTTP If-Match header to prevent conflict on deletion: If none is passed or they are different, an error 400 is returned If only one is passed or they are equals, the document will only be deleted if its _rev match the passed one. Otherwise, an error 409 is returned.", "title": "Conflict prevention"}, {"location": "cozy-stack/data-system/#details_4", "text": "If no id is provided in URL, an error 400 is returned", "title": "Details"}, {"location": "cozy-stack/data-system/#list-all-the-documents-recommended-paginated-way", "text": "We have added a non-standard _normal_docs endpoint since _all_docs endpoint sends the design docs in the response and that it makes it hard to use pagination on it. This _normal_docs endpoint skip the design docs (and does not count them in the total_rows ). It accepts three parameters in the query string: limit (default: 100), skip (default: 0), and bookmark (default: \u2018\u2019). The response format looks like a _find response with mango. And, like for _find , the limit cannot be more than 1000. The pagination is also the same: both bookmark and skip can be used, but bookmark is recommended for performances.", "title": "List all the documents (recommended & paginated way)"}, {"location": "cozy-stack/data-system/#request_6", "text": "GET /data/io.cozy.events/_normal_docs?limit=100&bookmark=g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76 HTTP / 1.1 Accept : application/json", "title": "Request"}, {"location": "cozy-stack/data-system/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"rows\" : [ { \"_id\" : \"16e458537602f5ef2a710089dffd9453\" , \"_rev\" : \"1-967a00dff5e02add41819138abb3284d\" , \"field\" : \"value\" }, { \"_id\" : \"f4ca7773ddea715afebc4b4b15d4f0b3\" , \"_rev\" : \"2-7051cbe5c8faecd085a3fa619e6e6337\" , \"field\" : \"other-value\" }, ... ], \"total_rows\" : 202 , \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76\" }", "title": "Response"}, {"location": "cozy-stack/data-system/#list-all-the-documents-alternative-not-pagginated-way", "text": "You can use _all_docs endpoint to get the list of all the documents. In some cases the use of this route is legitimate, but we recommend to avoid it as much as possible. The stack also supports a Fields query parameter to only include those fields in the response (with an uppercase F to avoid collusion with a possible future fields by CouchDB), and a DesignDocs query parameter to skip design docs. Example: ?Fields=name,metadata.title,tags&DesignDocs=false .", "title": "List all the documents (alternative & not pagginated way)"}, {"location": "cozy-stack/data-system/#request_7", "text": "GET /data/io.cozy.events/_all_docs?include_docs=true HTTP / 1.1 Accept : application/json", "title": "Request"}, {"location": "cozy-stack/data-system/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"offset\" : 0 , \"rows\" : [ { \"id\" : \"16e458537602f5ef2a710089dffd9453\" , \"key\" : \"16e458537602f5ef2a710089dffd9453\" , \"value\" : { \"rev\" : \"1-967a00dff5e02add41819138abb3284d\" }, \"doc\" : { \"field\" : \"value\" } }, { \"id\" : \"f4ca7773ddea715afebc4b4b15d4f0b3\" , \"key\" : \"f4ca7773ddea715afebc4b4b15d4f0b3\" , \"value\" : { \"rev\" : \"2-7051cbe5c8faecd085a3fa619e6e6337\" }, \"doc\" : { \"field\" : \"other-value\" } } ], \"total_rows\" : 2 }", "title": "Response"}, {"location": "cozy-stack/data-system/#details_5", "text": "See _all_docs in couchdb docs", "title": "Details"}, {"location": "cozy-stack/data-system/#list-the-known-doctypes", "text": "A permission on io.cozy.doctypes for GET is needed to query this endoint.", "title": "List the known doctypes"}, {"location": "cozy-stack/data-system/#request_8", "text": "GET /data/_all_doctypes HTTP / 1.1 Accept : application/json", "title": "Request"}, {"location": "cozy-stack/data-system/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/json [ \"io.cozy.files\" , \"io.cozy.jobs\" , \"io.cozy.triggers\" , \"io.cozy.settings\" ]", "title": "Response"}, {"location": "cozy-stack/data-system/#others", "text": "The creation and usage of Mango indexes is possible. CouchDB behaviors are not always straight forward: see some quirks for more details.", "title": "Others"}, {"location": "cozy-stack/data-system/#access-a-design-document", "text": "A design document is a special CouchDB document that represents a view or Mango index definition.", "title": "Access a design document"}, {"location": "cozy-stack/data-system/#request_9", "text": "GET /data/:type/_design/:ddoc HTTP / 1.1 GET /data/io.cozy.events/_design/c4a8fa4a4660b8eed43137881500265c HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_6", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"_id\" : \"_design/c4a8fa4a4660b8eed43137881500265c\" , \"_rev\" : \"1-56cf55098fc69450f84a22a632ffafb9\" , \"language\" : \"query\" , \"views\" : { \"by-startdate-and-enddate\" : { \"map\" : { \"fields\" : { \"startdate\" : \"asc\" , \"enddate\" : \"asc\" , }, \"partial_filter_selector\" : {} }, \"reduce\" : \"_count\" , \"options\" : { \"def\" : { \"fields\" : [ \"startdate\" , \"enddate\" , \"metadata.datetime\" ] } } } } }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#access-all-design-documents-for-a-doctype", "text": "", "title": "Access all design documents for a doctype"}, {"location": "cozy-stack/data-system/#request_10", "text": "GET /data/:type/_design_docs HTTP / 1.1 GET /data/io.cozy.events/_design_docs HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_7", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"total_rows\" : 123 , \"offset\" : 57 , \"rows\" : [ ... ] }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#delete-a-design-document", "text": "", "title": "Delete a design document"}, {"location": "cozy-stack/data-system/#request_11", "text": "DELETE /data/:type/_design/:ddoc HTTP / 1.1 DELETE /data/io.cozy.events/_design/c4a8fa4a4660b8eed43137881500265c?rev=1-1aa097a2eef904db9b1842342e6c6f50 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_8", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"ok\" : true , \"id\" : \"_design/c4a8fa4a4660b8eed43137881500265c\" , \"rev\" : \"2-2ad11c9dc32df12a4b24f994807408ba\" }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#copy-a-design-document", "text": "This is useful to duplicate a view or Mango index definition, without having to recompute the whole B-Tree. The original and the copy will both use the same index on disk.", "title": "Copy a design document"}, {"location": "cozy-stack/data-system/#request_12", "text": "POST /data/:type/_design/:ddoc/copy HTTP / 1.1 POST /data/io.cozy.events/_design/c4a8fa4a4660b8eed43137881500265c/copy?rev=1-1aa097a2eef904db9b1842342e6c6f50 HTTP / 1.1 Destination : _design/d7349ab71c0859c408a725ebbfd453b18aa94ec7", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_9", "text": "HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true , \"id\" : \"_design/d7349ab71c0859c408a725ebbfd453b18aa94ec7\" , \"rev\" : \"1-1aa097a2eef904db9b1842342e6c6f50\" }", "title": "Response OK"}, {"location": "cozy-stack/data-system/#delete-a-database", "text": "", "title": "Delete a database"}, {"location": "cozy-stack/data-system/#request_13", "text": "DELETE /data/:type/ HTTP / 1.1 DELETE /data/io.cozy.events/ HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/data-system/#response-ok_10", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"ok\" : true , \"deleted\" : true }", "title": "Response OK"}, {"location": "cozy-stack/delegated-auth/", "text": "Table of contents Delegated authentication \u00b6 In general, the cozy stack manages the authentication itself. In some cases, an integration with other softwares can be mandatory. It\u2019s possible to use JWT or OpenID Connect, with a bit of configuration to do that. JWT \u00b6 To enable an external system to create links with a JWT to log in users for cozy instances in a given context, we just need to add the secret to use for checking the JWT in the config, like this: authentication : the-context-name : jwt_secret : s3cr3t The external system can then create a JWT, with the parameter name as the instance domain, and send the user to https:///?jwt=... . The user will be logged in, and redirected to its default application. Open ID Connect \u00b6 OpenID Connect can also be used, and is more adapted when the users don\u2019t always come from the authentication provider. For OpenID Connect, there are more configuration parameters and they must be configured per context. A context is set of configuration parameters and each Cozy instance belongs to one context. authentication : the-context-name : disable_password_authentication : false oidc : client_id : aClientID client_secret : s3cret3 scope : openid profile login_domain : login.mycozy.cloud redirect_uri : https://oauthcallback.mycozy.cloud/oidc/redirect authorize_url : https://identity-provider/path/to/authorize token_url : https://identity-provider/path/to/token userinfo_url : https://identity-provider/path/to/userinfo userinfo_instance_field : cozy_number userinfo_instance_prefix : name userinfo_instance_suffix : .mycozy.cloud allow_custom_instance : false allow_oauth_token : false id_token_jwk_url : https://identity-provider/path/to/jwk Let\u2019s see what it means: disable_password_authentication can be set to true to disable the classic password authentication on the Cozy, and forces the user to login with OpenID Connect. And in the oidc section, we have: client_id and client_secret are the OAuth client that will be used to talk to the identity provider scope is the OAuth scope parameter (it is often openid profile ) login_domain is a domain that is not tied to an instance, but allows to login with OIDC with the provider configured on this context redirect_uri is where the user will be redirected by the identity provider after login (it must often be declared when creating the OAuth client, and we have to use a static hostname, not the hostname of a cozy instance) logout_url can be set to redirect the user to this URL after they have been logged out token_url , authorize_url , and userinfo_url are the URLs used to talk to the identity provider (they ofter can be found by the discovery mechanism of OpenID Connect with the names token_endpoint , authorization_endpoint , and userinfo_endpoint ) userinfo_instance_field is the JSON field to use in the UserInfo response to know the cozy instance of the logged in user. userinfo_instance_prefix and userinfo_instance_suffix are optional, and will be put before and after the field fetched from the UserInfo response to give the complete instance URL allow_custom_instance can be set to true to let the user chooses their instance name allow_oauth_token must be set to true to enable the POST /oidc/access_token route (see below for more details). With the example config, if the UserInfo response contains \"cozy_number\": \"00001\" , the user can login on the instance name00001.mycozy.cloud . When allow_custom_instance is set to true, the stack will look at the sub field in the UserInfo response, and checks that it matches the oidc_id set on this instance (and the userinfo_instance_* and login_domain fields are ignored). If id_token_jwk_url is set, the client can send the ID token from the provider instead of the access token. This token will be checked with the key fetched from this URL, and the sub field of it must match the oidc_id set in the instance. Routes \u00b6 Let\u2019s see the 3 routes used in this process GET /oidc/start \u00b6 To start the OpenID Connect dance, the user can go to this URL. It will redirect him/her to the identity provider with the rights parameter. The user will also be redirected here if they are not connected and that the password authentication is disabled. GET /oidc/start HTTP / 1.1 Host : name00001.mycozy.cloud HTTP / 1.1 303 See Other Location : https://identity-provider/path/to/authorize?response_type=code&state=9f6873dfce7d&scope=openid+profile&client_id=aClientID&nonce=94246498&redirect_uri=https://oauthcallback.mycozy.cloud/oidc/redirect GET /oidc/redirect \u00b6 Then, the user can log in on the identity provider, and then he/she will be redirected to this URL. Note that the URL is on a generic domain: the stack will redirect the user to his/her instance (where it\u2019s possible to create cookies to log in the user). GET /oidc/redirect?state=9f6873dfce7d&code=ccd0032a HTTP / 1.1 Host : oauthcallback.mycozy.cloud HTTP / 1.1 303 See Other Location : https://name00001.mycozy.cloud/oidc/login?state=9f6873dfce7d&code=ccd0032a GET /oidc/login \u00b6 On this route, the stack can create the session for the user, with the cookies. GET /oidc/login?code=ccd0032a HTTP / 1.1 Host : name00001.mycozy.cloud HTTP / 1.1 303 See Other Set-Cookie : ... Location : https://name00001-home.mycozy.cloud/ If the allow_oauth_token option is enabled, it\u2019s possible to use an access_token instead of code on this URL. If the id_token_jwk_url option is enabled, it\u2019s possible to use an id_token instead. POST /oidc/twofactor \u00b6 If the instance is protected with two-factor authentication, the login route will render an HTML page with JavaScript to check if the user has trusted the device. And the JavaScript submit a form to this route. If the trusted device token is set, a session will be created. Else, a mail with a code is sent, and the user is redirected to a page where they can type the two-factor code. POST /oidc/twofactor HTTP / 1.1 Host : name00001.mycozy.cloud Content-Type : application/x-www-form-urlencoded trusted-device-token=xxx&access-token=yyy&redirect=&confirm= HTTP / 1.1 303 See Other Set-Cookie : ... Location : https://name00001-home.mycozy.cloud/ POST /oidc/access_token \u00b6 This additional route can be used by an OAuth client (like a mobile app) when delegated authentication via OpenID Connect is enabled. It allows the client to obtain an access_token for requesting the cozy-stack in exchange of a token valid on the OpenID Connect Identity Provider. POST /oidc/access_token HTTP / 1.1 Host : name00001.mycozy.cloud Accept : application/json Content-Type : application/json { \"client_id\" : \"55eda056e85468fdfe2c8440d4009cbe\" , \"client_secret\" : \"DttCGIUOTniVNkivR_CsZ_xRoME9gghN\" , \"scope\" : \"io.cozy.files io.cozy.photos.albums\" , \"oidc_token\" : \"769fa760-59de-11e9-a167-9bab3784e3e7\" } HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"ooch1Yei\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"ui0Ohch8\" , \"scope\" : \"io.cozy.files io.cozy.photos.albums\" } If id_token_jwk_url option is set, the client can send an id_token instead of an oidc_token in the payload. If the flagship makes the request, it also can use a delegated code obtained from the cloudery, by using code instead of oidc_token . Note: if the OAuth client asks for a * scope and has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app. Special case of 2FA \u00b6 When 2FA is enabled on the instance, the stack will first respond with: HTTP / 1.1 403 Forbidden Content-Type : application/json { \"error\" : \"two factor needed\" , \"two_factor_token\" : \"123123123123\" } and the client must ask the user to type its 6-digits code, and then make again the request: { \"access_token\" : \"ooch1Yei\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"ui0Ohch8\" , \"scope\" : \"io.cozy.files io.cozy.photos.albums\" , \"two_factor_token\" : \"123123123123\" , \"two_factor_passcode\" : \"678678\" } FranceConnect \u00b6 It is pretty much the same thing as OIDC. It\u2019s logical as FranceConnect is an OIDC provider. But we have made a special case for the login page. The differences are that the flow is started with GET /oidc/franceconnect (instead of GET /oidc/start ) and the configuration looks like this: authentication : the-context-name : franceconnect : client_id : aClientID client_secret : s3cret3 scope : openid email redirect_uri : https://oauthcallback.mycozy.cloud/oidc/redirect authorize_url : https://identity-provider/path/to/authorize token_url : https://identity-provider/path/to/token userinfo_url : https://identity-provider/path/to/userinfo The last 3 URL can be omited for production.", "title": " /oidc - Delegated authentication"}, {"location": "cozy-stack/delegated-auth/#delegated-authentication", "text": "In general, the cozy stack manages the authentication itself. In some cases, an integration with other softwares can be mandatory. It\u2019s possible to use JWT or OpenID Connect, with a bit of configuration to do that.", "title": "Delegated authentication"}, {"location": "cozy-stack/delegated-auth/#jwt", "text": "To enable an external system to create links with a JWT to log in users for cozy instances in a given context, we just need to add the secret to use for checking the JWT in the config, like this: authentication : the-context-name : jwt_secret : s3cr3t The external system can then create a JWT, with the parameter name as the instance domain, and send the user to https:///?jwt=... . The user will be logged in, and redirected to its default application.", "title": "JWT"}, {"location": "cozy-stack/delegated-auth/#open-id-connect", "text": "OpenID Connect can also be used, and is more adapted when the users don\u2019t always come from the authentication provider. For OpenID Connect, there are more configuration parameters and they must be configured per context. A context is set of configuration parameters and each Cozy instance belongs to one context. authentication : the-context-name : disable_password_authentication : false oidc : client_id : aClientID client_secret : s3cret3 scope : openid profile login_domain : login.mycozy.cloud redirect_uri : https://oauthcallback.mycozy.cloud/oidc/redirect authorize_url : https://identity-provider/path/to/authorize token_url : https://identity-provider/path/to/token userinfo_url : https://identity-provider/path/to/userinfo userinfo_instance_field : cozy_number userinfo_instance_prefix : name userinfo_instance_suffix : .mycozy.cloud allow_custom_instance : false allow_oauth_token : false id_token_jwk_url : https://identity-provider/path/to/jwk Let\u2019s see what it means: disable_password_authentication can be set to true to disable the classic password authentication on the Cozy, and forces the user to login with OpenID Connect. And in the oidc section, we have: client_id and client_secret are the OAuth client that will be used to talk to the identity provider scope is the OAuth scope parameter (it is often openid profile ) login_domain is a domain that is not tied to an instance, but allows to login with OIDC with the provider configured on this context redirect_uri is where the user will be redirected by the identity provider after login (it must often be declared when creating the OAuth client, and we have to use a static hostname, not the hostname of a cozy instance) logout_url can be set to redirect the user to this URL after they have been logged out token_url , authorize_url , and userinfo_url are the URLs used to talk to the identity provider (they ofter can be found by the discovery mechanism of OpenID Connect with the names token_endpoint , authorization_endpoint , and userinfo_endpoint ) userinfo_instance_field is the JSON field to use in the UserInfo response to know the cozy instance of the logged in user. userinfo_instance_prefix and userinfo_instance_suffix are optional, and will be put before and after the field fetched from the UserInfo response to give the complete instance URL allow_custom_instance can be set to true to let the user chooses their instance name allow_oauth_token must be set to true to enable the POST /oidc/access_token route (see below for more details). With the example config, if the UserInfo response contains \"cozy_number\": \"00001\" , the user can login on the instance name00001.mycozy.cloud . When allow_custom_instance is set to true, the stack will look at the sub field in the UserInfo response, and checks that it matches the oidc_id set on this instance (and the userinfo_instance_* and login_domain fields are ignored). If id_token_jwk_url is set, the client can send the ID token from the provider instead of the access token. This token will be checked with the key fetched from this URL, and the sub field of it must match the oidc_id set in the instance.", "title": "Open ID Connect"}, {"location": "cozy-stack/delegated-auth/#routes", "text": "Let\u2019s see the 3 routes used in this process", "title": "Routes"}, {"location": "cozy-stack/delegated-auth/#get-oidcstart", "text": "To start the OpenID Connect dance, the user can go to this URL. It will redirect him/her to the identity provider with the rights parameter. The user will also be redirected here if they are not connected and that the password authentication is disabled. GET /oidc/start HTTP / 1.1 Host : name00001.mycozy.cloud HTTP / 1.1 303 See Other Location : https://identity-provider/path/to/authorize?response_type=code&state=9f6873dfce7d&scope=openid+profile&client_id=aClientID&nonce=94246498&redirect_uri=https://oauthcallback.mycozy.cloud/oidc/redirect", "title": "GET /oidc/start"}, {"location": "cozy-stack/delegated-auth/#get-oidcredirect", "text": "Then, the user can log in on the identity provider, and then he/she will be redirected to this URL. Note that the URL is on a generic domain: the stack will redirect the user to his/her instance (where it\u2019s possible to create cookies to log in the user). GET /oidc/redirect?state=9f6873dfce7d&code=ccd0032a HTTP / 1.1 Host : oauthcallback.mycozy.cloud HTTP / 1.1 303 See Other Location : https://name00001.mycozy.cloud/oidc/login?state=9f6873dfce7d&code=ccd0032a", "title": "GET /oidc/redirect"}, {"location": "cozy-stack/delegated-auth/#get-oidclogin", "text": "On this route, the stack can create the session for the user, with the cookies. GET /oidc/login?code=ccd0032a HTTP / 1.1 Host : name00001.mycozy.cloud HTTP / 1.1 303 See Other Set-Cookie : ... Location : https://name00001-home.mycozy.cloud/ If the allow_oauth_token option is enabled, it\u2019s possible to use an access_token instead of code on this URL. If the id_token_jwk_url option is enabled, it\u2019s possible to use an id_token instead.", "title": "GET /oidc/login"}, {"location": "cozy-stack/delegated-auth/#post-oidctwofactor", "text": "If the instance is protected with two-factor authentication, the login route will render an HTML page with JavaScript to check if the user has trusted the device. And the JavaScript submit a form to this route. If the trusted device token is set, a session will be created. Else, a mail with a code is sent, and the user is redirected to a page where they can type the two-factor code. POST /oidc/twofactor HTTP / 1.1 Host : name00001.mycozy.cloud Content-Type : application/x-www-form-urlencoded trusted-device-token=xxx&access-token=yyy&redirect=&confirm= HTTP / 1.1 303 See Other Set-Cookie : ... Location : https://name00001-home.mycozy.cloud/", "title": "POST /oidc/twofactor"}, {"location": "cozy-stack/delegated-auth/#post-oidcaccess_token", "text": "This additional route can be used by an OAuth client (like a mobile app) when delegated authentication via OpenID Connect is enabled. It allows the client to obtain an access_token for requesting the cozy-stack in exchange of a token valid on the OpenID Connect Identity Provider. POST /oidc/access_token HTTP / 1.1 Host : name00001.mycozy.cloud Accept : application/json Content-Type : application/json { \"client_id\" : \"55eda056e85468fdfe2c8440d4009cbe\" , \"client_secret\" : \"DttCGIUOTniVNkivR_CsZ_xRoME9gghN\" , \"scope\" : \"io.cozy.files io.cozy.photos.albums\" , \"oidc_token\" : \"769fa760-59de-11e9-a167-9bab3784e3e7\" } HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"ooch1Yei\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"ui0Ohch8\" , \"scope\" : \"io.cozy.files io.cozy.photos.albums\" } If id_token_jwk_url option is set, the client can send an id_token instead of an oidc_token in the payload. If the flagship makes the request, it also can use a delegated code obtained from the cloudery, by using code instead of oidc_token . Note: if the OAuth client asks for a * scope and has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app.", "title": "POST /oidc/access_token"}, {"location": "cozy-stack/delegated-auth/#special-case-of-2fa", "text": "When 2FA is enabled on the instance, the stack will first respond with: HTTP / 1.1 403 Forbidden Content-Type : application/json { \"error\" : \"two factor needed\" , \"two_factor_token\" : \"123123123123\" } and the client must ask the user to type its 6-digits code, and then make again the request: { \"access_token\" : \"ooch1Yei\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"ui0Ohch8\" , \"scope\" : \"io.cozy.files io.cozy.photos.albums\" , \"two_factor_token\" : \"123123123123\" , \"two_factor_passcode\" : \"678678\" }", "title": "Special case of 2FA"}, {"location": "cozy-stack/delegated-auth/#franceconnect", "text": "It is pretty much the same thing as OIDC. It\u2019s logical as FranceConnect is an OIDC provider. But we have made a special case for the login page. The differences are that the flow is started with GET /oidc/franceconnect (instead of GET /oidc/start ) and the configuration looks like this: authentication : the-context-name : franceconnect : client_id : aClientID client_secret : s3cret3 scope : openid email redirect_uri : https://oauthcallback.mycozy.cloud/oidc/redirect authorize_url : https://identity-provider/path/to/authorize token_url : https://identity-provider/path/to/token userinfo_url : https://identity-provider/path/to/userinfo The last 3 URL can be omited for production.", "title": "FranceConnect"}, {"location": "cozy-stack/docker/", "text": "Table of contents Docker \u00b6 This page list various operations that can be automated via Docker when developing cozy-stack. For docker usage in production to self-host your cozy instance, please refer to our Self Hosting Documentation . Running a CouchDB instance \u00b6 This will run a new instance of CouchDB in single mode (no cluster). This command exposes couchdb on the port 5984 . $ docker run -d \\ --name cozy-stack-couch \\ -p 5984 :5984 \\ -e COUCHDB_USER = admin -e COUCHDB_PASSWORD = password \\ -v $HOME /.cozy-stack-couch:/opt/couchdb/data \\ couchdb:3.3 $ curl -X PUT http://admin:password@127.0.0.1:5984/ { _users,_replicator } Verify your installation at: http://127.0.0.1:5984/_utils/#verifyinstall. Note: for running some unit tests, you will need to use --net=host instead of -p 5984:5984 as we are using CouchDB replications and CouchDB will need to be able to open a connexion to the stack. Building a cozy-stack via Docker \u00b6 Warning, this command will build a linux binary. Use GOOS and GOARCH to adapt to your own system. # From your cozy-stack developement folder docker run -it --rm --name cozy-stack \\ --workdir /app \\ -v $( pwd ) :/app \\ -v $( pwd ) :/go/bin \\ golang:1.22 \\ go get -v github.com/cozy/cozy-stack Publishing a new cozy-app-dev image \u00b6 We publish the cozy-app-dev image when we release a new version of the stack. See scripts/docker/cozy-app-dev/release.sh for details. Docker run and url name for cozy-app-dev \u00b6 A precision for the app name: docker run --rm -it -p 8080 :8080 -v \" $( pwd ) /build\" :/data/cozy-app/***my-app*** cozy/cozy-app-dev my-app will be the first part of: my-app .cozy.localhost:8080 Only-Office document server \u00b6 The cozy/onlyoffice-dev docker image can be used for local development on Linux (the --net=host option doesn\u2019t work on macOS). Just start it with: $ docker run -it --rm --name = oodev --net = host cozy/onlyoffice-dev and run the stack with: $ cozy-stack serve --disable-csp --onlyoffice-url = http://localhost:8000 --onlyoffice-inbox-secret = inbox_secret --onlyoffice-outbox-secret = outbox_secret $ cozy-stack features defaults '{\"drive.office\": {\"enabled\": true, \"write\": true}}' If you need to rebuild it, you can do that with: $ cd scripts/onlyoffice-dev $ docker build -t \"cozy/onlyoffice-dev\" .", "title": "Running and building Docker images"}, {"location": "cozy-stack/docker/#docker", "text": "This page list various operations that can be automated via Docker when developing cozy-stack. For docker usage in production to self-host your cozy instance, please refer to our Self Hosting Documentation .", "title": "Docker"}, {"location": "cozy-stack/docker/#running-a-couchdb-instance", "text": "This will run a new instance of CouchDB in single mode (no cluster). This command exposes couchdb on the port 5984 . $ docker run -d \\ --name cozy-stack-couch \\ -p 5984 :5984 \\ -e COUCHDB_USER = admin -e COUCHDB_PASSWORD = password \\ -v $HOME /.cozy-stack-couch:/opt/couchdb/data \\ couchdb:3.3 $ curl -X PUT http://admin:password@127.0.0.1:5984/ { _users,_replicator } Verify your installation at: http://127.0.0.1:5984/_utils/#verifyinstall. Note: for running some unit tests, you will need to use --net=host instead of -p 5984:5984 as we are using CouchDB replications and CouchDB will need to be able to open a connexion to the stack.", "title": "Running a CouchDB instance"}, {"location": "cozy-stack/docker/#building-a-cozy-stack-via-docker", "text": "Warning, this command will build a linux binary. Use GOOS and GOARCH to adapt to your own system. # From your cozy-stack developement folder docker run -it --rm --name cozy-stack \\ --workdir /app \\ -v $( pwd ) :/app \\ -v $( pwd ) :/go/bin \\ golang:1.22 \\ go get -v github.com/cozy/cozy-stack", "title": "Building a cozy-stack via Docker"}, {"location": "cozy-stack/docker/#publishing-a-new-cozy-app-dev-image", "text": "We publish the cozy-app-dev image when we release a new version of the stack. See scripts/docker/cozy-app-dev/release.sh for details.", "title": "Publishing a new cozy-app-dev image"}, {"location": "cozy-stack/docker/#docker-run-and-url-name-for-cozy-app-dev", "text": "A precision for the app name: docker run --rm -it -p 8080 :8080 -v \" $( pwd ) /build\" :/data/cozy-app/***my-app*** cozy/cozy-app-dev my-app will be the first part of: my-app .cozy.localhost:8080", "title": "Docker run and url name for cozy-app-dev"}, {"location": "cozy-stack/docker/#only-office-document-server", "text": "The cozy/onlyoffice-dev docker image can be used for local development on Linux (the --net=host option doesn\u2019t work on macOS). Just start it with: $ docker run -it --rm --name = oodev --net = host cozy/onlyoffice-dev and run the stack with: $ cozy-stack serve --disable-csp --onlyoffice-url = http://localhost:8000 --onlyoffice-inbox-secret = inbox_secret --onlyoffice-outbox-secret = outbox_secret $ cozy-stack features defaults '{\"drive.office\": {\"enabled\": true, \"write\": true}}' If you need to rebuild it, you can do that with: $ cd scripts/onlyoffice-dev $ docker build -t \"cozy/onlyoffice-dev\" .", "title": "Only-Office document server"}, {"location": "cozy-stack/doctype/", "text": "Table of contents Adding a new doctype \u00b6 There is currently several steps to add a new doctype. We hope to improve that in the near future. For the moment, this guide can help you to not forget a step. Choosing a name for your doctype \u00b6 The doctype name is something like io.cozy.contacts . The io.cozy prefix is reserved for doctypes created and managed by Cozy Cloud. If you have an official website, you can use it (in reversed order) for the prefix. Else, you can use your github or gitlab handle: github.nono or gitlab.nono . Then, you can add a plural noun to indicate what is the type of the documents. If you have several related doctypes, it is common to nest them. For example, io.cozy.contacts.accounts is the accounts of external services used to synchronize the io.cozy.accounts . The name of the doctype must be composed of only lowercase letters, digits, . and _ characters. Add documentation about your doctype \u00b6 The doctypes are documented on https://docs.cozy.io/en/cozy-doctypes/docs/ to help other developers to reuse the same doctypes. If you think that your doctype may be useful to others, you can make a pull request on the https://github.com/cozy/cozy-doctypes repository. \u26a0\ufe0f Do not forget to put a link to this new doc into: the toc.yml file so that it appears in the navigation menus. the Readme.md file so that it appears the index page. Note: it\u2019s the docs directory that you should update. The other directories are used by remote doctypes . Add your doctype to the store and stack \u00b6 Both the store and the stack knows of the doctypes, for showing permissions. For the store, it is shown to the user before installing an application that uses this doctype. For the stack, it is used for showing permissions for sharings and OAuth clients. In both cases, there is a short description of the doctype, localized on transifex, and an icon to illustrate it. Here are the relevant places: https://github.com/cozy/cozy-store/blob/master/src/locales/en.json https://github.com/cozy/cozy-store/blob/master/src/config/permissionsIcons.json https://github.com/cozy/cozy-store/tree/master/src/assets/icons/permissions https://github.com/cozy/cozy-stack/blob/master/assets/locales/en.po https://github.com/cozy/cozy-stack/blob/master/assets/styles/cirrus.css Using the doctype in your application \u00b6 Of course, after all those efforts, you want to use your new doctype in your application. Do not forget to add a permission in the manifest to use it!", "title": "Adding a new doctype"}, {"location": "cozy-stack/doctype/#adding-a-new-doctype", "text": "There is currently several steps to add a new doctype. We hope to improve that in the near future. For the moment, this guide can help you to not forget a step.", "title": "Adding a new doctype"}, {"location": "cozy-stack/doctype/#choosing-a-name-for-your-doctype", "text": "The doctype name is something like io.cozy.contacts . The io.cozy prefix is reserved for doctypes created and managed by Cozy Cloud. If you have an official website, you can use it (in reversed order) for the prefix. Else, you can use your github or gitlab handle: github.nono or gitlab.nono . Then, you can add a plural noun to indicate what is the type of the documents. If you have several related doctypes, it is common to nest them. For example, io.cozy.contacts.accounts is the accounts of external services used to synchronize the io.cozy.accounts . The name of the doctype must be composed of only lowercase letters, digits, . and _ characters.", "title": "Choosing a name for your doctype"}, {"location": "cozy-stack/doctype/#add-documentation-about-your-doctype", "text": "The doctypes are documented on https://docs.cozy.io/en/cozy-doctypes/docs/ to help other developers to reuse the same doctypes. If you think that your doctype may be useful to others, you can make a pull request on the https://github.com/cozy/cozy-doctypes repository. \u26a0\ufe0f Do not forget to put a link to this new doc into: the toc.yml file so that it appears in the navigation menus. the Readme.md file so that it appears the index page. Note: it\u2019s the docs directory that you should update. The other directories are used by remote doctypes .", "title": "Add documentation about your doctype"}, {"location": "cozy-stack/doctype/#add-your-doctype-to-the-store-and-stack", "text": "Both the store and the stack knows of the doctypes, for showing permissions. For the store, it is shown to the user before installing an application that uses this doctype. For the stack, it is used for showing permissions for sharings and OAuth clients. In both cases, there is a short description of the doctype, localized on transifex, and an icon to illustrate it. Here are the relevant places: https://github.com/cozy/cozy-store/blob/master/src/locales/en.json https://github.com/cozy/cozy-store/blob/master/src/config/permissionsIcons.json https://github.com/cozy/cozy-store/tree/master/src/assets/icons/permissions https://github.com/cozy/cozy-stack/blob/master/assets/locales/en.po https://github.com/cozy/cozy-stack/blob/master/assets/styles/cirrus.css", "title": "Add your doctype to the store and stack"}, {"location": "cozy-stack/doctype/#using-the-doctype-in-your-application", "text": "Of course, after all those efforts, you want to use your new doctype in your application. Do not forget to add a permission in the manifest to use it!", "title": "Using the doctype in your application"}, {"location": "cozy-stack/files/", "text": "Table of contents Virtual File System \u00b6 Cozy applications can use files for storing binary content, like photos or bills in PDF. This service offers a REST API to manipulate easily without having to know the underlying storage layer. The metadata are kept in CouchDB, but the binaries can go to the local system, or a Swift instance. Directories \u00b6 A directory is a container for files and sub-directories. Its path is the path of its parent, a slash ( / ), and its name. It\u2019s case sensitive. Root directory \u00b6 The root of the virtual file system is a special directory with id io.cozy.files.root-dir . You can use it in any request where you would use a directory, except you cannot delete it. POST /files/:dir-id \u00b6 Create a new directory. The dir-id parameter is optional. When it\u2019s not given, the directory is created at the root of the virtual file system. Query-String \u00b6 Parameter Description Type directory Name the directory name Tags an array of tags CreatedAt the creation date MetadataID the identifier of a metadata object HTTP headers \u00b6 Parameter Description Date The modification date of the directory Request \u00b6 POST /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?Type=directory&Name=phone&Tags=bills,konnectors HTTP / 1.1 Accept : application/vnd.api+json Date : Mon, 19 Sep 2016 12:35:08 GMT Status codes \u00b6 201 Created, when the directory has been successfully created 404 Not Found, when the parent directory does not exist 409 Conflict, when a directory with the same name already exists 422 Unprocessable Entity, when the Type , Name , or MetadataID parameter is missing or invalid Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"meta\" : { \"rev\" : \"1-ff3beeb456eb\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"phone\" , \"path\" : \"/Documents/phone\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" , \"konnectors\" ], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:48Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:48Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"not_synchronized_on\" : { \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on\" }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" } ] } }, \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } } } Note : see not synchronized directories for more informations about the not_synchronized_on field. POST /files/shared-drives \u00b6 This endpoint returns the information about the Shared Drives directory. If the directory does not exist, it is created. Request \u00b6 POST /files/shared-drives Accept: application/vnd.api+json Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"io.cozy.files.shared-drives-dir\" , \"meta\" : { \"rev\" : \"1-e4abdb5a\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Drives\" , \"path\" : \"/Drives\" , \"created_at\" : \"2024-03-25T15:22:00Z\" , \"updated_at\" : \"2024-03-25T15:22:00Z\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2024-03-25T15:22:00Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2024-03-25T15:22:00Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/io.cozy.files.root-dir\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"io.cozy.files.root-dir\" } } }, \"links\" : { \"self\" : \"/files/io.cozy.files.shared-drives-dir\" } } } GET /files/:file-id \u00b6 Get a directory or a file informations. In the case of a directory, it contains the list of files and sub-directories inside it. For a note, its images are included. Contents is paginated following jsonapi conventions . The default limit is 30 entries. Request \u00b6 GET /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81 HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"links\" : { \"next\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?page[cursor]=9152d568-7e7c-11e6-a377-37cbfb190b4b\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" , \"meta\" : { \"rev\" : \"1-e36ab092\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Documents\" , \"path\" : \"/Documents\" , \"created_at\" : \"2016-09-19T12:35:00Z\" , \"updated_at\" : \"2016-09-19T12:35:00Z\" , \"tags\" : [], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:47Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:47Z\" } }, \"relationships\" : { \"contents\" : { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" } ] } }, \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"included\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"meta\" : { \"rev\" : \"1-ff3beeb456eb\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"phone\" , \"path\" : \"/Documents/phone\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" , \"konnectors\" ], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:47Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:47Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.txt\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } ] } GET /files/:file-id/size \u00b6 This endpoint returns the size taken by the files in a directory, including those in subdirectories. Request \u00b6 GET /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/size HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.sizes\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" , \"attributes\" : { \"size\" : \"1234567890\" }, \"meta\" : {} } } GET /files/_changes \u00b6 This endpoint is similar to the changes feed of CouchDB for io.cozy.files. There are a few specificities: it is wrapped in the VFS lock to avoid seeing inconsistent results it automatically skips design docs if the requests is coming from an OAuth client, it excludes the files and directories that are in a not synchronized folder it only supports the options since , limit , and include_docs of CouchDB it has an option fields to only include those fields in the results it has an option include_file_path to add the path for files it has two options skip_deleted and skip_trashed to not send to the client the deleted/trashed files and directories. Request \u00b6 GET /files/_changes?include_docs=true&fields=type,name,dir_id&skip_deleted=true&limit=3 HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"last_seq\" : \"13-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTeXKAQe5Jpmrl5ojG68iwA2MMV1A\" , \"pending\" : 24 , \"results\" : [ { \"id\" : \"io.cozy.files.root-dir\" , \"seq\" : \"11-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTuXKAQe5Jpmrl5ojG68iwA2IcV0g\" , \"doc\" : { \"type\" : \"directory\" }, \"changes\" : [ { \"rev\" : \"1-077f26acac6f0a5e1022f109e8d1dfc4\" } ] }, { \"id\" : \"io.cozy.files.trash-dir\" , \"seq\" : \"12-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kSeXKAQe5Jpmrl5ojG68iwA2KUV0w\" , \"doc\" : { \"dir_id\" : \"io.cozy.files.root-dir\" , \"name\" : \".cozy_trash\" , \"type\" : \"directory\" }, \"changes\" : [ { \"rev\" : \"1-de9c11dbc386b5f91adbe2aee4a3e754\" } ] }, { \"id\" : \"d30b0dd6e0e8fefdac2a94cb2c00249f\" , \"seq\" : \"13-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTeXKAQe5Jpmrl5ojG68iwA2MMV1A\" , \"doc\" : { \"dir_id\" : \"io.cozy.files.root-dir\" , \"name\" : \"Administratif\" , \"type\" : \"directory\" }, \"changes\" : [ { \"rev\" : \"1-24f2828e8dbe64135913072a4c92d846\" } ] } ] } POST /files/_find \u00b6 Find allows to find documents using a mango selector. You can read more about mango selectors here . Note that it returns a bookmark in the links , useful to paginate (following the JSON-API pagination ). On the last page, there won\u2019t be a links.next . It is possible to pass a execution_stats parameter to get some information about the query execution. See here for more details. Request \u00b6 POST /files/_find HTTP / 1.1 { \"selector\" : { \"class\" : \"image\" , \"trashed\" : false }, \"limit\" : 2 , \"bookmark\" : \"g1AAAABjeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorpFokG5qaGVqYmCWbGxuYGFkYWhgkmqaZJZsZGpibWhiA9HHA9OWATAJpY83MTUxPTWFgTUvMKU7NygIA7IYZzA\" , \"use_index\" : \"_design/a5f4711fc9448864a13c81dc71e660b524d7410c\" , \"execution_stats\" : true } Response \u00b6 HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"e8c1561846c730428180a5f6c6107914\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"nicepic1.jpg\" , \"dir_id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"created_at\" : \"2020-02-13T16:35:47.568155477+01:00\" , \"updated_at\" : \"2020-02-13T16:35:47.568155477+01:00\" , \"size\" : \"345385\" , \"md5sum\" : \"12cGYwT+RiNjFxf4f7AmzQ==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"tags\" : [], \"path\" : \"/Pictures/nicepic1.jpg\" , \"metadata\" : { \"datetime\" : \"2020-02-13T16:35:47.568155477+01:00\" , \"extractor_version\" : 2 , \"height\" : 1080 , \"width\" : 1920 } }, \"meta\" : { \"rev\" : \"2-235e715b1d82a93285be1b0bd691b779\" }, \"links\" : { \"self\" : \"/files/e8c1561846c730428180a5f6c6107914\" , \"tiny\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/tiny\" , \"small\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/small\" , \"medium\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/medium\" , \"large\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/large\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f49b4087cbf946dfc759214394009a6c\" }, \"data\" : { \"id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"type\" : \"io.cozy.files\" } } } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"e8c1561846c730428180a5f6c6109007\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"nicepic2.jpg\" , \"dir_id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"created_at\" : \"2020-02-13T16:35:47.845049743+01:00\" , \"updated_at\" : \"2020-02-13T16:35:47.845049743+01:00\" , \"size\" : \"323009\" , \"md5sum\" : \"Fla3ucNXuW2Xw/TK8pfsPA==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"tags\" : [], \"path\" : \"/Pictures/nicepic2.jpg\" , \"metadata\" : { \"datetime\" : \"2020-02-13T16:35:47.845049743+01:00\" , \"extractor_version\" : 2 , \"height\" : 1080 , \"width\" : 1920 } }, \"meta\" : { \"rev\" : \"2-4883d6b8ccad32f8fb056af9b7f8b37f\" }, \"links\" : { \"self\" : \"/files/e8c1561846c730428180a5f6c6109007\" , \"tiny\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/tiny\" , \"small\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/small\" , \"medium\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/medium\" , \"large\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/large\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f49b4087cbf946dfc759214394009a6c\" }, \"data\" : { \"id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"type\" : \"io.cozy.files\" } } } } ], \"links\" : { \"next\" : \"/files/_find?page[cursor]=g1AAAABjeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorpFokG5qaGVqYmCWbGxuYGFkYWhgkmqaZJZsZGlgaGJiD9HHA9OWATAJpY83MTUxPTWFgTUvMKU7NygIA694ZyA\" }, \"meta\" : { \"count\" : 2 , \"execution_stats\" : { \"total_docs_examined\" : 11 , \"results_returned\" : 2 , \"execution_time_ms\" : 8.833 } } } DELETE /files/:dir-id \u00b6 Put a directory and its subtree in the trash. It requires the permissions on io.cozy.files for PATCH . HTTP headers \u00b6 It\u2019s possible to send the If-Match header, with the previous revision of the file/directory (optional). Files \u00b6 A file is a binary content with some metadata. POST /files/:dir-id \u00b6 Upload a file in the directory identified by :dir-id . The created_at field will be the first valid value in this list: the datetime extracted from the EXIF for a photo the CreatedAt parameter from the query-string the Date HTTP header the current time from the server. The updated_at field will be the first value in this list: the datetime extracted from the EXIF for a photo if it is greater than the other values the UpdatedAt parameter from the query-string the Date HTTP header the current time from the server. /!\\ If the updated_at field is older than the created_at one, then the updated_at will be set with the value of the created_at . Query-String \u00b6 Parameter Description Type file Name the file name Size the file size (when Content-Length can\u2019t be used) Tags an array of tags Executable true if the file is executable (UNIX permission) Encrypted true if the file is client-side encrypted Metadata a JSON with metadata on this file ( not recommended ) MetadataID the identifier of a metadata object CreatedAt the creation date of the file UpdatedAt the modification date of the file SourceAccount the id of the source account used by a konnector SourceAccountIdentifier the unique identifier of the account targeted by the connector HTTP headers \u00b6 Parameter Description Content-Length The file size Content-MD5 A Base64-encoded binary MD5 sum of the file Content-Type The mime-type of the file Date The modification date of the file Request \u00b6 POST /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?Type=file&Name=hello.txt&CreatedAt=2016-09-18T01:23:45Z HTTP / 1.1 Accept : application/vnd.api+json Content-Length : 12 Content-MD5 : hvsmnRkNLIX24EaM7KQqIA== Content-Type : text/plain Date : Mon, 19 Sep 2016 12:38:04 GMT Host : cozy.example.com Hello world! Status codes \u00b6 201 Created, when the file has been successfully created 404 Not Found, when the parent directory does not exist 409 Conflict, when a file with the same name already exists 412 Precondition Failed, when the md5sum is Content-MD5 is not equal to the md5sum computed by the server 413 Payload Too Large, when there is not enough available space on the cozy to upload the file or the file is larger than the server\u2019s filesystem maximum file size 422 Unprocessable Entity, when the sent data is invalid (for example, the parent doesn\u2019t exist, Type , Name , or MetadataID parameter is missing or invalid, etc.) Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"sunset.jpg\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-18T20:38:04Z\" , \"updated_at\" : \"2016-09-21T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2016-09-18T20:38:04Z\" , \"height\" : 1080 , \"width\" : 1920 }, \"size\" : 12 , \"executable\" : false , \"class\" : \"image\" , \"mime\" : \"image/jpg\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-21T14:46:37Z\" , \"uploadedAt\" : \"2016-09-20T18:37:52Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references\" }, \"data\" : [ { \"type\" : \"io.cozy.albums\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] }, \"old_versions\" : { \"data\" : [ { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec\" }, { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72\" } ] } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"tiny\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/tiny\" , \"small\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/small\" , \"medium\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/medium\" , \"large\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/large\" } }, \"included\" : [ { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec\" , \"meta\" : { \"rev\" : \"1-26a331\" }, \"attributes\" : { \"file_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"updated_at\" : \"2016-09-21T10:11:12Z\" , \"md5sum\" : \"a2lth5syMW+4r7jwNhdk3A==\" , \"size\" : 123456 , \"tags\" : [], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:37:52Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:37:52Z\" , \"uploadedAt\" : \"2016-09-20T18:37:52Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } } }, { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72\" , \"meta\" : { \"rev\" : \"1-57b3e2\" }, \"attributes\" : { \"file_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"updated_at\" : \"2016-09-18T20:38:04Z\" , \"md5sum\" : \"FBA89XXOZKFhdv37iILb2Q==\" , \"size\" : 159753 , \"tags\" : [], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } } } ] } Note : see references of documents in VFS for more informations about the references field. POST /files/upload/metadata \u00b6 Send a metadata object that can be associated to a file (or directory) uploaded after that, via the MetadataID query parameter. The MetadataID parameter is only valid for 10 minutes, and will expire after that. Note: a special permission on io.cozy.certified.carbon_copy is required to send a request with carbonCopy as key in the attributes map. Same for electronicSafe . See the metadata doctype to know more about metadata attributes that can be set, notably for images and document qualification. Request \u00b6 POST /files/upload/metadata HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.metadata\" , \"attributes\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" }, \"datetime\" : \"2017-04-22T01:00:00-05:00\" } } } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.metadata\" , \"id\" : \"42E6BD48\" , \"attributes\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" }, \"datetime\" : \"2017-04-22T01:00:00-05:00\" } } } GET /files/download/:file-id \u00b6 Download the file content. By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1 For a PDF file, it\u2019s possible to get only a single page by using the Page parameter in the query-string (1 is the first page). Request \u00b6 GET /files/download/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81 HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Length : 12 Content-Disposition : inline; filename=\"hello.txt\" Content-Type : text/plain Hello world! GET /files/download \u00b6 Download the file content from its path. By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1 For a PDF file, it\u2019s possible to get only a single page by using the Page parameter in the query-string (1 is the first page). Request \u00b6 GET /files/download?Path=/Documents/hello.txt&Dl=1 HTTP / 1.1 GET /files/:file-id/icon/:secret \u00b6 Get an image that shows the first page of a PDF in a small resolution (96x96). Note: this route is deprecated, you should use thumbnails instead. GET /files/:file-id/preview/:secret \u00b6 Get an image that shows the first page of a PDF (at most 1080x1920). Note: this route is deprecated, you should use thumbnails instead. GET /files/:file-id/thumbnails/:secret/:format \u00b6 Get a thumbnail of a file (for an image & pdf only). :format can be tiny (96x96) small (640x480), medium (1280x720), or large (1920x1080). This API does not require authentication because the secret acts as a token. This secret is valid for 10 minutes, after which the link will return an error. To retrieve a new functional link, you must query the files API again to obtain a new secret. PUT /files/:file-id \u00b6 Overwrite a file The updated_at field will be the first value in this list: the datetime extracted from the EXIF for a photo if it is greater than the other values the UpdatedAt parameter from the query-string the Date HTTP header the current time from the server. /!\\ If the updated_at field is older than the created_at one, then the updated_at will be set with the value of the created_at . Query-String \u00b6 Parameter Description Size the file size (when Content-Length can\u2019t be used) Tags an array of tags Executable true if the file is executable (UNIX permission) Encrypted true if the file is client-side encrypted MetadataID the identifier of a metadata object UpdatedAt the modification date of the file SourceAccount the id of the source account used by a konnector SourceAccountIdentifier the unique identifier of the account targeted by the connector HTTP headers \u00b6 The HTTP headers are the same than for uploading a file. There is one additional header, If-Match , with the previous revision of the file (optional). Request \u00b6 PUT /files/9152d568-7e7c-11e6-a377-37cbfb190b4b HTTP / 1.1 Accept : application/vnd.api+json Content-Length : 12 Content-MD5 : hvsmnRkNLIX24EaM7KQqIA== Content-Type : text/plain If-Match : 1-0e6d5b72 HELLO WORLD! Status codes \u00b6 200 OK, when the file has been successfully overwritten 404 Not Found, when the file wasn\u2019t existing 412 Precondition Failed, when the If-Match header is set and doesn\u2019t match the last revision of the file 413 Payload Too Large, when there is not enough available space on the cozy to upload the file or the file is larger than the server\u2019s filesystem maximum file size 422 Unprocessable Entity, when the sent data is invalid (for example, the MetadataID parameter has expired) Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"2-d903b54c\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.pdf\" , \"trashed\" : false , \"md5sum\" : \"YjU5YmMzN2Q2NDQxZDk2Nwo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"pdf\" , \"mime\" : \"application/pdf\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-21T04:27:50Z\" , \"uploadedAt\" : \"2016-09-21T04:27:50Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"icon\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/icon/543d7eb8\" , \"preview\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/preview/77e117e0\" , \"tiny\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/tiny\" , \"small\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/small\" , \"medium\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/medium\" , \"large\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/large\" } } } POST /files/:file-id/copy \u00b6 Create a copy of a file in the same directory with a copy suffix in its name Query-String \u00b6 Parameter Description Name the file copy name (optional) DirID the destination directory id (optional) Request \u00b6 POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/copy HTTP / 1.1 Accept : application/vnd.api+json Status codes \u00b6 201 Created, when the file has been successfully copied 404 Not Found, when the file does not exist 409 Conflict, when a file with the same name as the copy would have already exists 413 Payload Too Large, when there is not enough available space on the cozy to copy the file Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"7382f28a-21d4-12d9-4438-3fd53e98a219\" , \"meta\" : { \"rev\" : \"1-83a82e9\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello (copy).pdf\" , \"trashed\" : false , \"md5sum\" : \"YjU5YmMzN2Q2NDQxZDk2Nwo=\" , \"created_at\" : \"2022-10-18T18:33:24Z\" , \"updated_at\" : \"2022-10-18T18:33:24Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"pdf\" , \"mime\" : \"application/pdf\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2022-10-18T18:33:24Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2022-10-18T18:33:24Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219\" , \"icon\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/icon/543d7eb8\" , \"preview\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/preview/77e117e0\" , \"tiny\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/tiny\" , \"small\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/small\" , \"medium\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/medium\" , \"large\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/large\" } } } DELETE /files/:file-id \u00b6 Put a file in the trash. Common \u00b6 GET /files/metadata \u00b6 Same as /files/:file-id but to retrieve informations from a path. Request \u00b6 GET /files/metadata?Path=/Documents/hello.txt HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.txt\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } } PATCH /files/:file-id and PATCH /files/metadata \u00b6 Both endpoints can be used to update the metadata of a file or directory, or to rename/move it. The difference is the first one uses an id to identify the file/directory to update, and the second one uses the path. Some specific attributes of the patch can be used: dir_id attribute can be updated to move a file or directory move_to_trash boolean to specify that the file needs to be moved to the trash permanent_delete boolean to specify that the files needs to be deleted (after being trashed) cozyMetadata.favorite boolean attribute to put/remove a file from the favorites HTTP headers \u00b6 It\u2019s possible to send the If-Match header, with the previous revision of the file/directory (optional). Request \u00b6 PATCH /files/9152d568-7e7c-11e6-a377-37cbfb190b4b HTTP / 1.1 Accept : application/vnd.api+json Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hi.txt\" , \"dir_id\" : \"f2f36fec-8018-11e6-abd8-8b3814d9a465\" , \"tags\" : [ \"poem\" ], \"cozyMetadata\" : { \"favorite\" : true } } } } Status codes \u00b6 200 OK, when the file or directory metadata has been successfully updated 400 Bad Request, when a the directory is asked to move to one of its sub-directories 404 Not Found, when the file/directory wasn\u2019t existing 412 Precondition Failed, when the If-Match header is set and doesn\u2019t match the last revision of the file/directory 422 Unprocessable Entity, when the sent data is invalid (for example, the parent doesn\u2019t exist) Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hi.txt\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [ \"poem\" ], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-22T13:32:51Z\" , \"uploadedAt\" : \"2016-09-21T04:27:50Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f2f36fec-8018-11e6-abd8-8b3814d9a465\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f2f36fec-8018-11e6-abd8-8b3814d9a465\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } } PATCH /files/ \u00b6 Endpoint to update the metadata of files and directories in batch. It can be used, for instance, to move many files in a single request. Request \u00b6 PATCH /files/ HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"dir_id\" : \"f2f36fec-8018-11e6-abd8-8b3814d9a465\" } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4c\" , \"meta\" : { \"rev\" : \"2-123123\" }, \"attributes\" : { \"move_to_trash\" : true } } ] } Status codes \u00b6 The same status codes can be encountered as the PATCH /files/:file-id route. POST /files/archive \u00b6 Create an archive. The body of the request lists the files and directories that will be included in the archive. For directories, it includes all the files and sub-directories in the archive. It\u2019s possible to give a file by its id (in the ids array) or by its path (in the files array). For PDF files, it\u2019s possible to put in the archive a single page, with the pages argument: it\u2019s an array of objects, with id the file identifier of the PDF file, and page the page number (1 is the first page). The generated archive is temporary and is not persisted. Request \u00b6 POST /files/archive HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.archives\" , \"attributes\" : { \"name\" : \"project-X\" , \"ids\" : [ \"a51aeeea-4f79-11e7-9dc4-83f67e9494ab\" ], \"files\" : [ \"/Documents/bills\" , \"/Documents/images/sunset.jpg\" , \"/Documents/images/eiffel-tower.jpg\" ], \"pages\" : [ { \"id\" : \"3780caf0-104f-013d-3619-18c04daba326\" , \"page\" : 1 } ] } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"links\" : { \"related\" : \"/files/archive/4521DC87/project-X.zip\" }, \"data\" : { \"type\" : \"io.cozy.files.archives\" , \"id\" : \"4521DC87\" , \"attributes\" : { \"href\" : \"/files/archive/4521DC87/project-X.zip\" } } } GET /files/archive/:key/:name \u00b6 Download a previously created archive. The name parameter is not used in the stack but aims to allow setting a name even for browser / downloader that do not support Content-Disposition filename. This route does not require Basic Authentification GET /files/archive/4521DC87/project-X.zip HTTP / 1.1 Accept : application/zip Content-Length : 12345 Content-Disposition : attachment; filename=\"project-X.zip\" Content-Type : application/zip POST /files/downloads?Path=file_path \u00b6 Create a file download. The Path query parameter specifies the file to download. The response json API links contains a related link for downloading the file, see below. POST /files/downloads?Id=file_id \u00b6 Also create a file download. But it takes the id of the file and not its path. POST /files/downloads?VersionId=file_id/version_id \u00b6 This is a third way to create a file download. But, this time, it is for downloading an old version of a file. These 3 routes also accept a Filename=... parameter in the query-string to change the filename that will be used for the downloaded file. GET /files/downloads/:secret/:name \u00b6 Allows to download a file with a secret created from the route above. The name parameter is not used in the stack but aims to allow setting a name even for browser / downloader that do not support Content-Disposition filename. By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1 This route does not require Basic Authentification Versions \u00b6 The identifier of the io.cozy.files.versions is composed of the file-id and another string called the version-id , separated by a / . So, when a route makes reference to /something/:file-id/:version-id , you can use the identifier of the version document (without having to prepend the file identifier). GET /files/download/:file-id/:version-id \u00b6 Download an old version of the file content By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1 Request \u00b6 GET /files/download/9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72 HTTP / 1.1 POST /files/:file-id/versions \u00b6 Create a new version of a file, with the same content but new metadata. It requires a permission for PUT on the file, as it is equivalent to upload the same content of the file. Query-String \u00b6 Parameter Description Tags an array of tags Request \u00b6 POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/metadata HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.metadata\" , \"attributes\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" }, \"datetime\" : \"2017-04-22T01:00:00-05:00\" , } } } POST /files/revert/:file-id/:version-id \u00b6 This endpoint can be used to revert to an old version of the content for a file. Request \u00b6 POST /files/revert/9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec HTTP / 1.1 PATCH /files/:file-id/:version-id \u00b6 This endpoint can be used to edit the tags of a previous version of the file. Request \u00b6 PATCH /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72 HTTP / 1.1 Accept : application/vnd.api+json Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72\" , \"attributes\" : { \"tags\" : [ \"poem\" ] } } } DELETE /files/:file-id/:version-id \u00b6 This endpoint can be used to delete an old version of the content for a file. Request \u00b6 DELETE /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 No Content DELETE /files/versions \u00b6 Deletes all the old versions of all files to make space for new files. Request \u00b6 DELETE /files/versions HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 No Content Trash \u00b6 When a file is deleted, it is first moved to the trash. In the trash, it can be restored. Or, after some time, it will be removed from the trash and permanently destroyed. The file trashed attribute will be set to true. GET /files/trash \u00b6 List the files inside the trash. It\u2019s paginated. Query-String \u00b6 Parameter Description page[cursor] the last id of the results page[limit] the number of entries (30 by default) Request \u00b6 GET /files/trash HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"df24aac0-7f3d-11e6-81c0-d38812bfa0a8\" , \"meta\" : { \"rev\" : \"1-3b75377c\" }, \"attributes\" : { \"type\" : \"file\" , \"dir_id\" : \"io.cozy.files.trash-dir\" , \"name\" : \"foo.txt\" , \"trashed\" : true , \"restore_path\" : \"/previous_parent\" , \"md5sum\" : \"YjAxMzQxZTc4MDNjODAwYwo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 123 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"links\" : { \"self\" : \"/files/trash/df24aac0-7f3d-11e6-81c0-d38812bfa0a8\" } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4a4fc582-7f3e-11e6-b9ca-278406b6ddd4\" , \"meta\" : { \"rev\" : \"1-4a09030e\" }, \"attributes\" : { \"type\" : \"file\" , \"dir_id\" : \"io.cozy.files.trash-dir\" , \"name\" : \"bar.txt\" , \"trashed\" : true , \"restore_path\" : \"/other_parent\" , \"md5sum\" : \"YWVhYjg3ZWI0OWQzZjRlMAo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 456 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"links\" : { \"self\" : \"/files/trash/4a4fc582-7f3e-11e6-b9ca-278406b6ddd4\" } } ] } POST /files/trash/:file-id \u00b6 Restore the file with the file-id identifiant into its restore_path . If a file already exists at the restore path with the same name, a suffix will be added to avoid any conflict. The file\u2019s trashed attributes will be set to false. DELETE /files/trash/:file-id \u00b6 Destroy the file and make it unrecoverable (it will still be available in backups). DELETE /files/trash \u00b6 Clear out the trash. Trashed attribute \u00b6 All files that are inside the trash will have a trashed: true attribute. This attribute can be used in mango queries to only get \u201cinteresting\u201d files. Real-time via websockets \u00b6 In addition to the normal events for files, the stack also injects some events when a thumbnail is generated. A permission on io.cozy.files is required to subscribe to those events on io.cozy.files.thumbnails . Example \u00b6 client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.files.thumbnails\"}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"large\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"medium\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"small\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"tiny\"}}}", "title": "/files - Virtual File System"}, {"location": "cozy-stack/files/#virtual-file-system", "text": "Cozy applications can use files for storing binary content, like photos or bills in PDF. This service offers a REST API to manipulate easily without having to know the underlying storage layer. The metadata are kept in CouchDB, but the binaries can go to the local system, or a Swift instance.", "title": "Virtual File System"}, {"location": "cozy-stack/files/#directories", "text": "A directory is a container for files and sub-directories. Its path is the path of its parent, a slash ( / ), and its name. It\u2019s case sensitive.", "title": "Directories"}, {"location": "cozy-stack/files/#root-directory", "text": "The root of the virtual file system is a special directory with id io.cozy.files.root-dir . You can use it in any request where you would use a directory, except you cannot delete it.", "title": "Root directory"}, {"location": "cozy-stack/files/#post-filesdir-id", "text": "Create a new directory. The dir-id parameter is optional. When it\u2019s not given, the directory is created at the root of the virtual file system.", "title": "POST /files/:dir-id"}, {"location": "cozy-stack/files/#query-string", "text": "Parameter Description Type directory Name the directory name Tags an array of tags CreatedAt the creation date MetadataID the identifier of a metadata object", "title": "Query-String"}, {"location": "cozy-stack/files/#http-headers", "text": "Parameter Description Date The modification date of the directory", "title": "HTTP headers"}, {"location": "cozy-stack/files/#request", "text": "POST /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?Type=directory&Name=phone&Tags=bills,konnectors HTTP / 1.1 Accept : application/vnd.api+json Date : Mon, 19 Sep 2016 12:35:08 GMT", "title": "Request"}, {"location": "cozy-stack/files/#status-codes", "text": "201 Created, when the directory has been successfully created 404 Not Found, when the parent directory does not exist 409 Conflict, when a directory with the same name already exists 422 Unprocessable Entity, when the Type , Name , or MetadataID parameter is missing or invalid", "title": "Status codes"}, {"location": "cozy-stack/files/#response", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"meta\" : { \"rev\" : \"1-ff3beeb456eb\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"phone\" , \"path\" : \"/Documents/phone\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" , \"konnectors\" ], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:48Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:48Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"not_synchronized_on\" : { \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on\" }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" } ] } }, \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } } } Note : see not synchronized directories for more informations about the not_synchronized_on field.", "title": "Response"}, {"location": "cozy-stack/files/#post-filesshared-drives", "text": "This endpoint returns the information about the Shared Drives directory. If the directory does not exist, it is created.", "title": "POST /files/shared-drives"}, {"location": "cozy-stack/files/#request_1", "text": "POST /files/shared-drives Accept: application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/files/#response_1", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"io.cozy.files.shared-drives-dir\" , \"meta\" : { \"rev\" : \"1-e4abdb5a\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Drives\" , \"path\" : \"/Drives\" , \"created_at\" : \"2024-03-25T15:22:00Z\" , \"updated_at\" : \"2024-03-25T15:22:00Z\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2024-03-25T15:22:00Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2024-03-25T15:22:00Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/io.cozy.files.root-dir\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"io.cozy.files.root-dir\" } } }, \"links\" : { \"self\" : \"/files/io.cozy.files.shared-drives-dir\" } } }", "title": "Response"}, {"location": "cozy-stack/files/#get-filesfile-id", "text": "Get a directory or a file informations. In the case of a directory, it contains the list of files and sub-directories inside it. For a note, its images are included. Contents is paginated following jsonapi conventions . The default limit is 30 entries.", "title": "GET /files/:file-id"}, {"location": "cozy-stack/files/#request_2", "text": "GET /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/files/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"links\" : { \"next\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?page[cursor]=9152d568-7e7c-11e6-a377-37cbfb190b4b\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" , \"meta\" : { \"rev\" : \"1-e36ab092\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Documents\" , \"path\" : \"/Documents\" , \"created_at\" : \"2016-09-19T12:35:00Z\" , \"updated_at\" : \"2016-09-19T12:35:00Z\" , \"tags\" : [], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:47Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:47Z\" } }, \"relationships\" : { \"contents\" : { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" } ] } }, \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"included\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"meta\" : { \"rev\" : \"1-ff3beeb456eb\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"phone\" , \"path\" : \"/Documents/phone\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" , \"konnectors\" ], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:47Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:47Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.txt\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } ] }", "title": "Response"}, {"location": "cozy-stack/files/#get-filesfile-idsize", "text": "This endpoint returns the size taken by the files in a directory, including those in subdirectories.", "title": "GET /files/:file-id/size"}, {"location": "cozy-stack/files/#request_3", "text": "GET /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/size HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/files/#response_3", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.sizes\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" , \"attributes\" : { \"size\" : \"1234567890\" }, \"meta\" : {} } }", "title": "Response"}, {"location": "cozy-stack/files/#get-files_changes", "text": "This endpoint is similar to the changes feed of CouchDB for io.cozy.files. There are a few specificities: it is wrapped in the VFS lock to avoid seeing inconsistent results it automatically skips design docs if the requests is coming from an OAuth client, it excludes the files and directories that are in a not synchronized folder it only supports the options since , limit , and include_docs of CouchDB it has an option fields to only include those fields in the results it has an option include_file_path to add the path for files it has two options skip_deleted and skip_trashed to not send to the client the deleted/trashed files and directories.", "title": "GET /files/_changes"}, {"location": "cozy-stack/files/#request_4", "text": "GET /files/_changes?include_docs=true&fields=type,name,dir_id&skip_deleted=true&limit=3 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"last_seq\" : \"13-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTeXKAQe5Jpmrl5ojG68iwA2MMV1A\" , \"pending\" : 24 , \"results\" : [ { \"id\" : \"io.cozy.files.root-dir\" , \"seq\" : \"11-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTuXKAQe5Jpmrl5ojG68iwA2IcV0g\" , \"doc\" : { \"type\" : \"directory\" }, \"changes\" : [ { \"rev\" : \"1-077f26acac6f0a5e1022f109e8d1dfc4\" } ] }, { \"id\" : \"io.cozy.files.trash-dir\" , \"seq\" : \"12-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kSeXKAQe5Jpmrl5ojG68iwA2KUV0w\" , \"doc\" : { \"dir_id\" : \"io.cozy.files.root-dir\" , \"name\" : \".cozy_trash\" , \"type\" : \"directory\" }, \"changes\" : [ { \"rev\" : \"1-de9c11dbc386b5f91adbe2aee4a3e754\" } ] }, { \"id\" : \"d30b0dd6e0e8fefdac2a94cb2c00249f\" , \"seq\" : \"13-g1AAAABHeJzLYWBgYMxgTmHgzcvPy09JdcjLz8gvLskBCjMlMuSxMPwHgqwM5kTeXKAQe5Jpmrl5ojG68iwA2MMV1A\" , \"doc\" : { \"dir_id\" : \"io.cozy.files.root-dir\" , \"name\" : \"Administratif\" , \"type\" : \"directory\" }, \"changes\" : [ { \"rev\" : \"1-24f2828e8dbe64135913072a4c92d846\" } ] } ] }", "title": "Response"}, {"location": "cozy-stack/files/#post-files_find", "text": "Find allows to find documents using a mango selector. You can read more about mango selectors here . Note that it returns a bookmark in the links , useful to paginate (following the JSON-API pagination ). On the last page, there won\u2019t be a links.next . It is possible to pass a execution_stats parameter to get some information about the query execution. See here for more details.", "title": "POST /files/_find"}, {"location": "cozy-stack/files/#request_5", "text": "POST /files/_find HTTP / 1.1 { \"selector\" : { \"class\" : \"image\" , \"trashed\" : false }, \"limit\" : 2 , \"bookmark\" : \"g1AAAABjeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorpFokG5qaGVqYmCWbGxuYGFkYWhgkmqaZJZsZGpibWhiA9HHA9OWATAJpY83MTUxPTWFgTUvMKU7NygIA7IYZzA\" , \"use_index\" : \"_design/a5f4711fc9448864a13c81dc71e660b524d7410c\" , \"execution_stats\" : true }", "title": "Request"}, {"location": "cozy-stack/files/#response_5", "text": "HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"e8c1561846c730428180a5f6c6107914\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"nicepic1.jpg\" , \"dir_id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"created_at\" : \"2020-02-13T16:35:47.568155477+01:00\" , \"updated_at\" : \"2020-02-13T16:35:47.568155477+01:00\" , \"size\" : \"345385\" , \"md5sum\" : \"12cGYwT+RiNjFxf4f7AmzQ==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"tags\" : [], \"path\" : \"/Pictures/nicepic1.jpg\" , \"metadata\" : { \"datetime\" : \"2020-02-13T16:35:47.568155477+01:00\" , \"extractor_version\" : 2 , \"height\" : 1080 , \"width\" : 1920 } }, \"meta\" : { \"rev\" : \"2-235e715b1d82a93285be1b0bd691b779\" }, \"links\" : { \"self\" : \"/files/e8c1561846c730428180a5f6c6107914\" , \"tiny\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/tiny\" , \"small\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/small\" , \"medium\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/medium\" , \"large\" : \"/files/e8c1561846c730428180a5f6c6107914/thumbnails/377327a8e20d6a50/large\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f49b4087cbf946dfc759214394009a6c\" }, \"data\" : { \"id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"type\" : \"io.cozy.files\" } } } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"e8c1561846c730428180a5f6c6109007\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"nicepic2.jpg\" , \"dir_id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"created_at\" : \"2020-02-13T16:35:47.845049743+01:00\" , \"updated_at\" : \"2020-02-13T16:35:47.845049743+01:00\" , \"size\" : \"323009\" , \"md5sum\" : \"Fla3ucNXuW2Xw/TK8pfsPA==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"tags\" : [], \"path\" : \"/Pictures/nicepic2.jpg\" , \"metadata\" : { \"datetime\" : \"2020-02-13T16:35:47.845049743+01:00\" , \"extractor_version\" : 2 , \"height\" : 1080 , \"width\" : 1920 } }, \"meta\" : { \"rev\" : \"2-4883d6b8ccad32f8fb056af9b7f8b37f\" }, \"links\" : { \"self\" : \"/files/e8c1561846c730428180a5f6c6109007\" , \"tiny\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/tiny\" , \"small\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/small\" , \"medium\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/medium\" , \"large\" : \"/files/e8c1561846c730428180a5f6c6109007/thumbnails/58a4aea31b00c99d/large\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f49b4087cbf946dfc759214394009a6c\" }, \"data\" : { \"id\" : \"f49b4087cbf946dfc759214394009a6c\" , \"type\" : \"io.cozy.files\" } } } } ], \"links\" : { \"next\" : \"/files/_find?page[cursor]=g1AAAABjeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorpFokG5qaGVqYmCWbGxuYGFkYWhgkmqaZJZsZGlgaGJiD9HHA9OWATAJpY83MTUxPTWFgTUvMKU7NygIA694ZyA\" }, \"meta\" : { \"count\" : 2 , \"execution_stats\" : { \"total_docs_examined\" : 11 , \"results_returned\" : 2 , \"execution_time_ms\" : 8.833 } } }", "title": "Response"}, {"location": "cozy-stack/files/#delete-filesdir-id", "text": "Put a directory and its subtree in the trash. It requires the permissions on io.cozy.files for PATCH .", "title": "DELETE /files/:dir-id"}, {"location": "cozy-stack/files/#http-headers_1", "text": "It\u2019s possible to send the If-Match header, with the previous revision of the file/directory (optional).", "title": "HTTP headers"}, {"location": "cozy-stack/files/#files", "text": "A file is a binary content with some metadata.", "title": "Files"}, {"location": "cozy-stack/files/#post-filesdir-id_1", "text": "Upload a file in the directory identified by :dir-id . The created_at field will be the first valid value in this list: the datetime extracted from the EXIF for a photo the CreatedAt parameter from the query-string the Date HTTP header the current time from the server. The updated_at field will be the first value in this list: the datetime extracted from the EXIF for a photo if it is greater than the other values the UpdatedAt parameter from the query-string the Date HTTP header the current time from the server. /!\\ If the updated_at field is older than the created_at one, then the updated_at will be set with the value of the created_at .", "title": "POST /files/:dir-id"}, {"location": "cozy-stack/files/#query-string_1", "text": "Parameter Description Type file Name the file name Size the file size (when Content-Length can\u2019t be used) Tags an array of tags Executable true if the file is executable (UNIX permission) Encrypted true if the file is client-side encrypted Metadata a JSON with metadata on this file ( not recommended ) MetadataID the identifier of a metadata object CreatedAt the creation date of the file UpdatedAt the modification date of the file SourceAccount the id of the source account used by a konnector SourceAccountIdentifier the unique identifier of the account targeted by the connector", "title": "Query-String"}, {"location": "cozy-stack/files/#http-headers_2", "text": "Parameter Description Content-Length The file size Content-MD5 A Base64-encoded binary MD5 sum of the file Content-Type The mime-type of the file Date The modification date of the file", "title": "HTTP headers"}, {"location": "cozy-stack/files/#request_6", "text": "POST /files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81?Type=file&Name=hello.txt&CreatedAt=2016-09-18T01:23:45Z HTTP / 1.1 Accept : application/vnd.api+json Content-Length : 12 Content-MD5 : hvsmnRkNLIX24EaM7KQqIA== Content-Type : text/plain Date : Mon, 19 Sep 2016 12:38:04 GMT Host : cozy.example.com Hello world!", "title": "Request"}, {"location": "cozy-stack/files/#status-codes_1", "text": "201 Created, when the file has been successfully created 404 Not Found, when the parent directory does not exist 409 Conflict, when a file with the same name already exists 412 Precondition Failed, when the md5sum is Content-MD5 is not equal to the md5sum computed by the server 413 Payload Too Large, when there is not enough available space on the cozy to upload the file or the file is larger than the server\u2019s filesystem maximum file size 422 Unprocessable Entity, when the sent data is invalid (for example, the parent doesn\u2019t exist, Type , Name , or MetadataID parameter is missing or invalid, etc.)", "title": "Status codes"}, {"location": "cozy-stack/files/#response_6", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"sunset.jpg\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-18T20:38:04Z\" , \"updated_at\" : \"2016-09-21T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2016-09-18T20:38:04Z\" , \"height\" : 1080 , \"width\" : 1920 }, \"size\" : 12 , \"executable\" : false , \"class\" : \"image\" , \"mime\" : \"image/jpg\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-21T14:46:37Z\" , \"uploadedAt\" : \"2016-09-20T18:37:52Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references\" }, \"data\" : [ { \"type\" : \"io.cozy.albums\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] }, \"old_versions\" : { \"data\" : [ { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec\" }, { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72\" } ] } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"tiny\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/tiny\" , \"small\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/small\" , \"medium\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/medium\" , \"large\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/0f9cda56674282ac/large\" } }, \"included\" : [ { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec\" , \"meta\" : { \"rev\" : \"1-26a331\" }, \"attributes\" : { \"file_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"updated_at\" : \"2016-09-21T10:11:12Z\" , \"md5sum\" : \"a2lth5syMW+4r7jwNhdk3A==\" , \"size\" : 123456 , \"tags\" : [], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:37:52Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:37:52Z\" , \"uploadedAt\" : \"2016-09-20T18:37:52Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } } }, { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72\" , \"meta\" : { \"rev\" : \"1-57b3e2\" }, \"attributes\" : { \"file_id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"updated_at\" : \"2016-09-18T20:38:04Z\" , \"md5sum\" : \"FBA89XXOZKFhdv37iILb2Q==\" , \"size\" : 159753 , \"tags\" : [], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } } } ] } Note : see references of documents in VFS for more informations about the references field.", "title": "Response"}, {"location": "cozy-stack/files/#post-filesuploadmetadata", "text": "Send a metadata object that can be associated to a file (or directory) uploaded after that, via the MetadataID query parameter. The MetadataID parameter is only valid for 10 minutes, and will expire after that. Note: a special permission on io.cozy.certified.carbon_copy is required to send a request with carbonCopy as key in the attributes map. Same for electronicSafe . See the metadata doctype to know more about metadata attributes that can be set, notably for images and document qualification.", "title": "POST /files/upload/metadata"}, {"location": "cozy-stack/files/#request_7", "text": "POST /files/upload/metadata HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.metadata\" , \"attributes\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" }, \"datetime\" : \"2017-04-22T01:00:00-05:00\" } } }", "title": "Request"}, {"location": "cozy-stack/files/#response_7", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.metadata\" , \"id\" : \"42E6BD48\" , \"attributes\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" }, \"datetime\" : \"2017-04-22T01:00:00-05:00\" } } }", "title": "Response"}, {"location": "cozy-stack/files/#get-filesdownloadfile-id", "text": "Download the file content. By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1 For a PDF file, it\u2019s possible to get only a single page by using the Page parameter in the query-string (1 is the first page).", "title": "GET /files/download/:file-id"}, {"location": "cozy-stack/files/#request_8", "text": "GET /files/download/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#response_8", "text": "HTTP / 1.1 200 OK Content-Length : 12 Content-Disposition : inline; filename=\"hello.txt\" Content-Type : text/plain Hello world!", "title": "Response"}, {"location": "cozy-stack/files/#get-filesdownload", "text": "Download the file content from its path. By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1 For a PDF file, it\u2019s possible to get only a single page by using the Page parameter in the query-string (1 is the first page).", "title": "GET /files/download"}, {"location": "cozy-stack/files/#request_9", "text": "GET /files/download?Path=/Documents/hello.txt&Dl=1 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#get-filesfile-idiconsecret", "text": "Get an image that shows the first page of a PDF in a small resolution (96x96). Note: this route is deprecated, you should use thumbnails instead.", "title": "GET /files/:file-id/icon/:secret"}, {"location": "cozy-stack/files/#get-filesfile-idpreviewsecret", "text": "Get an image that shows the first page of a PDF (at most 1080x1920). Note: this route is deprecated, you should use thumbnails instead.", "title": "GET /files/:file-id/preview/:secret"}, {"location": "cozy-stack/files/#get-filesfile-idthumbnailssecretformat", "text": "Get a thumbnail of a file (for an image & pdf only). :format can be tiny (96x96) small (640x480), medium (1280x720), or large (1920x1080). This API does not require authentication because the secret acts as a token. This secret is valid for 10 minutes, after which the link will return an error. To retrieve a new functional link, you must query the files API again to obtain a new secret.", "title": "GET /files/:file-id/thumbnails/:secret/:format"}, {"location": "cozy-stack/files/#put-filesfile-id", "text": "Overwrite a file The updated_at field will be the first value in this list: the datetime extracted from the EXIF for a photo if it is greater than the other values the UpdatedAt parameter from the query-string the Date HTTP header the current time from the server. /!\\ If the updated_at field is older than the created_at one, then the updated_at will be set with the value of the created_at .", "title": "PUT /files/:file-id"}, {"location": "cozy-stack/files/#query-string_2", "text": "Parameter Description Size the file size (when Content-Length can\u2019t be used) Tags an array of tags Executable true if the file is executable (UNIX permission) Encrypted true if the file is client-side encrypted MetadataID the identifier of a metadata object UpdatedAt the modification date of the file SourceAccount the id of the source account used by a konnector SourceAccountIdentifier the unique identifier of the account targeted by the connector", "title": "Query-String"}, {"location": "cozy-stack/files/#http-headers_3", "text": "The HTTP headers are the same than for uploading a file. There is one additional header, If-Match , with the previous revision of the file (optional).", "title": "HTTP headers"}, {"location": "cozy-stack/files/#request_10", "text": "PUT /files/9152d568-7e7c-11e6-a377-37cbfb190b4b HTTP / 1.1 Accept : application/vnd.api+json Content-Length : 12 Content-MD5 : hvsmnRkNLIX24EaM7KQqIA== Content-Type : text/plain If-Match : 1-0e6d5b72 HELLO WORLD!", "title": "Request"}, {"location": "cozy-stack/files/#status-codes_2", "text": "200 OK, when the file has been successfully overwritten 404 Not Found, when the file wasn\u2019t existing 412 Precondition Failed, when the If-Match header is set and doesn\u2019t match the last revision of the file 413 Payload Too Large, when there is not enough available space on the cozy to upload the file or the file is larger than the server\u2019s filesystem maximum file size 422 Unprocessable Entity, when the sent data is invalid (for example, the MetadataID parameter has expired)", "title": "Status codes"}, {"location": "cozy-stack/files/#response_9", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"2-d903b54c\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.pdf\" , \"trashed\" : false , \"md5sum\" : \"YjU5YmMzN2Q2NDQxZDk2Nwo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"pdf\" , \"mime\" : \"application/pdf\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-21T04:27:50Z\" , \"uploadedAt\" : \"2016-09-21T04:27:50Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"icon\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/icon/543d7eb8\" , \"preview\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/preview/77e117e0\" , \"tiny\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/tiny\" , \"small\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/small\" , \"medium\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/medium\" , \"large\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b/thumbnails/93fd0a5d96b22e9d/large\" } } }", "title": "Response"}, {"location": "cozy-stack/files/#post-filesfile-idcopy", "text": "Create a copy of a file in the same directory with a copy suffix in its name", "title": "POST /files/:file-id/copy"}, {"location": "cozy-stack/files/#query-string_3", "text": "Parameter Description Name the file copy name (optional) DirID the destination directory id (optional)", "title": "Query-String"}, {"location": "cozy-stack/files/#request_11", "text": "POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/copy HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/files/#status-codes_3", "text": "201 Created, when the file has been successfully copied 404 Not Found, when the file does not exist 409 Conflict, when a file with the same name as the copy would have already exists 413 Payload Too Large, when there is not enough available space on the cozy to copy the file", "title": "Status codes"}, {"location": "cozy-stack/files/#response_10", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"7382f28a-21d4-12d9-4438-3fd53e98a219\" , \"meta\" : { \"rev\" : \"1-83a82e9\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello (copy).pdf\" , \"trashed\" : false , \"md5sum\" : \"YjU5YmMzN2Q2NDQxZDk2Nwo=\" , \"created_at\" : \"2022-10-18T18:33:24Z\" , \"updated_at\" : \"2022-10-18T18:33:24Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"pdf\" , \"mime\" : \"application/pdf\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2022-10-18T18:33:24Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2022-10-18T18:33:24Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219\" , \"icon\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/icon/543d7eb8\" , \"preview\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/preview/77e117e0\" , \"tiny\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/tiny\" , \"small\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/small\" , \"medium\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/medium\" , \"large\" : \"/files/7382f28a-21d4-12d9-4438-3fd53e98a219/thumbnails/93fd0a5d96b22e9d/large\" } } }", "title": "Response"}, {"location": "cozy-stack/files/#delete-filesfile-id", "text": "Put a file in the trash.", "title": "DELETE /files/:file-id"}, {"location": "cozy-stack/files/#common", "text": "", "title": "Common"}, {"location": "cozy-stack/files/#get-filesmetadata", "text": "Same as /files/:file-id but to retrieve informations from a path.", "title": "GET /files/metadata"}, {"location": "cozy-stack/files/#request_12", "text": "GET /files/metadata?Path=/Documents/hello.txt HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#response_11", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.txt\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } }", "title": "Response"}, {"location": "cozy-stack/files/#patch-filesfile-id-and-patch-filesmetadata", "text": "Both endpoints can be used to update the metadata of a file or directory, or to rename/move it. The difference is the first one uses an id to identify the file/directory to update, and the second one uses the path. Some specific attributes of the patch can be used: dir_id attribute can be updated to move a file or directory move_to_trash boolean to specify that the file needs to be moved to the trash permanent_delete boolean to specify that the files needs to be deleted (after being trashed) cozyMetadata.favorite boolean attribute to put/remove a file from the favorites", "title": "PATCH /files/:file-id and PATCH /files/metadata"}, {"location": "cozy-stack/files/#http-headers_4", "text": "It\u2019s possible to send the If-Match header, with the previous revision of the file/directory (optional).", "title": "HTTP headers"}, {"location": "cozy-stack/files/#request_13", "text": "PATCH /files/9152d568-7e7c-11e6-a377-37cbfb190b4b HTTP / 1.1 Accept : application/vnd.api+json Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hi.txt\" , \"dir_id\" : \"f2f36fec-8018-11e6-abd8-8b3814d9a465\" , \"tags\" : [ \"poem\" ], \"cozyMetadata\" : { \"favorite\" : true } } } }", "title": "Request"}, {"location": "cozy-stack/files/#status-codes_4", "text": "200 OK, when the file or directory metadata has been successfully updated 400 Bad Request, when a the directory is asked to move to one of its sub-directories 404 Not Found, when the file/directory wasn\u2019t existing 412 Precondition Failed, when the If-Match header is set and doesn\u2019t match the last revision of the file/directory 422 Unprocessable Entity, when the sent data is invalid (for example, the parent doesn\u2019t exist)", "title": "Status codes"}, {"location": "cozy-stack/files/#response_12", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json Location : https://cozy.example.com/files/9152d568-7e7c-11e6-a377-37cbfb190b4b { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hi.txt\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [ \"poem\" ], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-22T13:32:51Z\" , \"uploadedAt\" : \"2016-09-21T04:27:50Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f2f36fec-8018-11e6-abd8-8b3814d9a465\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f2f36fec-8018-11e6-abd8-8b3814d9a465\" } } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } }", "title": "Response"}, {"location": "cozy-stack/files/#patch-files", "text": "Endpoint to update the metadata of files and directories in batch. It can be used, for instance, to move many files in a single request.", "title": "PATCH /files/"}, {"location": "cozy-stack/files/#request_14", "text": "PATCH /files/ HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"dir_id\" : \"f2f36fec-8018-11e6-abd8-8b3814d9a465\" } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4c\" , \"meta\" : { \"rev\" : \"2-123123\" }, \"attributes\" : { \"move_to_trash\" : true } } ] }", "title": "Request"}, {"location": "cozy-stack/files/#status-codes_5", "text": "The same status codes can be encountered as the PATCH /files/:file-id route.", "title": "Status codes"}, {"location": "cozy-stack/files/#post-filesarchive", "text": "Create an archive. The body of the request lists the files and directories that will be included in the archive. For directories, it includes all the files and sub-directories in the archive. It\u2019s possible to give a file by its id (in the ids array) or by its path (in the files array). For PDF files, it\u2019s possible to put in the archive a single page, with the pages argument: it\u2019s an array of objects, with id the file identifier of the PDF file, and page the page number (1 is the first page). The generated archive is temporary and is not persisted.", "title": "POST /files/archive"}, {"location": "cozy-stack/files/#request_15", "text": "POST /files/archive HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.archives\" , \"attributes\" : { \"name\" : \"project-X\" , \"ids\" : [ \"a51aeeea-4f79-11e7-9dc4-83f67e9494ab\" ], \"files\" : [ \"/Documents/bills\" , \"/Documents/images/sunset.jpg\" , \"/Documents/images/eiffel-tower.jpg\" ], \"pages\" : [ { \"id\" : \"3780caf0-104f-013d-3619-18c04daba326\" , \"page\" : 1 } ] } } }", "title": "Request"}, {"location": "cozy-stack/files/#response_13", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"links\" : { \"related\" : \"/files/archive/4521DC87/project-X.zip\" }, \"data\" : { \"type\" : \"io.cozy.files.archives\" , \"id\" : \"4521DC87\" , \"attributes\" : { \"href\" : \"/files/archive/4521DC87/project-X.zip\" } } }", "title": "Response"}, {"location": "cozy-stack/files/#get-filesarchivekeyname", "text": "Download a previously created archive. The name parameter is not used in the stack but aims to allow setting a name even for browser / downloader that do not support Content-Disposition filename. This route does not require Basic Authentification GET /files/archive/4521DC87/project-X.zip HTTP / 1.1 Accept : application/zip Content-Length : 12345 Content-Disposition : attachment; filename=\"project-X.zip\" Content-Type : application/zip", "title": "GET /files/archive/:key/:name"}, {"location": "cozy-stack/files/#post-filesdownloadspathfile_path", "text": "Create a file download. The Path query parameter specifies the file to download. The response json API links contains a related link for downloading the file, see below.", "title": "POST /files/downloads?Path=file_path"}, {"location": "cozy-stack/files/#post-filesdownloadsidfile_id", "text": "Also create a file download. But it takes the id of the file and not its path.", "title": "POST /files/downloads?Id=file_id"}, {"location": "cozy-stack/files/#post-filesdownloadsversionidfile_idversion_id", "text": "This is a third way to create a file download. But, this time, it is for downloading an old version of a file. These 3 routes also accept a Filename=... parameter in the query-string to change the filename that will be used for the downloaded file.", "title": "POST /files/downloads?VersionId=file_id/version_id"}, {"location": "cozy-stack/files/#get-filesdownloadssecretname", "text": "Allows to download a file with a secret created from the route above. The name parameter is not used in the stack but aims to allow setting a name even for browser / downloader that do not support Content-Disposition filename. By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1 This route does not require Basic Authentification", "title": "GET /files/downloads/:secret/:name"}, {"location": "cozy-stack/files/#versions", "text": "The identifier of the io.cozy.files.versions is composed of the file-id and another string called the version-id , separated by a / . So, when a route makes reference to /something/:file-id/:version-id , you can use the identifier of the version document (without having to prepend the file identifier).", "title": "Versions"}, {"location": "cozy-stack/files/#get-filesdownloadfile-idversion-id", "text": "Download an old version of the file content By default the content-disposition will be inline , but it will be attachment if the query string contains the parameter Dl=1", "title": "GET /files/download/:file-id/:version-id"}, {"location": "cozy-stack/files/#request_16", "text": "GET /files/download/9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#post-filesfile-idversions", "text": "Create a new version of a file, with the same content but new metadata. It requires a permission for PUT on the file, as it is equivalent to upload the same content of the file.", "title": "POST /files/:file-id/versions"}, {"location": "cozy-stack/files/#query-string_4", "text": "Parameter Description Tags an array of tags", "title": "Query-String"}, {"location": "cozy-stack/files/#request_17", "text": "POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/metadata HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.metadata\" , \"attributes\" : { \"qualification\" : { \"label\" : \"telecom_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"telecom\" }, \"datetime\" : \"2017-04-22T01:00:00-05:00\" , } } }", "title": "Request"}, {"location": "cozy-stack/files/#post-filesrevertfile-idversion-id", "text": "This endpoint can be used to revert to an old version of the content for a file.", "title": "POST /files/revert/:file-id/:version-id"}, {"location": "cozy-stack/files/#request_18", "text": "POST /files/revert/9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#patch-filesfile-idversion-id", "text": "This endpoint can be used to edit the tags of a previous version of the file.", "title": "PATCH /files/:file-id/:version-id"}, {"location": "cozy-stack/files/#request_19", "text": "PATCH /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72 HTTP / 1.1 Accept : application/vnd.api+json Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.versions\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b/1-0e6d5b72\" , \"attributes\" : { \"tags\" : [ \"poem\" ] } } }", "title": "Request"}, {"location": "cozy-stack/files/#delete-filesfile-idversion-id", "text": "This endpoint can be used to delete an old version of the content for a file.", "title": "DELETE /files/:file-id/:version-id"}, {"location": "cozy-stack/files/#request_20", "text": "DELETE /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/2-fa3a3bec HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#response_14", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/files/#delete-filesversions", "text": "Deletes all the old versions of all files to make space for new files.", "title": "DELETE /files/versions"}, {"location": "cozy-stack/files/#request_21", "text": "DELETE /files/versions HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/files/#response_15", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/files/#trash", "text": "When a file is deleted, it is first moved to the trash. In the trash, it can be restored. Or, after some time, it will be removed from the trash and permanently destroyed. The file trashed attribute will be set to true.", "title": "Trash"}, {"location": "cozy-stack/files/#get-filestrash", "text": "List the files inside the trash. It\u2019s paginated.", "title": "GET /files/trash"}, {"location": "cozy-stack/files/#query-string_5", "text": "Parameter Description page[cursor] the last id of the results page[limit] the number of entries (30 by default)", "title": "Query-String"}, {"location": "cozy-stack/files/#request_22", "text": "GET /files/trash HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/files/#response_16", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"df24aac0-7f3d-11e6-81c0-d38812bfa0a8\" , \"meta\" : { \"rev\" : \"1-3b75377c\" }, \"attributes\" : { \"type\" : \"file\" , \"dir_id\" : \"io.cozy.files.trash-dir\" , \"name\" : \"foo.txt\" , \"trashed\" : true , \"restore_path\" : \"/previous_parent\" , \"md5sum\" : \"YjAxMzQxZTc4MDNjODAwYwo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 123 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"links\" : { \"self\" : \"/files/trash/df24aac0-7f3d-11e6-81c0-d38812bfa0a8\" } }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4a4fc582-7f3e-11e6-b9ca-278406b6ddd4\" , \"meta\" : { \"rev\" : \"1-4a09030e\" }, \"attributes\" : { \"type\" : \"file\" , \"dir_id\" : \"io.cozy.files.trash-dir\" , \"name\" : \"bar.txt\" , \"trashed\" : true , \"restore_path\" : \"/other_parent\" , \"md5sum\" : \"YWVhYjg3ZWI0OWQzZjRlMAo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 456 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:49Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedAt\" : \"2016-09-20T18:32:49Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"drive\" } } }, \"links\" : { \"self\" : \"/files/trash/4a4fc582-7f3e-11e6-b9ca-278406b6ddd4\" } } ] }", "title": "Response"}, {"location": "cozy-stack/files/#post-filestrashfile-id", "text": "Restore the file with the file-id identifiant into its restore_path . If a file already exists at the restore path with the same name, a suffix will be added to avoid any conflict. The file\u2019s trashed attributes will be set to false.", "title": "POST /files/trash/:file-id"}, {"location": "cozy-stack/files/#delete-filestrashfile-id", "text": "Destroy the file and make it unrecoverable (it will still be available in backups).", "title": "DELETE /files/trash/:file-id"}, {"location": "cozy-stack/files/#delete-filestrash", "text": "Clear out the trash.", "title": "DELETE /files/trash"}, {"location": "cozy-stack/files/#trashed-attribute", "text": "All files that are inside the trash will have a trashed: true attribute. This attribute can be used in mango queries to only get \u201cinteresting\u201d files.", "title": "Trashed attribute"}, {"location": "cozy-stack/files/#real-time-via-websockets", "text": "In addition to the normal events for files, the stack also injects some events when a thumbnail is generated. A permission on io.cozy.files is required to subscribe to those events on io.cozy.files.thumbnails .", "title": "Real-time via websockets"}, {"location": "cozy-stack/files/#example", "text": "client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.files.thumbnails\"}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"large\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"medium\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"small\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"9152d568-7e7c-11e6-a377-37cbfb190b4b\", \"type\": \"io.cozy.files.thumbnails\", \"doc\": {\"format\": \"tiny\"}}}", "title": "Example"}, {"location": "cozy-stack/flagship/", "text": "Flagship App \u00b6 Introduction \u00b6 The flagship application is a mobile application that can be used to run all the Cozy webapps inside it. It also has a bunch of exclusive features like the client-side connectors. But, to be able to work, it needs a very powerful access to the Cozy instance. Technically, it means that the flagship app is an OAuth client with a scope that covers everything. And we want to ensure that only the flagship can have this power. So, we require the application to be certified. It can be certified via the Google and Apple stores, and when it\u2019s not available, the user has the possibility to manually certify the flagship app (lineage OS users for example). Let\u2019s see the workflow when a user opens the flagship app for the first time. The app will load, and it will open a page of the cloudery for the onboarding. The user can type their email address, the cloudery sends an email, the user opens a link in this email, and then, we have two cases: the user already have a Cozy instance, or they want to create a new one. In both cases, the flagship will register its-self as an OAuth client on the Cozy and will type their passphrase before going to the home of the Cozy inside the flagship app. It is just that for a new Cozy, there are a few additional steps like accepting the terms of services. Note: the flagship app can be used with self-hosted stack. The user will have to type their Cozy address instead of using their email address, but everything else should work, including the certification via the Google and Apple stores (there are some config parameters, but they have a default value that make this possible). Create the OAuth client & certification \u00b6 When the flagship app knows the Cozy instance of the user, it will register itself as an OAuth client, and will try to attest that it is really the flagship app via the Google and Apple APIs. It is done by calling these 3 routes from the stack: POST /auth/register POST /auth/clients/:client-id/challenge POST /auth/clients/:client-id/attestation Between 2 and 3, the app will ask the mobile OS to certify that this is really the flagship app. It is done via the Play Integrity API (or SafetyNet attestation API ) on Android, and the AppAttest API on iOS. New Cozy instance \u00b6 On a new Cozy instance, the user will choose a passphrase that will be registered on the Cozy by sending its PBKDF2 hash to POST /settings/passphrase/flagship . Existing Cozy instance \u00b6 On an existing Cozy instance, the app will fetch some parameters with GET /public/prelogin , then the user can type their passphrase, and the PBKDF2 hash will be sent to POST /auth/login/flagship to give the app access to the whole Cozy. Magic link variant \u00b6 When magic link is enabled on a Cozy, the flagship app can use POST /auth/magic_link/flagship with a code sent by email to the user to get access to the Cozy. OIDC variant \u00b6 When a user uses an OIDC provider, or FranceConnect, the flagship app will get a delegated code from the cloudery and will use it via the POST /oidc/access_token endpoint to get access to the Cozy. Manual certification \u00b6 When the certification from the Google and Apple stores has failed, the app will have to do a few more steps to have access to the Cozy: Opening an in-app browser on the authorize page of the stack GET /auth/authorize?scope=* (note: PKCE is mandatory for the flagship app) The stack sends a mail with a 6 digits code in that case. The email explains that this code can be used to certify the flagship app. The user can type this code on the authorize page and submit it. It makes a POST /auth/clients/:client-id/flagship . If successful, it redirects back to the same page ( GET /auth/authorize?scope=* ), but this time, the user has button to accept using the flagship app. The user accepts, it sends a request to POST /auth/authorize , and the flagship app can finish the OAuth danse and have a full access on the Cozy. Special routes \u00b6 Some routes of the stack are dedicated to the flagship app, like: creating a session code with POST /auth/session_code getting a konnector token with POST /auth/tokens/konnectors/:slug getting the parameters to open a webapp with GET /apps/:slug/open And some routes accept a session_code to open a session in a webview or inAppBrowser, like: serving the index.html of a webapp starting the OAuth danse of a konnector ( /accounts/:slug/start ) starting the reconnect BI flow ( /accounts/:slug/reconnect ). Notifications \u00b6 When a notification is sent via the push channel, the stack will first try to send it to the dedicated mobile app. If there are no dedicated apps with a push token, the stack will then try to send the notification to the flagship apps. If it fails again, the stack then fallbacks on email. If the notification is sent to the flagship app, the title is modified to preprend the application name. By default, the notification slug is used but, if present, the name is taken from the appName field of the additional parameters ( data ). It allows the user to have more context when reading the notification on their mobile. The data.appName field can also be used to completely remove the application name from the notification title if set to an empty string.", "title": "Flagship app"}, {"location": "cozy-stack/flagship/#flagship-app", "text": "", "title": "Flagship App"}, {"location": "cozy-stack/flagship/#introduction", "text": "The flagship application is a mobile application that can be used to run all the Cozy webapps inside it. It also has a bunch of exclusive features like the client-side connectors. But, to be able to work, it needs a very powerful access to the Cozy instance. Technically, it means that the flagship app is an OAuth client with a scope that covers everything. And we want to ensure that only the flagship can have this power. So, we require the application to be certified. It can be certified via the Google and Apple stores, and when it\u2019s not available, the user has the possibility to manually certify the flagship app (lineage OS users for example). Let\u2019s see the workflow when a user opens the flagship app for the first time. The app will load, and it will open a page of the cloudery for the onboarding. The user can type their email address, the cloudery sends an email, the user opens a link in this email, and then, we have two cases: the user already have a Cozy instance, or they want to create a new one. In both cases, the flagship will register its-self as an OAuth client on the Cozy and will type their passphrase before going to the home of the Cozy inside the flagship app. It is just that for a new Cozy, there are a few additional steps like accepting the terms of services. Note: the flagship app can be used with self-hosted stack. The user will have to type their Cozy address instead of using their email address, but everything else should work, including the certification via the Google and Apple stores (there are some config parameters, but they have a default value that make this possible).", "title": "Introduction"}, {"location": "cozy-stack/flagship/#create-the-oauth-client-certification", "text": "When the flagship app knows the Cozy instance of the user, it will register itself as an OAuth client, and will try to attest that it is really the flagship app via the Google and Apple APIs. It is done by calling these 3 routes from the stack: POST /auth/register POST /auth/clients/:client-id/challenge POST /auth/clients/:client-id/attestation Between 2 and 3, the app will ask the mobile OS to certify that this is really the flagship app. It is done via the Play Integrity API (or SafetyNet attestation API ) on Android, and the AppAttest API on iOS.", "title": "Create the OAuth client & certification"}, {"location": "cozy-stack/flagship/#new-cozy-instance", "text": "On a new Cozy instance, the user will choose a passphrase that will be registered on the Cozy by sending its PBKDF2 hash to POST /settings/passphrase/flagship .", "title": "New Cozy instance"}, {"location": "cozy-stack/flagship/#existing-cozy-instance", "text": "On an existing Cozy instance, the app will fetch some parameters with GET /public/prelogin , then the user can type their passphrase, and the PBKDF2 hash will be sent to POST /auth/login/flagship to give the app access to the whole Cozy.", "title": "Existing Cozy instance"}, {"location": "cozy-stack/flagship/#magic-link-variant", "text": "When magic link is enabled on a Cozy, the flagship app can use POST /auth/magic_link/flagship with a code sent by email to the user to get access to the Cozy.", "title": "Magic link variant"}, {"location": "cozy-stack/flagship/#oidc-variant", "text": "When a user uses an OIDC provider, or FranceConnect, the flagship app will get a delegated code from the cloudery and will use it via the POST /oidc/access_token endpoint to get access to the Cozy.", "title": "OIDC variant"}, {"location": "cozy-stack/flagship/#manual-certification", "text": "When the certification from the Google and Apple stores has failed, the app will have to do a few more steps to have access to the Cozy: Opening an in-app browser on the authorize page of the stack GET /auth/authorize?scope=* (note: PKCE is mandatory for the flagship app) The stack sends a mail with a 6 digits code in that case. The email explains that this code can be used to certify the flagship app. The user can type this code on the authorize page and submit it. It makes a POST /auth/clients/:client-id/flagship . If successful, it redirects back to the same page ( GET /auth/authorize?scope=* ), but this time, the user has button to accept using the flagship app. The user accepts, it sends a request to POST /auth/authorize , and the flagship app can finish the OAuth danse and have a full access on the Cozy.", "title": "Manual certification"}, {"location": "cozy-stack/flagship/#special-routes", "text": "Some routes of the stack are dedicated to the flagship app, like: creating a session code with POST /auth/session_code getting a konnector token with POST /auth/tokens/konnectors/:slug getting the parameters to open a webapp with GET /apps/:slug/open And some routes accept a session_code to open a session in a webview or inAppBrowser, like: serving the index.html of a webapp starting the OAuth danse of a konnector ( /accounts/:slug/start ) starting the reconnect BI flow ( /accounts/:slug/reconnect ).", "title": "Special routes"}, {"location": "cozy-stack/flagship/#notifications", "text": "When a notification is sent via the push channel, the stack will first try to send it to the dedicated mobile app. If there are no dedicated apps with a push token, the stack will then try to send the notification to the flagship apps. If it fails again, the stack then fallbacks on email. If the notification is sent to the flagship app, the title is modified to preprend the application name. By default, the notification slug is used but, if present, the name is taken from the appName field of the additional parameters ( data ). It allows the user to have more context when reading the notification on their mobile. The data.appName field can also be used to completely remove the application name from the notification title if set to an empty string.", "title": "Notifications"}, {"location": "cozy-stack/http-api/", "text": "Table of contents Using the HTTP API of cozy-stack \u00b6 HTTP Codes \u00b6 The developers of cozy-stack are trying to respect the semantics of HTTP, and the HTTP response code is symbolic of that. The stack uses a large range of HTTP codes, but the most common ones are: 200 OK for a successful operation, with information in the HTTP body 201 Created for a document successfully created 204 No Content for a success with no relevant information to send (like a successful deletion) 400 Bad Request when the request is incorrect 401 Unauthorized when no authorization has been sent, or the token is expired 402 Payment Required when the instance has been blocked and a user action is required (payment, or validating the Terms of Services) 403 Forbidden when the authorization has been sent, is valid, but does not grant access to the resource 404 Not Found when the resource is not found 409 Conflict when there is a conflict on the managed resource 410 Gone when a Cozy instance has been moved to a new address 412 Precondition Failed when a parameter from the HTTP headers or query string is invalid 422 Unprocessable entity when an attribute in the HTTP request body is invalid 500 Internal Server Error when something went wrong on the server (bug, network issue, unavailable database) 502 Bad Gateway when an HTTP service used by the stack is not available (apps registry, OIDC provider) JSON-API \u00b6 Introduction \u00b6 Except for the routes in /data , which imitate couchdb, most of the stack exposes a JSON-API interface. See JSON-API specification for more information. Pagination \u00b6 All routes that return a list are (or will be) paginated. As recommended for couchdb, we use cursor-based pagination. The default page limit is determined on a by-route basis. The client can require a different limit using page[limit] query parameter. If the client does not specify a limit, default limit will be used instead. If there is more docs after the limit, the response will contain a next key in its links section, with a page[cursor] set to fetch docs starting after the last one from current request. Alternatively, the client can opt in for skip mode by using page[skip] . When using skip, the number given in page[skip] is number of element ignored before returning value. Similarly, the response will contain a next link with a page[skip] set for next page (skip + limit). Example \u00b6 The /relationships/references as a default limit of 100. GET /data/some-type/some-id/relationships/references HTTP / 1.1 { \"data\" : [ \"... 100 docs ...\" ], \"links\" : { \"next\" : \"/data/some-type/some-id/relationships/references?page[limit]=100&page[cursor]=7845122548848454212\" } } GET /data/some-type/some-id/relationships/references?page[limit]=10 HTTP / 1.1 { \"data\" : [ \"... 10 docs ...\" ], \"links\" : { \"next\" : \"/data/some-type/some-id/relationships/references?page[limit]=10&page[cursor]=5487ba7596\" } } GET /data/some-type/some-id/relationships/references?page[limit]=100&page[cursor]=7845122548848454212 HTTP / 1.1 { \"data\" : [ \"... 20 docs ...\" ] } GET /data/some-type/some-id/relationships/references?page[limit]=10&page[skip]=0 HTTP / 1.1 { \"data\" : [ \"... 10 docs ...\" ], \"links\" : { \"next\" : \"/data/some-type/some-id/relationships/references?page[limit]=10&page[skip]=10\" } }", "title": "Using the HTTP API"}, {"location": "cozy-stack/http-api/#using-the-http-api-of-cozy-stack", "text": "", "title": "Using the HTTP API of cozy-stack"}, {"location": "cozy-stack/http-api/#http-codes", "text": "The developers of cozy-stack are trying to respect the semantics of HTTP, and the HTTP response code is symbolic of that. The stack uses a large range of HTTP codes, but the most common ones are: 200 OK for a successful operation, with information in the HTTP body 201 Created for a document successfully created 204 No Content for a success with no relevant information to send (like a successful deletion) 400 Bad Request when the request is incorrect 401 Unauthorized when no authorization has been sent, or the token is expired 402 Payment Required when the instance has been blocked and a user action is required (payment, or validating the Terms of Services) 403 Forbidden when the authorization has been sent, is valid, but does not grant access to the resource 404 Not Found when the resource is not found 409 Conflict when there is a conflict on the managed resource 410 Gone when a Cozy instance has been moved to a new address 412 Precondition Failed when a parameter from the HTTP headers or query string is invalid 422 Unprocessable entity when an attribute in the HTTP request body is invalid 500 Internal Server Error when something went wrong on the server (bug, network issue, unavailable database) 502 Bad Gateway when an HTTP service used by the stack is not available (apps registry, OIDC provider)", "title": "HTTP Codes"}, {"location": "cozy-stack/http-api/#json-api", "text": "", "title": "JSON-API"}, {"location": "cozy-stack/http-api/#introduction", "text": "Except for the routes in /data , which imitate couchdb, most of the stack exposes a JSON-API interface. See JSON-API specification for more information.", "title": "Introduction"}, {"location": "cozy-stack/http-api/#pagination", "text": "All routes that return a list are (or will be) paginated. As recommended for couchdb, we use cursor-based pagination. The default page limit is determined on a by-route basis. The client can require a different limit using page[limit] query parameter. If the client does not specify a limit, default limit will be used instead. If there is more docs after the limit, the response will contain a next key in its links section, with a page[cursor] set to fetch docs starting after the last one from current request. Alternatively, the client can opt in for skip mode by using page[skip] . When using skip, the number given in page[skip] is number of element ignored before returning value. Similarly, the response will contain a next link with a page[skip] set for next page (skip + limit).", "title": "Pagination"}, {"location": "cozy-stack/http-api/#example", "text": "The /relationships/references as a default limit of 100. GET /data/some-type/some-id/relationships/references HTTP / 1.1 { \"data\" : [ \"... 100 docs ...\" ], \"links\" : { \"next\" : \"/data/some-type/some-id/relationships/references?page[limit]=100&page[cursor]=7845122548848454212\" } } GET /data/some-type/some-id/relationships/references?page[limit]=10 HTTP / 1.1 { \"data\" : [ \"... 10 docs ...\" ], \"links\" : { \"next\" : \"/data/some-type/some-id/relationships/references?page[limit]=10&page[cursor]=5487ba7596\" } } GET /data/some-type/some-id/relationships/references?page[limit]=100&page[cursor]=7845122548848454212 HTTP / 1.1 { \"data\" : [ \"... 20 docs ...\" ] } GET /data/some-type/some-id/relationships/references?page[limit]=10&page[skip]=0 HTTP / 1.1 { \"data\" : [ \"... 10 docs ...\" ], \"links\" : { \"next\" : \"/data/some-type/some-id/relationships/references?page[limit]=10&page[skip]=10\" } }", "title": "Example"}, {"location": "cozy-stack/important-changes/", "text": "Table of contents Important changes \u00b6 This section will list important changes to the stack or its usage, and migration procedures if any is needed. December 2023: Iterations for PBKDF2 increased \u00b6 We have increased the number of PBKDF2 iterations for new users to 650_000, and removed the exception for Edge as it now supports PBKDF2 via the subtle crypto API. December 2020: Jobs permissions \u00b6 We used to have a specific permission logic for jobs, in order to allow apps to direclty manage konnectors. More specifically, an app had the right to access a trigger state or remove it, if there was a doctype in common between the app permissions and the konnector manifest. This does not seem useful anymore as the konnectors are handled directly through harvest. October 2019: Authentication \u00b6 We are about to change our authentification logic. This change will be transparent for end-users. End-users don\u2019t need to change anything. Developpers that used to manually send POST /auth/login , POST /auth/passphrase_renew or POST /settings/passphrase requests will need to update their code. What are the changes \u00b6 Previously, we expected the user to type its passphrase on the browser. This passphrase was sent to the stack. There it was salted, hashed and compared to the salted-hashed version stored on our systems. From today, the browser will send an intermediary secret to the server instead of your passphrase. The rest of the process will stay unchanged. We\u2019ll salt and hash this intermediary secret ans compare it the the salted-hashed version stored on our system. The three API endpoint upper have been updated and now require you to pass this intermediary secret instead of the old passphrase. The settings endpoint will also expect a parameter with a number of pbkdf2 iterations. Dirty details for developers \u00b6 The intermediary secret is built from the user passphrase and the URL of its instance with the following formula: user - iterations = # from a / bitwarden / api / accounts / prelogin request user - salt = \"me@\" + host key = pbdkf2 ( passphrase , salt = user - salt , iterations = user - salt , alg = SHA - 256 ) secret = pbkdf2 ( key , salt = passphrase , iterations = 1 , alg = SHA - 256 ) \u2026where passphrase is the user passphrase in UTF-8 and host is the instance host string (without protocol, like \u201cexample.mycozy.cloud\u201d). The default iteration number in the first step ( user-iterations ) is a per-user settings set by the stack. You can find it by emitting a prelogin request . You can also see the user-salt and user-iterations in io.cozy.settings or through a GET /settings/passphrase request. For most of users, the today\u2019s default is 100_000 pbkdf2 iterations. Users initializing their account with a Edge browser will default to 10_000 iterations (Edge does not have a native pbkdf2 function and this is a balance between security and user experience). As always, if you have any doubt, you can explore our own source code. At the time of writing, there is a function nativeHash on password-helpers.js used on the login page of the stack. A schema of the new architecture is available in the Bitwarden section of the stack . Migration \u00b6 Users will migrate transparently to the new authentification logic on their first login. The stack will intercept the passphrase sent by the browser, create the intermediary secret and store it salted-hashed for all future logins. Once the migration done, the stack will not allow direct passphrase logins anymore. Why this change \u00b6 Some content will support end-to-end encryption in the future. To ease the use for most users, we\u2019ll use the same passphrase for to login in their cozy instance and to encrypt their data. As we do not want the server to be able to read this encrypted data, we do not want to know your real passphrase anymore.", "title": "Important changes"}, {"location": "cozy-stack/important-changes/#important-changes", "text": "This section will list important changes to the stack or its usage, and migration procedures if any is needed.", "title": "Important changes"}, {"location": "cozy-stack/important-changes/#december-2023-iterations-for-pbkdf2-increased", "text": "We have increased the number of PBKDF2 iterations for new users to 650_000, and removed the exception for Edge as it now supports PBKDF2 via the subtle crypto API.", "title": "December 2023: Iterations for PBKDF2 increased"}, {"location": "cozy-stack/important-changes/#december-2020-jobs-permissions", "text": "We used to have a specific permission logic for jobs, in order to allow apps to direclty manage konnectors. More specifically, an app had the right to access a trigger state or remove it, if there was a doctype in common between the app permissions and the konnector manifest. This does not seem useful anymore as the konnectors are handled directly through harvest.", "title": "December 2020: Jobs permissions"}, {"location": "cozy-stack/important-changes/#october-2019-authentication", "text": "We are about to change our authentification logic. This change will be transparent for end-users. End-users don\u2019t need to change anything. Developpers that used to manually send POST /auth/login , POST /auth/passphrase_renew or POST /settings/passphrase requests will need to update their code.", "title": "October 2019: Authentication"}, {"location": "cozy-stack/important-changes/#what-are-the-changes", "text": "Previously, we expected the user to type its passphrase on the browser. This passphrase was sent to the stack. There it was salted, hashed and compared to the salted-hashed version stored on our systems. From today, the browser will send an intermediary secret to the server instead of your passphrase. The rest of the process will stay unchanged. We\u2019ll salt and hash this intermediary secret ans compare it the the salted-hashed version stored on our system. The three API endpoint upper have been updated and now require you to pass this intermediary secret instead of the old passphrase. The settings endpoint will also expect a parameter with a number of pbkdf2 iterations.", "title": "What are the changes"}, {"location": "cozy-stack/important-changes/#dirty-details-for-developers", "text": "The intermediary secret is built from the user passphrase and the URL of its instance with the following formula: user - iterations = # from a / bitwarden / api / accounts / prelogin request user - salt = \"me@\" + host key = pbdkf2 ( passphrase , salt = user - salt , iterations = user - salt , alg = SHA - 256 ) secret = pbkdf2 ( key , salt = passphrase , iterations = 1 , alg = SHA - 256 ) \u2026where passphrase is the user passphrase in UTF-8 and host is the instance host string (without protocol, like \u201cexample.mycozy.cloud\u201d). The default iteration number in the first step ( user-iterations ) is a per-user settings set by the stack. You can find it by emitting a prelogin request . You can also see the user-salt and user-iterations in io.cozy.settings or through a GET /settings/passphrase request. For most of users, the today\u2019s default is 100_000 pbkdf2 iterations. Users initializing their account with a Edge browser will default to 10_000 iterations (Edge does not have a native pbkdf2 function and this is a balance between security and user experience). As always, if you have any doubt, you can explore our own source code. At the time of writing, there is a function nativeHash on password-helpers.js used on the login page of the stack. A schema of the new architecture is available in the Bitwarden section of the stack .", "title": "Dirty details for developers"}, {"location": "cozy-stack/important-changes/#migration", "text": "Users will migrate transparently to the new authentification logic on their first login. The stack will intercept the passphrase sent by the browser, create the intermediary secret and store it salted-hashed for all future logins. Once the migration done, the stack will not allow direct passphrase logins anymore.", "title": "Migration"}, {"location": "cozy-stack/important-changes/#why-this-change", "text": "Some content will support end-to-end encryption in the future. To ease the use for most users, we\u2019ll use the same passphrase for to login in their cozy instance and to encrypt their data. As we do not want the server to be able to read this encrypted data, we do not want to know your real passphrase anymore.", "title": "Why this change"}, {"location": "cozy-stack/instance/", "text": "Table of contents Instances \u00b6 A single cozy-stack can manage several instances. Requests to different instances are identified through the Host HTTP Header, any reverse proxy placed in front of the cozy-stack should forward this header. Creation \u00b6 An instance is created on the command line: $ cozy-stack instances add [ flags ] The flags are documented in the instances add manpage . It registers the instance in a global couchdb database global/instances and creates the proper databases ($PREFIX/$DOCTYPE) for these doctypes: io.cozy.apps io.cozy.contacts io.cozy.files io.cozy.jobs io.cozy.konnectors io.cozy.notifications io.cozy.oauth.clients io.cozy.permissions io.cozy.sessions.logins io.cozy.settings io.cozy.shared io.cozy.sharings io.cozy.triggers Then, it creates some indexes for these doctypes, and some directories: / , with the id io.cozy.files.root-dir the trash, with the id io.cozy.files.trash-dir /Administrative /Photos /Photos/Uploaded from Cozy Photos /Photos/Backed up from my mobile The names are localized: If a locale is provided through the CLI, the directories will be created with names in this locale. Then it creates the basic settings with the options from the CLI. Finally, applications from the --apps CLI option are installed. Onboarding \u00b6 At the end of the instance creation, the CLI returns a token, called registerToken . The registerToken can be used to send a link to the user, where they will be able to choose their password. After that, the instance is said to be onboarded, and the user can use it normally. Listing \u00b6 To get the list of all the instances that can be served by this server : $ cozy-stack instances ls [ flags ] Flags are optional, more info on ls . Destroying \u00b6 An instance is destroyed through the command line. A confirmation is asked from the CLI user unless the \u2013force flag is passed: $ cozy-stack instances destroy When the deletion of an instance starts, the stack puts a flag deleting on the instance. This flag avoids that someone can try again to destroy the instance while the stack is doing cleaning before the real deletion (like deleting accounts). It\u2019s possible to remove manually the flag via the command cozy-stack instance modify --deleting=false to force a deletion that has failed. Blocking \u00b6 If you manage several instances on your stack, you can block some instances. When an instance is blocked (for whatever reason), the user cannot use his Cozy anymore and has to wait to be unblocked. $ cozy-stack instances modify --blocked A --blocking-reason can be added for specific cases and to inform a user the reason of the blocking. Several pre-included reasons are included, but you can define your owns if needed. These reasons are: \"LOGIN_FAILED\" : The instance was blocked because of too many login attempts \"PAYMENT_FAILED\" : The instance waits for a payment to be done \"UNKNOWN\" : The instance was blocked for an unknown reason Modifying \u00b6 If you want to edit an instance, see instances modify manpage .", "title": "Managing Instances"}, {"location": "cozy-stack/instance/#instances", "text": "A single cozy-stack can manage several instances. Requests to different instances are identified through the Host HTTP Header, any reverse proxy placed in front of the cozy-stack should forward this header.", "title": "Instances"}, {"location": "cozy-stack/instance/#creation", "text": "An instance is created on the command line: $ cozy-stack instances add [ flags ] The flags are documented in the instances add manpage . It registers the instance in a global couchdb database global/instances and creates the proper databases ($PREFIX/$DOCTYPE) for these doctypes: io.cozy.apps io.cozy.contacts io.cozy.files io.cozy.jobs io.cozy.konnectors io.cozy.notifications io.cozy.oauth.clients io.cozy.permissions io.cozy.sessions.logins io.cozy.settings io.cozy.shared io.cozy.sharings io.cozy.triggers Then, it creates some indexes for these doctypes, and some directories: / , with the id io.cozy.files.root-dir the trash, with the id io.cozy.files.trash-dir /Administrative /Photos /Photos/Uploaded from Cozy Photos /Photos/Backed up from my mobile The names are localized: If a locale is provided through the CLI, the directories will be created with names in this locale. Then it creates the basic settings with the options from the CLI. Finally, applications from the --apps CLI option are installed.", "title": "Creation"}, {"location": "cozy-stack/instance/#onboarding", "text": "At the end of the instance creation, the CLI returns a token, called registerToken . The registerToken can be used to send a link to the user, where they will be able to choose their password. After that, the instance is said to be onboarded, and the user can use it normally.", "title": "Onboarding"}, {"location": "cozy-stack/instance/#listing", "text": "To get the list of all the instances that can be served by this server : $ cozy-stack instances ls [ flags ] Flags are optional, more info on ls .", "title": "Listing"}, {"location": "cozy-stack/instance/#destroying", "text": "An instance is destroyed through the command line. A confirmation is asked from the CLI user unless the \u2013force flag is passed: $ cozy-stack instances destroy When the deletion of an instance starts, the stack puts a flag deleting on the instance. This flag avoids that someone can try again to destroy the instance while the stack is doing cleaning before the real deletion (like deleting accounts). It\u2019s possible to remove manually the flag via the command cozy-stack instance modify --deleting=false to force a deletion that has failed.", "title": "Destroying"}, {"location": "cozy-stack/instance/#blocking", "text": "If you manage several instances on your stack, you can block some instances. When an instance is blocked (for whatever reason), the user cannot use his Cozy anymore and has to wait to be unblocked. $ cozy-stack instances modify --blocked A --blocking-reason can be added for specific cases and to inform a user the reason of the blocking. Several pre-included reasons are included, but you can define your owns if needed. These reasons are: \"LOGIN_FAILED\" : The instance was blocked because of too many login attempts \"PAYMENT_FAILED\" : The instance waits for a payment to be done \"UNKNOWN\" : The instance was blocked for an unknown reason", "title": "Blocking"}, {"location": "cozy-stack/instance/#modifying", "text": "If you want to edit an instance, see instances modify manpage .", "title": "Modifying"}, {"location": "cozy-stack/intents/", "text": "Table of contents Intents \u00b6 Overview Glossary Proposal 1. Manifest 2. Intent Start 3. Service Resolution 4. Handshake 5. Processing & Terminating Routes Annexes Use cases Bibliography & Prior Art Discarded Ideas Overview \u00b6 A typical Cozy Cloud runs multiple applications, but most of these applications are focused on one task and interact with one particular type of data. However, Cozy Cloud especially shines when data is combined across apps to provide an integrated experience. This is made difficult by the fact that apps have no dedicated back-end and that they have restricted access to documents. This document outlines a proposal for apps to rely on each other to accomplish certain tasks and gain access to new documents, in a way that hopefully is neither painful for the users nor the developers. Glossary \u00b6 Intent : Intents, sometimes also called Activities, is a pattern used in environments where multiple apps with different purposes coexist. The idea is that any app can express the need to do something that it can\u2019t do itself, and an app that can do it will take over from there. Stack : refers to cozy-stack , the server-side part of the Cozy infrastructure. Client : the client is the application that starts an intent. Service : the service is the application that handles an intent started by a client. Available apps : Uninstalled applications that handles the intent. Proposal \u00b6 In this proposal, services declare themselves through their manifest. When a clients starts an intent, the stack finds the appropriate service and help the two apps to create a communication channel between them. After the channel is ready, the intent is processed. These steps are detailed below. 1. Manifest \u00b6 Every app can register itself as a potential handler for one or more intents. To do so, it must provide the following information for each intent it wishes to handle: action : A verb that describes what the service should do. The most common actions are CREATE , EDIT , OPEN , PICK , and SHARE . While we recommend using one of these verbs, the list is not exhaustive and may be extended by any app. type : One or more types of data on which the service knows how to operate the action . A type can be expressed as a MIME type or a Cozy Document Type . The application must have permissions for any Cozy Document Type listed here. You can also think of the type as the intent\u2019s subject. href : the relative URL of the route designed to handle this intent. A query-string with the intent id will be added to this URL. These informations must be provided in the manifest of the application, inside the intents key. Here is a very simple example: \"intents\" : [ { \"action\" : \"PICK\" , \"type\" : [ \"io.cozy.files\" ], \"href\" : \"/pick\" } ] When this service is called, it will load the page https://service.domain.example.com/pick?intent=123abc . Here is an example of an app that supports multiple data types: \"intents\" : [ { \"action\" : \"PICK\" , \"type\" : [ \"io.cozy.files\" , \"image/*\" ], \"href\" : \"/pick\" } ] Finally, here is an example of an app that supports several intent types: \"intents\" : [ { \"action\" : \"PICK\" , \"type\" : [ \"io.cozy.files\" , \"image/*\" ], \"href\" : \"/pick\" }, { \"action\" : \"VIEW\" , \"type\" : [ \"image/gif\" ], \"href\" : \"/viewer\" } ] This information is stored by the stack when the application is installed. 2. Intent Start \u00b6 Any app can start a new intent whenever it wants. When it does, the app becomes the client . To start an intent, it must specify the following information: action : an action verb, which will be matched against the actions declared in services manifest files. type : a single data type, which will be matched against the types declared in services manifest files. There are also two optional fields that can be defined at the start of the intent: data : Any data that the client wants to make available to the service. data must be a JSON object but its structure is left to the discretion of the client. The only exception is when type is a MIME type and the client wishes to send a file to the service. In that case, the file should be represented as a base-64 encoded Data URL and must be named content . This convention is also recomended when dealing with other intent type s. See the examples below for an example of this. permissions : When type is a Cozy Document Type and the client expects to receive one or more documents as part of the reply from the service, the permissions field allows the client to request permissions for these documents. permissions is a list of HTTP Verbs. Refer to this section of the permission documentation for more information. Note : if the intent\u2019s subject is a Cozy Doctype that holds references to other Cozy Documents (such as an album referencing photos or a playlist referencing music files), the permissions should be granted for the referenced documents too, whenever possible. Here is an example of what the API could look like: // \"Let the user pick a file\" cozy . intents . start ( 'PICK' , 'io.cozy.files' ) . then ( document => { // document is a JSON representation of the picked file }); // \"Create a contact, with some information already filled out\" cozy . intents . start ( 'CREATE' , 'io.cozy.contacts' , { name : 'John Johnsons' , tel : '+12345678' email : 'john@johnsons.com' }) . then ( document => { // document is a JSON representation of the contact that was created }); // \"Save this file somewhere\" cozy . intents . start ( 'CREATE' , 'io.cozy.files' , { content : 'data:application/zip;base64,UEsDB...' , name : 'photos.zip' }); // \"Create a new note, and give me read-only access to it\" cozy . intents . start ( 'CREATE' , 'io.cozy.notes' , {}, [ 'GET' ]) . then ( document => { // document is a JSON representation of the note that was created. // Additionally, this note can now be retrieved through the API since we have read access on it. }); // \"Create an event based on the provided data, and give me full access to it\" cozy . intents . start ( 'CREATE' , 'io.cozy.events' , { date : '2017/06/24' , title : 'Beach day' }, [ 'ALL' ]) . then ( document => { // document is a JSON representation of the note that was created. // Additionally, this note can now be retrieved through the API since we have read access on it. }); // \"Crop this picture\" cozy . intents . start ( 'EDIT' , 'image/png' , { content : 'data:image/png;base64,iVBORw...' , width : 50 , height : 50 }) . then ( image => { //image is the edited version of the image provided above. }) 3. Service Resolution \u00b6 The service resolution is the phase where a service is chosen to handle an intent. This phase is handled by the stack. After the client has started it\u2019s intent, it sends the action , the type and the permissions to the stack. The stack will then traverse the list of installed apps and find all the apps that can handle that specific combination. Note that if the intent request GET permissions on a certain Cozy Document Type, but the service does not have this permission itself, it can not handle the intent. The stack then stores the information for that intent: A unique id for that intent Client URL Service URL action type permissions Finally, the service URL is suffixed with ?intent= followed by the intent\u2019s id, and then sent to the client. 4. Available apps \u00b6 In addition to the services that manage intents, a list of available (but not installed) applications of the instance that handles the intent is returned. This object list is called availableApps and contains: - The application slug - The application name Service choice \u00b6 If more than one service match the intent\u2019s criteria, the stack returns the list of all matching service URLs to the client (and stores it in the service URL version of the intent it keeps in memory). The client is then free to pick one arbitrarily. The client may also decide to let the user choose one of the services. To do this, it should start another intent with a PICK action and a io.cozy.apps type . This intent should be resolved by the stack to a special page, in order to avoid having multiple services trying to handle it and ending up in a loop. This special page is a service like any other; it expects the list of services to pick from as input data, and will return the one that has been picked to the client. The client can then proceed with the first intent. The user may decide to abort the intent before picking a service. If that is the case, the choice page will need to inform the client that the intent was aborted. No available service \u00b6 If no service is available to handle an intent, the stack returns an error to the client. However, some non-installed applications may handle the intent, and are listed in the availableApps field. 4. Handshake \u00b6 The next phase consist of the client and the service establishing a communication channel between them. The communication will be done using the window.postMessage API. Service Initialization \u00b6 When the client receives the service URL from the stack, it starts to listen for messages coming from that URL. Once the listener is started, it opens an iframe that points to the service\u2019s URL. Service to Client \u00b6 At this point, the service app is opened on the route that it provided in the href part of it\u2019s manifest. This route now also contains the intent\u2019s id. The service queries the stack to find out information about the intent, passing along the intent id. In response, the stack sends the client\u2019s URL, the action , and the type . If the intent includes permissions , the stack sends them too, as well as the client\u2019s permission id. It then starts to listen for messages coming from the client\u2019s URL. Eventually, it sends a message to the client, as a mean to inform it that the service is now ready. Client to Service \u00b6 After the client receives the \u201cready\u201d message from the service, it sends a message to the service acknowledging the \u201cready\u201d state. Along with this message, it should send the data that was provided at the start of the intent, if any. 5. Processing & Terminating \u00b6 After this handshake, there is a confirmed communication channel between the client and the service, and the service knows what it has to do. This is the phase where the user interacts with the service. If the service is going to grant extra permissions to the client app, it is strongly recommended to make this clear to the user. When the service has finished his task, it sends a \u201ccompleted\u201d message to the client. Permissions extensions should have been done before that. Along with the completed message, the service should send any data it deems relevant. This data should be a JSON object. Again, the structure of that object is left to the discretion of the service, except when type is a MIME type. In that case, the file should be represented as a base-64 encoded Data URL and must be named content . This convention is also recomended when dealing with other intent type s. After the client receives a \u201ccompleted\u201d message, it can close the service\u2019s iframe and resume operations as usual. If, for whatever reason, the service can not fulfill the intent, it can send an \u201cerror\u201d message to the client. When the client receives an \u201cerror\u201d message, the intent is aborted and the iframe can be closed. Routes \u00b6 POST /intents \u00b6 The client app can ask to start an intent via this route. Any client-side app can call this route, no permission is needed. Request \u00b6 POST /intents HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.intents\" , \"attributes\" : { \"action\" : \"PICK\" , \"type\" : \"io.cozy.files\" , \"permissions\" : [ \"GET\" ] } } } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"type\" : \"io.cozy.intents\" , \"attributes\" : { \"action\" : \"PICK\" , \"type\" : \"io.cozy.files\" , \"permissions\" : [ \"GET\" ], \"client\" : \"https://contacts.cozy.example.net\" , \"services\" : [ { \"slug\" : \"files\" , \"href\" : \"https://files.cozy.example.net/pick?intent=77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" } ], \"availableApps\" : [ { \"slug\" : \"myapp\" , \"name\" : \"My App\" } ] }, \"links\" : { \"self\" : \"/intents/77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"permissions\" : \"/permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" } } } GET /intents/:id \u00b6 Get all the informations about the intent Note : only the service can access this route (no permission involved). Request \u00b6 GET /intents/77bcc42c-0fd8-11e7-ac95-8f605f6e8338 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer J9l-ZhwP... Content-Type : application/vnd.api+json Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"type\" : \"io.cozy.intents\" , \"attributes\" : { \"action\" : \"PICK\" , \"type\" : \"io.cozy.files\" , \"permissions\" : [ \"GET\" ], \"client\" : \"https://contacts.cozy.example.net\" , \"services\" : [ { \"slug\" : \"files\" , \"href\" : \"https://files.cozy.example.net/pick?intent=77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" } ], \"availableApps\" : [ { \"slug\" : \"myapp\" , \"name\" : \"My App\" } ] }, \"links\" : { \"self\" : \"/intents/77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"permissions\" : \"/permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" } } } Annexes \u00b6 Use Cases \u00b6 Here is a non exhaustive list of situations that may use intents: Configure a new connector account Share a photo album via email Add an attachment to an email Attach a note to a contact Create a contact based on an email Save an attachment received in an email Create a birthday event in a calendar, based on a contact Create an event based on an email\u2019s content Create an event based on an ICS file Chose an avatar for a contact Open a file from the file browser (music, PDF, image, \u2026) Attach a receipt to an expense Provide a tip for another application Bibliography & Prior Art \u00b6 Prior art Web intents WebActivities and WebActivities on FirefoxOS (archive) Siri Intents Android Intents iOS extensions Discarded Ideas \u00b6 Disposition \u00b6 Some specifications include a disposition field in the manifests, that gives a hint to the client about how to display the service (inlined or in a new window). Since we were unable to find a use case where a new window is required, we decided not to include the disposition in this specification. It might be added later if the need arises. Client / Server architecture \u00b6 Instead of letting the two applications communicate with each other, they could be made to talk through the stack. This would be useful as the stack could act as a middleware, transforming data on the fly or granting permissions where appropriate. However, this approach has also severe drawbacks, notably the fact that the stack must hold a copy of all the data that the apps want to transfer (which can include large files). It also makes it significantly harder for the client to know when the intent has been processed. Data representation \u00b6 The client could explicitly request a data format to be used in the communication. However, this idea was abandoned because the format is always json, except when then intent\u2019s type is a MIME type, in which case the data format also uses this type.", "title": "/intents - Intents"}, {"location": "cozy-stack/intents/#intents", "text": "Overview Glossary Proposal 1. Manifest 2. Intent Start 3. Service Resolution 4. Handshake 5. Processing & Terminating Routes Annexes Use cases Bibliography & Prior Art Discarded Ideas", "title": "Intents"}, {"location": "cozy-stack/intents/#overview", "text": "A typical Cozy Cloud runs multiple applications, but most of these applications are focused on one task and interact with one particular type of data. However, Cozy Cloud especially shines when data is combined across apps to provide an integrated experience. This is made difficult by the fact that apps have no dedicated back-end and that they have restricted access to documents. This document outlines a proposal for apps to rely on each other to accomplish certain tasks and gain access to new documents, in a way that hopefully is neither painful for the users nor the developers.", "title": "Overview"}, {"location": "cozy-stack/intents/#glossary", "text": "Intent : Intents, sometimes also called Activities, is a pattern used in environments where multiple apps with different purposes coexist. The idea is that any app can express the need to do something that it can\u2019t do itself, and an app that can do it will take over from there. Stack : refers to cozy-stack , the server-side part of the Cozy infrastructure. Client : the client is the application that starts an intent. Service : the service is the application that handles an intent started by a client. Available apps : Uninstalled applications that handles the intent.", "title": "Glossary"}, {"location": "cozy-stack/intents/#proposal", "text": "In this proposal, services declare themselves through their manifest. When a clients starts an intent, the stack finds the appropriate service and help the two apps to create a communication channel between them. After the channel is ready, the intent is processed. These steps are detailed below.", "title": "Proposal"}, {"location": "cozy-stack/intents/#1-manifest", "text": "Every app can register itself as a potential handler for one or more intents. To do so, it must provide the following information for each intent it wishes to handle: action : A verb that describes what the service should do. The most common actions are CREATE , EDIT , OPEN , PICK , and SHARE . While we recommend using one of these verbs, the list is not exhaustive and may be extended by any app. type : One or more types of data on which the service knows how to operate the action . A type can be expressed as a MIME type or a Cozy Document Type . The application must have permissions for any Cozy Document Type listed here. You can also think of the type as the intent\u2019s subject. href : the relative URL of the route designed to handle this intent. A query-string with the intent id will be added to this URL. These informations must be provided in the manifest of the application, inside the intents key. Here is a very simple example: \"intents\" : [ { \"action\" : \"PICK\" , \"type\" : [ \"io.cozy.files\" ], \"href\" : \"/pick\" } ] When this service is called, it will load the page https://service.domain.example.com/pick?intent=123abc . Here is an example of an app that supports multiple data types: \"intents\" : [ { \"action\" : \"PICK\" , \"type\" : [ \"io.cozy.files\" , \"image/*\" ], \"href\" : \"/pick\" } ] Finally, here is an example of an app that supports several intent types: \"intents\" : [ { \"action\" : \"PICK\" , \"type\" : [ \"io.cozy.files\" , \"image/*\" ], \"href\" : \"/pick\" }, { \"action\" : \"VIEW\" , \"type\" : [ \"image/gif\" ], \"href\" : \"/viewer\" } ] This information is stored by the stack when the application is installed.", "title": "1. Manifest"}, {"location": "cozy-stack/intents/#2-intent-start", "text": "Any app can start a new intent whenever it wants. When it does, the app becomes the client . To start an intent, it must specify the following information: action : an action verb, which will be matched against the actions declared in services manifest files. type : a single data type, which will be matched against the types declared in services manifest files. There are also two optional fields that can be defined at the start of the intent: data : Any data that the client wants to make available to the service. data must be a JSON object but its structure is left to the discretion of the client. The only exception is when type is a MIME type and the client wishes to send a file to the service. In that case, the file should be represented as a base-64 encoded Data URL and must be named content . This convention is also recomended when dealing with other intent type s. See the examples below for an example of this. permissions : When type is a Cozy Document Type and the client expects to receive one or more documents as part of the reply from the service, the permissions field allows the client to request permissions for these documents. permissions is a list of HTTP Verbs. Refer to this section of the permission documentation for more information. Note : if the intent\u2019s subject is a Cozy Doctype that holds references to other Cozy Documents (such as an album referencing photos or a playlist referencing music files), the permissions should be granted for the referenced documents too, whenever possible. Here is an example of what the API could look like: // \"Let the user pick a file\" cozy . intents . start ( 'PICK' , 'io.cozy.files' ) . then ( document => { // document is a JSON representation of the picked file }); // \"Create a contact, with some information already filled out\" cozy . intents . start ( 'CREATE' , 'io.cozy.contacts' , { name : 'John Johnsons' , tel : '+12345678' email : 'john@johnsons.com' }) . then ( document => { // document is a JSON representation of the contact that was created }); // \"Save this file somewhere\" cozy . intents . start ( 'CREATE' , 'io.cozy.files' , { content : 'data:application/zip;base64,UEsDB...' , name : 'photos.zip' }); // \"Create a new note, and give me read-only access to it\" cozy . intents . start ( 'CREATE' , 'io.cozy.notes' , {}, [ 'GET' ]) . then ( document => { // document is a JSON representation of the note that was created. // Additionally, this note can now be retrieved through the API since we have read access on it. }); // \"Create an event based on the provided data, and give me full access to it\" cozy . intents . start ( 'CREATE' , 'io.cozy.events' , { date : '2017/06/24' , title : 'Beach day' }, [ 'ALL' ]) . then ( document => { // document is a JSON representation of the note that was created. // Additionally, this note can now be retrieved through the API since we have read access on it. }); // \"Crop this picture\" cozy . intents . start ( 'EDIT' , 'image/png' , { content : 'data:image/png;base64,iVBORw...' , width : 50 , height : 50 }) . then ( image => { //image is the edited version of the image provided above. })", "title": "2. Intent Start"}, {"location": "cozy-stack/intents/#3-service-resolution", "text": "The service resolution is the phase where a service is chosen to handle an intent. This phase is handled by the stack. After the client has started it\u2019s intent, it sends the action , the type and the permissions to the stack. The stack will then traverse the list of installed apps and find all the apps that can handle that specific combination. Note that if the intent request GET permissions on a certain Cozy Document Type, but the service does not have this permission itself, it can not handle the intent. The stack then stores the information for that intent: A unique id for that intent Client URL Service URL action type permissions Finally, the service URL is suffixed with ?intent= followed by the intent\u2019s id, and then sent to the client.", "title": "3. Service Resolution"}, {"location": "cozy-stack/intents/#4-available-apps", "text": "In addition to the services that manage intents, a list of available (but not installed) applications of the instance that handles the intent is returned. This object list is called availableApps and contains: - The application slug - The application name", "title": "4. Available apps"}, {"location": "cozy-stack/intents/#service-choice", "text": "If more than one service match the intent\u2019s criteria, the stack returns the list of all matching service URLs to the client (and stores it in the service URL version of the intent it keeps in memory). The client is then free to pick one arbitrarily. The client may also decide to let the user choose one of the services. To do this, it should start another intent with a PICK action and a io.cozy.apps type . This intent should be resolved by the stack to a special page, in order to avoid having multiple services trying to handle it and ending up in a loop. This special page is a service like any other; it expects the list of services to pick from as input data, and will return the one that has been picked to the client. The client can then proceed with the first intent. The user may decide to abort the intent before picking a service. If that is the case, the choice page will need to inform the client that the intent was aborted.", "title": "Service choice"}, {"location": "cozy-stack/intents/#no-available-service", "text": "If no service is available to handle an intent, the stack returns an error to the client. However, some non-installed applications may handle the intent, and are listed in the availableApps field.", "title": "No available service"}, {"location": "cozy-stack/intents/#4-handshake", "text": "The next phase consist of the client and the service establishing a communication channel between them. The communication will be done using the window.postMessage API.", "title": "4. Handshake"}, {"location": "cozy-stack/intents/#service-initialization", "text": "When the client receives the service URL from the stack, it starts to listen for messages coming from that URL. Once the listener is started, it opens an iframe that points to the service\u2019s URL.", "title": "Service Initialization"}, {"location": "cozy-stack/intents/#service-to-client", "text": "At this point, the service app is opened on the route that it provided in the href part of it\u2019s manifest. This route now also contains the intent\u2019s id. The service queries the stack to find out information about the intent, passing along the intent id. In response, the stack sends the client\u2019s URL, the action , and the type . If the intent includes permissions , the stack sends them too, as well as the client\u2019s permission id. It then starts to listen for messages coming from the client\u2019s URL. Eventually, it sends a message to the client, as a mean to inform it that the service is now ready.", "title": "Service to Client"}, {"location": "cozy-stack/intents/#client-to-service", "text": "After the client receives the \u201cready\u201d message from the service, it sends a message to the service acknowledging the \u201cready\u201d state. Along with this message, it should send the data that was provided at the start of the intent, if any.", "title": "Client to Service"}, {"location": "cozy-stack/intents/#5-processing-terminating", "text": "After this handshake, there is a confirmed communication channel between the client and the service, and the service knows what it has to do. This is the phase where the user interacts with the service. If the service is going to grant extra permissions to the client app, it is strongly recommended to make this clear to the user. When the service has finished his task, it sends a \u201ccompleted\u201d message to the client. Permissions extensions should have been done before that. Along with the completed message, the service should send any data it deems relevant. This data should be a JSON object. Again, the structure of that object is left to the discretion of the service, except when type is a MIME type. In that case, the file should be represented as a base-64 encoded Data URL and must be named content . This convention is also recomended when dealing with other intent type s. After the client receives a \u201ccompleted\u201d message, it can close the service\u2019s iframe and resume operations as usual. If, for whatever reason, the service can not fulfill the intent, it can send an \u201cerror\u201d message to the client. When the client receives an \u201cerror\u201d message, the intent is aborted and the iframe can be closed.", "title": "5. Processing & Terminating"}, {"location": "cozy-stack/intents/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/intents/#post-intents", "text": "The client app can ask to start an intent via this route. Any client-side app can call this route, no permission is needed.", "title": "POST /intents"}, {"location": "cozy-stack/intents/#request", "text": "POST /intents HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.intents\" , \"attributes\" : { \"action\" : \"PICK\" , \"type\" : \"io.cozy.files\" , \"permissions\" : [ \"GET\" ] } } }", "title": "Request"}, {"location": "cozy-stack/intents/#response", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"type\" : \"io.cozy.intents\" , \"attributes\" : { \"action\" : \"PICK\" , \"type\" : \"io.cozy.files\" , \"permissions\" : [ \"GET\" ], \"client\" : \"https://contacts.cozy.example.net\" , \"services\" : [ { \"slug\" : \"files\" , \"href\" : \"https://files.cozy.example.net/pick?intent=77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" } ], \"availableApps\" : [ { \"slug\" : \"myapp\" , \"name\" : \"My App\" } ] }, \"links\" : { \"self\" : \"/intents/77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"permissions\" : \"/permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" } } }", "title": "Response"}, {"location": "cozy-stack/intents/#get-intentsid", "text": "Get all the informations about the intent Note : only the service can access this route (no permission involved).", "title": "GET /intents/:id"}, {"location": "cozy-stack/intents/#request_1", "text": "GET /intents/77bcc42c-0fd8-11e7-ac95-8f605f6e8338 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer J9l-ZhwP... Content-Type : application/vnd.api+json Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/intents/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"type\" : \"io.cozy.intents\" , \"attributes\" : { \"action\" : \"PICK\" , \"type\" : \"io.cozy.files\" , \"permissions\" : [ \"GET\" ], \"client\" : \"https://contacts.cozy.example.net\" , \"services\" : [ { \"slug\" : \"files\" , \"href\" : \"https://files.cozy.example.net/pick?intent=77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" } ], \"availableApps\" : [ { \"slug\" : \"myapp\" , \"name\" : \"My App\" } ] }, \"links\" : { \"self\" : \"/intents/77bcc42c-0fd8-11e7-ac95-8f605f6e8338\" , \"permissions\" : \"/permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" } } }", "title": "Response"}, {"location": "cozy-stack/intents/#annexes", "text": "", "title": "Annexes"}, {"location": "cozy-stack/intents/#use-cases", "text": "Here is a non exhaustive list of situations that may use intents: Configure a new connector account Share a photo album via email Add an attachment to an email Attach a note to a contact Create a contact based on an email Save an attachment received in an email Create a birthday event in a calendar, based on a contact Create an event based on an email\u2019s content Create an event based on an ICS file Chose an avatar for a contact Open a file from the file browser (music, PDF, image, \u2026) Attach a receipt to an expense Provide a tip for another application", "title": "Use Cases"}, {"location": "cozy-stack/intents/#bibliography-prior-art", "text": "Prior art Web intents WebActivities and WebActivities on FirefoxOS (archive) Siri Intents Android Intents iOS extensions", "title": "Bibliography & Prior Art"}, {"location": "cozy-stack/intents/#discarded-ideas", "text": "", "title": "Discarded Ideas"}, {"location": "cozy-stack/intents/#disposition", "text": "Some specifications include a disposition field in the manifests, that gives a hint to the client about how to display the service (inlined or in a new window). Since we were unable to find a use case where a new window is required, we decided not to include the disposition in this specification. It might be added later if the need arises.", "title": "Disposition"}, {"location": "cozy-stack/intents/#client-server-architecture", "text": "Instead of letting the two applications communicate with each other, they could be made to talk through the stack. This would be useful as the stack could act as a middleware, transforming data on the fly or granting permissions where appropriate. However, this approach has also severe drawbacks, notably the fact that the stack must hold a copy of all the data that the apps want to transfer (which can include large files). It also makes it significantly harder for the client to know when the intent has been processed.", "title": "Client / Server architecture"}, {"location": "cozy-stack/intents/#data-representation", "text": "The client could explicitly request a data format to be used in the communication. However, this idea was abandoned because the format is always json, except when then intent\u2019s type is a MIME type, in which case the data format also uses this type.", "title": "Data representation"}, {"location": "cozy-stack/jobs/", "text": "Table of contents Jobs \u00b6 Jobs are designed to represent asynchronous tasks that your cozy can execute. These tasks can be scheduled in advance, recurring or sudden and provide various services. At the time, we do not provide \u201cgeneric\u201d and programmable tasks. This list of available workers is part of the defined API. The job queue can be either local to the cozy-stack when used as a monolithic instance (self-hosted for instance) or distributed via a redis server for distributed infrastructures. This doc introduces two cozy types: io.cozy.jobs for jobs io.cozy.triggers for triggers Triggers \u00b6 Jobs can be queued up via the /jobs/queue/:worker-type API, for a direct execution. But it can also be convenient to schedule jobs on some conditions, and the triggers are the way to do that. Jobs can be launched by different types of triggers: @at to schedule a one-time job executed after at a specific time in the future @in to schedule a one-time job executed after a specific amount of time @hourly to schedule jobs that run once an hour @daily to schedule jobs that run once a day @weekly to schedule jobs that run once a week @monthly to schedule jobs that run once a month @every to schedule periodic jobs executed at a given fix interval @cron to schedule recurring jobs scheduled at specific times @event to launch a job after a change on documents in the cozy @webhook to launch a job when an HTTP request hit a specific URL @client when the client controls when the job are launched. These triggers have specific syntaxes to describe when jobs should be scheduled. See below for more informations. @at syntax \u00b6 The @at trigger takes a ISO-8601 formatted string indicating a UTC time in the future. The date is of this form: YYYY-MM-DDTHH:mm:ss.sssZ Be aware that the @at trigger is removed from the doctype after it has created the associated job. Examples @at 2018-12-12T15:36:25.507Z @in syntax \u00b6 The @in trigger takes the same duration syntax as @every Be aware that the @in trigger is removed from the doctype after it has created the associated job. Examples @in 10m @in 1h30m @daily syntax \u00b6 The @daily trigger will create a job once a day. By default, the stack is free to choose the day and hour when to do that, but you can add restrictions: @daily # Once a day, any hour @daily before 5 am # Once a day, between midnight and 5am (UTC) @daily after 10 pm # Once a day, between 10pm and midnight (UTC) @daily between 8 am and 6 pm # Once a day, between 8am and 6pm (UTC) @weekly syntax \u00b6 The @weekly trigger will create a job once a week. By default, the stack is free to choose the day and hour when to do that, but you can add restrictions: @weekly # Once a week, any day, any hour @weekly on monday # Every monday @weekly on mon , wed , fri # Once a week, on a monday, wednesday, or friday @weekly on wed - fri # Once a week, on a wednesday, thursday, or friday @weekly on weekday # Once a week, but not the week-end @weekly on weekend # Every week-end (saturday or sunday) @weekly before 5 am # Once a week, any day, but between midnight and 5am (UTC) @weekly after 10 pm # Once a week, any day, but between 10pm and midnight (UTC) @weekly between 8 am and 6 pm # Once a week, any day, between 8am and 6pm (UTC) @weekly on monday before 9 am # Every monday, between midnight and 9am (UTC) @monthly syntax \u00b6 The @monthly trigger will create a job once a month. By default, the stack is free to choose the day and hour when to do that, but you can add restrictions: @monthly # Once a month, any day, any hour @monthly on the 1 # Every first day of the month @monthly on the 1 - 5 # Once a month, on the first five days of the month @monthly before 5 am # Once a month, any day, but between midnight and 5am (UTC) @monthly after 10 pm # Once a month, any day, but between 10pm and midnight (UTC) @monthly between 8 am and 6 pm # Once a month, any day, between 8am and 6pm (UTC) @monthly on the 1 before 9 am # Every first day of the month, between midnight and 9am (UTC) Note: the current implementation is to take a random day/hour and run the job each month at this day/hour. So, you should avoid 29-31 if you really want the job to run each month. @every syntax \u00b6 The @every trigger uses the same syntax as golang\u2019s time.ParseDuration (but only support time units above seconds): A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as \u201c300ms\u201d, \u201c1.5h\u201d or \u201c2h45m\u201d. Valid time units are \u201cs\u201d, \u201cm\u201d, \u201ch\u201d. Examples @every 1.5h # schedules every 1 and a half hours @every 30m10s # schedules every 30 minutes and 10 seconds @cron syntax \u00b6 In order to schedule recurring jobs, the @cron trigger has the syntax using six fields: Field name Mandatory? Allowed values Allowed special characters Seconds Yes 0-59 * / , - Minutes Yes 0-59 * / , - Hours Yes 0-23 * / , - Day of month Yes 1-31 * / , - ? Month Yes 1-12 or JAN-DEC * / , - Day of week Yes 0-6 or SUN-SAT * / , - ? Asterisk ( * ) The asterisk indicates that the cron expression will match for all values of the field; e.g., using an asterisk in the 5th field (month) would indicate every month. Slash ( / ) Slashes are used to describe increments of ranges. For example 3-59/15 in the 1st field (minutes) would indicate the 3rd minute of the hour and every 15 minutes thereafter. The form \"*\\/...\" is equivalent to the form \"first-last/...\" , that is, an increment over the largest possible range of the field. The form \"N-/...\" is accepted as meaning \"N-MAX/...\" , that is, starting at N, use the increment until the end of that specific range. It does not wrap around. Comma ( , ) Commas are used to separate items of a list. For example, using \"MON,WED,FRI\" in the 5th field (day of week) would mean Mondays, Wednesdays and Fridays. Hyphen ( - ) Hyphens are used to define ranges. For example, 9-17 would indicate every hour between 9am and 5pm inclusive. Question mark ( ? ) Question mark may be used instead of * for leaving either day-of-month or day-of-week blank. To schedule jobs given an interval: Examples: @cron 0 0 0 1 1 * # Run once a year, midnight, Jan. 1st @cron 0 0 0 1 1 * # Run once a year, midnight, Jan. 1st @cron 0 0 0 1 * * # Run once a month, midnight, first of month @cron 0 0 0 * * 0 # Run once a week, midnight on Sunday @cron 0 0 0 * * * # Run once a day, midnight @cron 0 0 * * * * # Run once an hour, beginning of hour @event syntax \u00b6 The @event syntax allows to trigger a job when something occurs in the stack. It follows the same syntax than permissions scope string: type[:verb][:values][:selector] Unlike for permissions string, the verb should be one of CREATED , DELETED , UPDATED . It is possible to put several verbs, separated by a comma. There is also a special value != . It means that a job will be trigger only if the value for the given selector has changed (ie the value before the update and the value after that are different). The job worker will receive a compound message including original trigger_infos messages and the event which has triggered it. Examples: @event io.cozy.files // anything happens on files @event io.cozy.files:CREATED // a file was created @event io.cozy.files:DELETED:image/jpg:mime // an image was deleted @event io.cozy.bank.operations:CREATED io.cozy.bank.bills:CREATED // a bank operation or a bill @event io.cozy.bank.operations:CREATED,UPDATED // a bank operation created or updated @event io.cozy.bank.operations:UPDATED:!=:category // a change of category for a bank operation @webhook syntax \u00b6 It takes no parameter. The URL to hit is not controlled by the request, but is chosen by the server (and is returned as webhook in the links JSON-API response). Example: @webhook @client syntax \u00b6 It takes no parameter and can only by used for the client worker. The stack won\u2019t create a job unless a client calls the launch endpoint for this trigger. The main goal of this trigger is keep a state, as the aggregation of job results. Error Handling \u00b6 Jobs can fail to execute their task. We have two ways to parameterize such cases. Retry \u00b6 A retry count can be optionally specified to ask the worker to re-execute the task if it has failed. Each retry is executed after a configurable delay. The try count is part of the attributes of the job. Also, each occurring error is kept in the errors field containing all the errors that may have happened. Timeout \u00b6 A worker may never end. To prevent this, a configurable timeout value is specified with the job. If a job does not end after the specified amount of time, it will be aborted. A timeout is just like another error from the worker and can provoke a retry if specified. Defaults \u00b6 By default, jobs are parameterized with a maximum of 3 tries with 1 minute timeout. These defaults may vary given the workload of the workers. Jobs API \u00b6 Example and description of the attributes of a io.cozy.jobs : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , // worker type name \"options\" : { \"timeout\" : 60 , // timeout value in seconds \"max_exec_count\" : 3 , // maximum number of time the job should be executed (including retries) }, \"arguments\" : { // the arguments will be given to the worker (if you look in CouchDB, it is called message there) \"mode\" : \"noreply\" , \"template_name\" : \"new_registration\" , \"template_values\" : { \"DevicesLink\" : \"http://me.cozy.localhost/#/connectedDevices\" , } }, \"state\" : \"running\" , // queued, running, done, errored \"queued_at\" : \"2016-09-19T12:35:08Z\" , // time of the queuing \"started_at\" : \"2016-09-19T12:35:08Z\" , // time of first execution \"error\" : \"\" // error message if any } Example and description of a job creation options \u2014 as you can see, the options are replicated in the io.cozy.jobs attributes: { \"timeout\" : 60 , // timeout value in seconds \"max_exec_count\" : 3 , // maximum number of retry } GET /jobs/:job-id \u00b6 Get a job informations given its ID. Request \u00b6 GET /jobs/123123 HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"state\" : \"running\" , \"queued_at\" : \"2016-09-19T12:35:08Z\" , \"started_at\" : \"2016-09-19T12:35:08Z\" , \"error\" : \"\" }, \"links\" : { \"self\" : \"/jobs/123123\" } } } POST /jobs/queue/:worker-type \u00b6 Enqueue programmatically a new job. This route requires a specific permission on the worker-type. A global permission on the global io.cozy.jobs doctype is not allowed. Each worker accepts different arguments. For konnectors, the arguments will be given in the process.env['COZY_FIELDS'] variable. Request \u00b6 POST /jobs/queue/sendmail HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"manual\" : false , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"arguments\" : {} // any json value used as arguments for the job } } } Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"state\" : \"running\" , \"queued_at\" : \"2016-09-19T12:35:08Z\" , \"started_at\" : \"2016-09-19T12:35:08Z\" , \"error\" : \"\" }, \"links\" : { \"self\" : \"/jobs/123123\" } } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb POST . The is required to restrict its permission to specific worker(s), like this (a global permission on the doctype is not allowed): { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to send mails from the user to his/her friends\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } POST /jobs/support \u00b6 Send a mail to the support (email address defined by mail.reply_to in the config file, or overwritten by context with contexts..reply_to ). It requires a permission on io.cozy.support (a permission on io.cozy.jobs:POST:sendmail:worker , or larger, is also accepted to ease the transition from sending manually a mail to the support via the sendmail queue). Request \u00b6 POST /jobs/support HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"arguments\" : { \"subject\" : \"Cozy is so cool!\" , \"body\" : \"I really love Cozy. Thank you so much!\" } } } } Response \u00b6 HTTP / 1.1 204 No Content POST /jobs/campaign-emails \u00b6 Send a non transactional (or campaign) email to the user via the dedicated campaign mail server (configured via campaign_mail attributes in the config file, or overwritten by context with campaign_mail.contexts. attributes). Both the subject and at least one part are required. Request \u00b6 POST /jobs/campaign-emails HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"arguments\" : { \"subject\" : \"Checkout the new cool stuff!\" , \"parts\" : [ { \"body\" : \"So many new features to check out!\" , \"type\" : \"text/plain\" } ] } } } } Response \u00b6 HTTP / 1.1 204 No Content Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb POST and the sendmail worker. This can be defined like so: { \"permissions\" : { \"campaign-emails\" : { \"description\" : \"Required to send campaign emails to the user\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } GET /jobs/queue/:worker-type \u00b6 List the jobs in the queue. Request \u00b6 GET /jobs/queue/sendmail HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 { \"data\" : [ { \"attributes\" : { \"domain\" : \"cozy.localhost:8080\" , \"options\" : null , \"queued_at\" : \"2017-09-29T15:32:31.953878568+02:00\" , \"started_at\" : \"0001-01-01T00:00:00Z\" , \"state\" : \"queued\" , \"worker\" : \"log\" }, \"id\" : \"77689bca9634b4fb08d6ca3d1643de5f\" , \"links\" : { \"self\" : \"/jobs/log/77689bca9634b4fb08d6ca3d1643de5f\" }, \"meta\" : { \"rev\" : \"1-f823bcd2759103a5ad1a98f4bf083b36\" }, \"type\" : \"io.cozy.jobs\" } ], \"meta\" : { \"count\" : 0 } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb GET . In most cases, the application will restrict its permission to only one worker, like this: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to know the number of jobs in the sendmail queues\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"GET\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } PATCH /jobs/:job-id \u00b6 This endpoint can be used for a job of the client worker (executed by a client, not on the server) to update the status. Request \u00b6 PATCH /jobs/022368c07dc701396403543d7eb8149c HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"022368c07dc701396403543d7eb8149c\" , \"attributes\" : { \"state\" : \"errored\" , \"error\" : \"LOGIN_FAILED\" } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"022368c07dc701396403543d7eb8149c\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : {}, \"state\" : \"errored\" , \"error\" : \"LOGIN_FAILED\" , \"queued_at\" : \"2021-04-12T12:34:56Z\" , \"started_at\" : \"2021-04-12T12:34:56Z\" , \"finished_at\" : \"2021-04-12T12:38:59Z\" }, \"links\" : { \"self\" : \"/jobs/022368c07dc701396403543d7eb8149c\" } } } POST /jobs/triggers \u00b6 Add a trigger of the worker. See triggers\u2019 descriptions to see the types of trigger and their arguments syntax. This route requires a specific permission on the worker type. A global permission on the global io.cozy.triggers doctype is not allowed. The debounce parameter can be used to limit the number of jobs created in a burst. It delays the creation of the job on the first input by the given time argument, and if the trigger has its condition matched again during this period, it won\u2019t create another job. It can be useful to combine it with the changes feed of couchdb with a last sequence number persisted by the worker, as it allows to have a nice diff between two executions of the worker. Its syntax is the one understood by go\u2019s time.ParseDuration . Request \u00b6 POST /jobs/triggers HTTP / 1.1 Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"type\" : \"@event\" , \"arguments\" : \"io.cozy.invitations\" , \"debounce\" : \"10m\" , \"worker\" : \"sendmail\" , \"message\" : {}, \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 } } } } Note : the message field was previously called worker_arguments . The latter version still works but is deprecated, you should use message instead. Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"attributes\" : { \"type\" : \"@every\" , \"arguments\" : \"30m10s\" , \"debounce\" : \"10m\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 } }, \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb POST . In most cases, the application will restrict its permission to only one worker, like this: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to send regularly mails from the user to his/her friends\" , \"type\" : \"io.cozy.triggers\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } GET /jobs/triggers/:trigger-id \u00b6 Get a trigger informations given its ID. Request \u00b6 GET /jobs/triggers/123123 HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"attributes\" : { \"type\" : \"@every\" , \"arguments\" : \"30m10s\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"current_state\" : { \"status\" : \"done\" , \"last_success\" : \"2017-11-20T13:31:09.01641731\" , \"last_successful_job_id\" : \"abcde\" , \"last_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_executed_job_id\" : \"abcde\" , \"last_failure\" : \"2017-11-20T13:31:09.01641731\" , \"last_failed_job_id\" : \"abcde\" , \"last_error\" : \"error value\" , \"last_manual_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_manual_job_id\" : \"abcde\" } }, \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb GET . A konnector can also call this endpoint for one of its triggers (no permission required). GET /jobs/triggers/:trigger-id/state \u00b6 Get the trigger current state, to give a big picture of the health of the trigger. last executed job status ( done , errored , queued or running ) last executed job that resulted in a successful executoin last executed job that resulted in an error last executed job from a manual execution (not executed by the trigger directly) Request \u00b6 GET /jobs/triggers/123123/state HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.triggers.state\" , \"id\" : \"123123\" , \"attributes\" : { \"status\" : \"done\" , \"last_success\" : \"2017-11-20T13:31:09.01641731\" , \"last_successful_job_id\" : \"abcde\" , \"last_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_executed_job_id\" : \"abcde\" , \"last_failure\" : \"2017-11-20T13:31:09.01641731\" , \"last_failed_job_id\" : \"abcde\" , \"last_error\" : \"error value\" , \"last_manual_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_manual_job_id\" : \"abcde\" } } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb GET . A konnector can also call this endpoint for one of its triggers (no permission required). GET /jobs/triggers/:trigger-id/jobs \u00b6 Get the jobs launched by the trigger with the specified ID. Query parameters: Limit : to specify the number of jobs to get out Request \u00b6 GET /jobs/triggers/123123/jobs?Limit=1 HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 { \"data\" : [ { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : {}, \"links\" : { \"self\" : \"/jobs/123123\" } } ] } PATCH /jobs/triggers/:trigger-id \u00b6 This route can be used to change the frequency of execution of a @cron trigger, or the message of any trigger. Request \u00b6 PATCH /jobs/triggers/123123 HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 0 0 * * 0\" } } } Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 0 0 * * 0\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 } }, \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb PATCH . A konnector can also call this endpoint for one of its triggers (no permission required). POST /jobs/triggers/:trigger-id/launch \u00b6 Launch a trigger manually given its ID and return the created job. Note: this endpoint can be used to create a job for a @client trigger. In that case, the job won\u2019t be executed on the server but by the client. And the client must call PATCH /jobs/:job-id when the job is completed (success or error). Request \u00b6 POST /jobs/triggers/123123/launch HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : {}, \"state\" : \"running\" , \"queued_at\" : \"2016-09-19T12:35:08Z\" , \"started_at\" : \"2016-09-19T12:35:08Z\" , \"error\" : \"\" }, \"links\" : { \"self\" : \"/jobs/123123\" } } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb POST . DELETE /jobs/triggers/:trigger-id \u00b6 Delete a trigger given its ID. Request \u00b6 DELETE /jobs/triggers/123123 HTTP / 1.1 Accept : application/vnd.api+json Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb DELETE . A konnector can also call this endpoint for one of its triggers (no permission required). GET /jobs/triggers \u00b6 Get the list of triggers. This route only accept Worker and Type query parameters and returns the trigger but also in attributes its current_state (the same current_state returned by GET /jobs/triggers/:trigger-id ). Be warned that /data/io.cozy.triggers/_find does not return this current_state attribute and you\u2019ll need to query /jobs/triggers/:trigger-id to have it. Query parameters (with comma-separated values): Type : to filter on the trigger type ( @cron , @in , etc.) Worker : to filter only triggers associated with a specific worker. Request \u00b6 GET /jobs/triggers?Worker=konnector&Type=@cron,@in,@at HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 { \"data\" : [ { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"arguments\" : \"0 40 0 * * *\" , \"current_state\" : { \"last_error\" : \"LOGIN_FAILED\" , \"last_executed_job_id\" : \"abc\" , \"last_execution\" : \"2019-01-07T08:23:22.069902888Z\" , \"last_failed_job_id\" : \"abcd\" , \"last_failure\" : \"2019-01-07T08:23:22.069902888Z\" , \"last_manual_execution\" : \"2019-01-07T08:23:22.069902888Z\" , \"last_manual_job_id\" : \"azer\" , \"status\" : \"errored\" , \"trigger_id\" : \"123123\" }, \"debounce\" : \"\" , \"domain\" : \"xxx.mycozy.cloud\" , \"message\" : { \"konnector\" : \"slug\" , \"account\" : \"XXX\" }, \"options\" : null , \"type\" : \"@cron\" , \"worker\" : \"konnector\" , \"id\" : \"123123\" , \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } ] } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb GET . When used on a specific worker, the permission can be specified on the worker field. POST /jobs/webhooks/:trigger-id \u00b6 This endpoint is used for creating a job (for example executing a konnector or a service). It requires no permission, but a trigger of type @webhook must have been created before using this endpoint. Its body must be a JSON that will be available to the konnector or to the service through the process.env['COZY_PAYLOAD'] variable. It is possible to pass a Manual=true parameter in the query-string if the job is interactive. It will give it an higher priority in the queues. Request \u00b6 POST /jobs/webhooks/f34c74d0-0c91-0139-5af5-543d7eb8149c HTTP / 1.1 Content-Type : application/json { \"account_id\" : \"0672e560\" } Response \u00b6 HTTP/1.1 204 No Content POST /jobs/webhooks/bi \u00b6 This endpoint is used to create jobs for banking konnectors. It requires a payload with the format defined by Budget Insight and an Authorization header with a Bearer token, where a trigger and an account can be found on this instance matching their data. The event type and the URL of the BI API (on the good environment) are also sent in the query string. Request \u00b6 POST /jobs/webhooks/bi?event=CONNECTION_SYNCED&bi_url=https://.../ HTTP / 1.1 Content-Type : application/json Authorization : Bearer token-from-bi Host : cozy.example.com Response \u00b6 HTTP / 1.1 204 No Content DELETE /jobs/purge \u00b6 This endpoint allows to purge old jobs of an instance. Some parameters can be given to this route: duration is the duration of jobs to keep. This is a human-readable string (integer+suffix). For example: \u201c3W\u201d will keep jobs up to 3 weeks \u201c2M\u201d will keep jobs up to 2 months workers is a comma-separated list of workers to apply the purge job. Request \u00b6 DELETE /jobs/purge HTTP / 1.1 Accept : application/json Response \u00b6 { \"deleted\" : 42 } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb DELETE . Worker pool \u00b6 The consuming side of the job queue is handled by a worker pool. On a monolithic cozy-stack, the worker pool has a configurable fixed size of workers. The default value is not yet determined. Each time a worker has finished a job, it check the queue and based on the priority and the queued date of the job, picks a new job to execute. Permissions \u00b6 In order to prevent jobs from leaking informations between applications, we may need to add filtering per applications: for instance one queue per applications. We should also have an explicit check on the permissions of the applications before launching a job scheduled by an application. For more information, refer to our permission document . Multi-stack \u00b6 When some instances are served by several stacks, the scheduling and running of jobs can be distributed on the stacks. The synchronization is done via redis. For scheduling, there is one important key in redis: triggers . It\u2019s a sorted set. The members are the identifiants of the triggers (with the domain name), and the score are the timestamp of the next time the trigger should occur. During the short period of time where a trigger is processed, its key is moved to scheduling (another sorted set). So, even if a stack crash during processing a trigger, this trigger won\u2019t be lost. For @event triggers, we don\u2019t use the same mechanism. Each stack has all the triggers in memory and is responsible to trigger them for the events generated by the HTTP requests of their API. They also publish them on redis: this pub/sub is used for the realtime API.", "title": "/jobs - Jobs"}, {"location": "cozy-stack/jobs/#jobs", "text": "Jobs are designed to represent asynchronous tasks that your cozy can execute. These tasks can be scheduled in advance, recurring or sudden and provide various services. At the time, we do not provide \u201cgeneric\u201d and programmable tasks. This list of available workers is part of the defined API. The job queue can be either local to the cozy-stack when used as a monolithic instance (self-hosted for instance) or distributed via a redis server for distributed infrastructures. This doc introduces two cozy types: io.cozy.jobs for jobs io.cozy.triggers for triggers", "title": "Jobs"}, {"location": "cozy-stack/jobs/#triggers", "text": "Jobs can be queued up via the /jobs/queue/:worker-type API, for a direct execution. But it can also be convenient to schedule jobs on some conditions, and the triggers are the way to do that. Jobs can be launched by different types of triggers: @at to schedule a one-time job executed after at a specific time in the future @in to schedule a one-time job executed after a specific amount of time @hourly to schedule jobs that run once an hour @daily to schedule jobs that run once a day @weekly to schedule jobs that run once a week @monthly to schedule jobs that run once a month @every to schedule periodic jobs executed at a given fix interval @cron to schedule recurring jobs scheduled at specific times @event to launch a job after a change on documents in the cozy @webhook to launch a job when an HTTP request hit a specific URL @client when the client controls when the job are launched. These triggers have specific syntaxes to describe when jobs should be scheduled. See below for more informations.", "title": "Triggers"}, {"location": "cozy-stack/jobs/#at-syntax", "text": "The @at trigger takes a ISO-8601 formatted string indicating a UTC time in the future. The date is of this form: YYYY-MM-DDTHH:mm:ss.sssZ Be aware that the @at trigger is removed from the doctype after it has created the associated job. Examples @at 2018-12-12T15:36:25.507Z", "title": "@at syntax"}, {"location": "cozy-stack/jobs/#in-syntax", "text": "The @in trigger takes the same duration syntax as @every Be aware that the @in trigger is removed from the doctype after it has created the associated job. Examples @in 10m @in 1h30m", "title": "@in syntax"}, {"location": "cozy-stack/jobs/#daily-syntax", "text": "The @daily trigger will create a job once a day. By default, the stack is free to choose the day and hour when to do that, but you can add restrictions: @daily # Once a day, any hour @daily before 5 am # Once a day, between midnight and 5am (UTC) @daily after 10 pm # Once a day, between 10pm and midnight (UTC) @daily between 8 am and 6 pm # Once a day, between 8am and 6pm (UTC)", "title": "@daily syntax"}, {"location": "cozy-stack/jobs/#weekly-syntax", "text": "The @weekly trigger will create a job once a week. By default, the stack is free to choose the day and hour when to do that, but you can add restrictions: @weekly # Once a week, any day, any hour @weekly on monday # Every monday @weekly on mon , wed , fri # Once a week, on a monday, wednesday, or friday @weekly on wed - fri # Once a week, on a wednesday, thursday, or friday @weekly on weekday # Once a week, but not the week-end @weekly on weekend # Every week-end (saturday or sunday) @weekly before 5 am # Once a week, any day, but between midnight and 5am (UTC) @weekly after 10 pm # Once a week, any day, but between 10pm and midnight (UTC) @weekly between 8 am and 6 pm # Once a week, any day, between 8am and 6pm (UTC) @weekly on monday before 9 am # Every monday, between midnight and 9am (UTC)", "title": "@weekly syntax"}, {"location": "cozy-stack/jobs/#monthly-syntax", "text": "The @monthly trigger will create a job once a month. By default, the stack is free to choose the day and hour when to do that, but you can add restrictions: @monthly # Once a month, any day, any hour @monthly on the 1 # Every first day of the month @monthly on the 1 - 5 # Once a month, on the first five days of the month @monthly before 5 am # Once a month, any day, but between midnight and 5am (UTC) @monthly after 10 pm # Once a month, any day, but between 10pm and midnight (UTC) @monthly between 8 am and 6 pm # Once a month, any day, between 8am and 6pm (UTC) @monthly on the 1 before 9 am # Every first day of the month, between midnight and 9am (UTC) Note: the current implementation is to take a random day/hour and run the job each month at this day/hour. So, you should avoid 29-31 if you really want the job to run each month.", "title": "@monthly syntax"}, {"location": "cozy-stack/jobs/#every-syntax", "text": "The @every trigger uses the same syntax as golang\u2019s time.ParseDuration (but only support time units above seconds): A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as \u201c300ms\u201d, \u201c1.5h\u201d or \u201c2h45m\u201d. Valid time units are \u201cs\u201d, \u201cm\u201d, \u201ch\u201d. Examples @every 1.5h # schedules every 1 and a half hours @every 30m10s # schedules every 30 minutes and 10 seconds", "title": "@every syntax"}, {"location": "cozy-stack/jobs/#cron-syntax", "text": "In order to schedule recurring jobs, the @cron trigger has the syntax using six fields: Field name Mandatory? Allowed values Allowed special characters Seconds Yes 0-59 * / , - Minutes Yes 0-59 * / , - Hours Yes 0-23 * / , - Day of month Yes 1-31 * / , - ? Month Yes 1-12 or JAN-DEC * / , - Day of week Yes 0-6 or SUN-SAT * / , - ? Asterisk ( * ) The asterisk indicates that the cron expression will match for all values of the field; e.g., using an asterisk in the 5th field (month) would indicate every month. Slash ( / ) Slashes are used to describe increments of ranges. For example 3-59/15 in the 1st field (minutes) would indicate the 3rd minute of the hour and every 15 minutes thereafter. The form \"*\\/...\" is equivalent to the form \"first-last/...\" , that is, an increment over the largest possible range of the field. The form \"N-/...\" is accepted as meaning \"N-MAX/...\" , that is, starting at N, use the increment until the end of that specific range. It does not wrap around. Comma ( , ) Commas are used to separate items of a list. For example, using \"MON,WED,FRI\" in the 5th field (day of week) would mean Mondays, Wednesdays and Fridays. Hyphen ( - ) Hyphens are used to define ranges. For example, 9-17 would indicate every hour between 9am and 5pm inclusive. Question mark ( ? ) Question mark may be used instead of * for leaving either day-of-month or day-of-week blank. To schedule jobs given an interval: Examples: @cron 0 0 0 1 1 * # Run once a year, midnight, Jan. 1st @cron 0 0 0 1 1 * # Run once a year, midnight, Jan. 1st @cron 0 0 0 1 * * # Run once a month, midnight, first of month @cron 0 0 0 * * 0 # Run once a week, midnight on Sunday @cron 0 0 0 * * * # Run once a day, midnight @cron 0 0 * * * * # Run once an hour, beginning of hour", "title": "@cron syntax"}, {"location": "cozy-stack/jobs/#event-syntax", "text": "The @event syntax allows to trigger a job when something occurs in the stack. It follows the same syntax than permissions scope string: type[:verb][:values][:selector] Unlike for permissions string, the verb should be one of CREATED , DELETED , UPDATED . It is possible to put several verbs, separated by a comma. There is also a special value != . It means that a job will be trigger only if the value for the given selector has changed (ie the value before the update and the value after that are different). The job worker will receive a compound message including original trigger_infos messages and the event which has triggered it. Examples: @event io.cozy.files // anything happens on files @event io.cozy.files:CREATED // a file was created @event io.cozy.files:DELETED:image/jpg:mime // an image was deleted @event io.cozy.bank.operations:CREATED io.cozy.bank.bills:CREATED // a bank operation or a bill @event io.cozy.bank.operations:CREATED,UPDATED // a bank operation created or updated @event io.cozy.bank.operations:UPDATED:!=:category // a change of category for a bank operation", "title": "@event syntax"}, {"location": "cozy-stack/jobs/#webhook-syntax", "text": "It takes no parameter. The URL to hit is not controlled by the request, but is chosen by the server (and is returned as webhook in the links JSON-API response). Example: @webhook", "title": "@webhook syntax"}, {"location": "cozy-stack/jobs/#client-syntax", "text": "It takes no parameter and can only by used for the client worker. The stack won\u2019t create a job unless a client calls the launch endpoint for this trigger. The main goal of this trigger is keep a state, as the aggregation of job results.", "title": "@client syntax"}, {"location": "cozy-stack/jobs/#error-handling", "text": "Jobs can fail to execute their task. We have two ways to parameterize such cases.", "title": "Error Handling"}, {"location": "cozy-stack/jobs/#retry", "text": "A retry count can be optionally specified to ask the worker to re-execute the task if it has failed. Each retry is executed after a configurable delay. The try count is part of the attributes of the job. Also, each occurring error is kept in the errors field containing all the errors that may have happened.", "title": "Retry"}, {"location": "cozy-stack/jobs/#timeout", "text": "A worker may never end. To prevent this, a configurable timeout value is specified with the job. If a job does not end after the specified amount of time, it will be aborted. A timeout is just like another error from the worker and can provoke a retry if specified.", "title": "Timeout"}, {"location": "cozy-stack/jobs/#defaults", "text": "By default, jobs are parameterized with a maximum of 3 tries with 1 minute timeout. These defaults may vary given the workload of the workers.", "title": "Defaults"}, {"location": "cozy-stack/jobs/#jobs-api", "text": "Example and description of the attributes of a io.cozy.jobs : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , // worker type name \"options\" : { \"timeout\" : 60 , // timeout value in seconds \"max_exec_count\" : 3 , // maximum number of time the job should be executed (including retries) }, \"arguments\" : { // the arguments will be given to the worker (if you look in CouchDB, it is called message there) \"mode\" : \"noreply\" , \"template_name\" : \"new_registration\" , \"template_values\" : { \"DevicesLink\" : \"http://me.cozy.localhost/#/connectedDevices\" , } }, \"state\" : \"running\" , // queued, running, done, errored \"queued_at\" : \"2016-09-19T12:35:08Z\" , // time of the queuing \"started_at\" : \"2016-09-19T12:35:08Z\" , // time of first execution \"error\" : \"\" // error message if any } Example and description of a job creation options \u2014 as you can see, the options are replicated in the io.cozy.jobs attributes: { \"timeout\" : 60 , // timeout value in seconds \"max_exec_count\" : 3 , // maximum number of retry }", "title": "Jobs API"}, {"location": "cozy-stack/jobs/#get-jobsjob-id", "text": "Get a job informations given its ID.", "title": "GET /jobs/:job-id"}, {"location": "cozy-stack/jobs/#request", "text": "GET /jobs/123123 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#response", "text": "{ \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"state\" : \"running\" , \"queued_at\" : \"2016-09-19T12:35:08Z\" , \"started_at\" : \"2016-09-19T12:35:08Z\" , \"error\" : \"\" }, \"links\" : { \"self\" : \"/jobs/123123\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#post-jobsqueueworker-type", "text": "Enqueue programmatically a new job. This route requires a specific permission on the worker-type. A global permission on the global io.cozy.jobs doctype is not allowed. Each worker accepts different arguments. For konnectors, the arguments will be given in the process.env['COZY_FIELDS'] variable.", "title": "POST /jobs/queue/:worker-type"}, {"location": "cozy-stack/jobs/#request_1", "text": "POST /jobs/queue/sendmail HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"manual\" : false , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"arguments\" : {} // any json value used as arguments for the job } } }", "title": "Request"}, {"location": "cozy-stack/jobs/#response_1", "text": "{ \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"state\" : \"running\" , \"queued_at\" : \"2016-09-19T12:35:08Z\" , \"started_at\" : \"2016-09-19T12:35:08Z\" , \"error\" : \"\" }, \"links\" : { \"self\" : \"/jobs/123123\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions", "text": "To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb POST . The is required to restrict its permission to specific worker(s), like this (a global permission on the doctype is not allowed): { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to send mails from the user to his/her friends\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/jobs/#post-jobssupport", "text": "Send a mail to the support (email address defined by mail.reply_to in the config file, or overwritten by context with contexts..reply_to ). It requires a permission on io.cozy.support (a permission on io.cozy.jobs:POST:sendmail:worker , or larger, is also accepted to ease the transition from sending manually a mail to the support via the sendmail queue).", "title": "POST /jobs/support"}, {"location": "cozy-stack/jobs/#request_2", "text": "POST /jobs/support HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"arguments\" : { \"subject\" : \"Cozy is so cool!\" , \"body\" : \"I really love Cozy. Thank you so much!\" } } } }", "title": "Request"}, {"location": "cozy-stack/jobs/#response_2", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/jobs/#post-jobscampaign-emails", "text": "Send a non transactional (or campaign) email to the user via the dedicated campaign mail server (configured via campaign_mail attributes in the config file, or overwritten by context with campaign_mail.contexts. attributes). Both the subject and at least one part are required.", "title": "POST /jobs/campaign-emails"}, {"location": "cozy-stack/jobs/#request_3", "text": "POST /jobs/campaign-emails HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"arguments\" : { \"subject\" : \"Checkout the new cool stuff!\" , \"parts\" : [ { \"body\" : \"So many new features to check out!\" , \"type\" : \"text/plain\" } ] } } } }", "title": "Request"}, {"location": "cozy-stack/jobs/#response_3", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_1", "text": "To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb POST and the sendmail worker. This can be defined like so: { \"permissions\" : { \"campaign-emails\" : { \"description\" : \"Required to send campaign emails to the user\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/jobs/#get-jobsqueueworker-type", "text": "List the jobs in the queue.", "title": "GET /jobs/queue/:worker-type"}, {"location": "cozy-stack/jobs/#request_4", "text": "GET /jobs/queue/sendmail HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#response_4", "text": "{ \"data\" : [ { \"attributes\" : { \"domain\" : \"cozy.localhost:8080\" , \"options\" : null , \"queued_at\" : \"2017-09-29T15:32:31.953878568+02:00\" , \"started_at\" : \"0001-01-01T00:00:00Z\" , \"state\" : \"queued\" , \"worker\" : \"log\" }, \"id\" : \"77689bca9634b4fb08d6ca3d1643de5f\" , \"links\" : { \"self\" : \"/jobs/log/77689bca9634b4fb08d6ca3d1643de5f\" }, \"meta\" : { \"rev\" : \"1-f823bcd2759103a5ad1a98f4bf083b36\" }, \"type\" : \"io.cozy.jobs\" } ], \"meta\" : { \"count\" : 0 } }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_2", "text": "To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb GET . In most cases, the application will restrict its permission to only one worker, like this: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to know the number of jobs in the sendmail queues\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"GET\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/jobs/#patch-jobsjob-id", "text": "This endpoint can be used for a job of the client worker (executed by a client, not on the server) to update the status.", "title": "PATCH /jobs/:job-id"}, {"location": "cozy-stack/jobs/#request_5", "text": "PATCH /jobs/022368c07dc701396403543d7eb8149c HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"022368c07dc701396403543d7eb8149c\" , \"attributes\" : { \"state\" : \"errored\" , \"error\" : \"LOGIN_FAILED\" } } }", "title": "Request"}, {"location": "cozy-stack/jobs/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"022368c07dc701396403543d7eb8149c\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : {}, \"state\" : \"errored\" , \"error\" : \"LOGIN_FAILED\" , \"queued_at\" : \"2021-04-12T12:34:56Z\" , \"started_at\" : \"2021-04-12T12:34:56Z\" , \"finished_at\" : \"2021-04-12T12:38:59Z\" }, \"links\" : { \"self\" : \"/jobs/022368c07dc701396403543d7eb8149c\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#post-jobstriggers", "text": "Add a trigger of the worker. See triggers\u2019 descriptions to see the types of trigger and their arguments syntax. This route requires a specific permission on the worker type. A global permission on the global io.cozy.triggers doctype is not allowed. The debounce parameter can be used to limit the number of jobs created in a burst. It delays the creation of the job on the first input by the given time argument, and if the trigger has its condition matched again during this period, it won\u2019t create another job. It can be useful to combine it with the changes feed of couchdb with a last sequence number persisted by the worker, as it allows to have a nice diff between two executions of the worker. Its syntax is the one understood by go\u2019s time.ParseDuration .", "title": "POST /jobs/triggers"}, {"location": "cozy-stack/jobs/#request_6", "text": "POST /jobs/triggers HTTP / 1.1 Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"type\" : \"@event\" , \"arguments\" : \"io.cozy.invitations\" , \"debounce\" : \"10m\" , \"worker\" : \"sendmail\" , \"message\" : {}, \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 } } } } Note : the message field was previously called worker_arguments . The latter version still works but is deprecated, you should use message instead.", "title": "Request"}, {"location": "cozy-stack/jobs/#response_6", "text": "{ \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"attributes\" : { \"type\" : \"@every\" , \"arguments\" : \"30m10s\" , \"debounce\" : \"10m\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 } }, \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_3", "text": "To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb POST . In most cases, the application will restrict its permission to only one worker, like this: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to send regularly mails from the user to his/her friends\" , \"type\" : \"io.cozy.triggers\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/jobs/#get-jobstriggerstrigger-id", "text": "Get a trigger informations given its ID.", "title": "GET /jobs/triggers/:trigger-id"}, {"location": "cozy-stack/jobs/#request_7", "text": "GET /jobs/triggers/123123 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#response_7", "text": "{ \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"attributes\" : { \"type\" : \"@every\" , \"arguments\" : \"30m10s\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 }, \"current_state\" : { \"status\" : \"done\" , \"last_success\" : \"2017-11-20T13:31:09.01641731\" , \"last_successful_job_id\" : \"abcde\" , \"last_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_executed_job_id\" : \"abcde\" , \"last_failure\" : \"2017-11-20T13:31:09.01641731\" , \"last_failed_job_id\" : \"abcde\" , \"last_error\" : \"error value\" , \"last_manual_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_manual_job_id\" : \"abcde\" } }, \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_4", "text": "To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb GET . A konnector can also call this endpoint for one of its triggers (no permission required).", "title": "Permissions"}, {"location": "cozy-stack/jobs/#get-jobstriggerstrigger-idstate", "text": "Get the trigger current state, to give a big picture of the health of the trigger. last executed job status ( done , errored , queued or running ) last executed job that resulted in a successful executoin last executed job that resulted in an error last executed job from a manual execution (not executed by the trigger directly)", "title": "GET /jobs/triggers/:trigger-id/state"}, {"location": "cozy-stack/jobs/#request_8", "text": "GET /jobs/triggers/123123/state HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#response_8", "text": "{ \"data\" : { \"type\" : \"io.cozy.triggers.state\" , \"id\" : \"123123\" , \"attributes\" : { \"status\" : \"done\" , \"last_success\" : \"2017-11-20T13:31:09.01641731\" , \"last_successful_job_id\" : \"abcde\" , \"last_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_executed_job_id\" : \"abcde\" , \"last_failure\" : \"2017-11-20T13:31:09.01641731\" , \"last_failed_job_id\" : \"abcde\" , \"last_error\" : \"error value\" , \"last_manual_execution\" : \"2017-11-20T13:31:09.01641731\" , \"last_manual_job_id\" : \"abcde\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_5", "text": "To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb GET . A konnector can also call this endpoint for one of its triggers (no permission required).", "title": "Permissions"}, {"location": "cozy-stack/jobs/#get-jobstriggerstrigger-idjobs", "text": "Get the jobs launched by the trigger with the specified ID. Query parameters: Limit : to specify the number of jobs to get out", "title": "GET /jobs/triggers/:trigger-id/jobs"}, {"location": "cozy-stack/jobs/#request_9", "text": "GET /jobs/triggers/123123/jobs?Limit=1 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#response_9", "text": "{ \"data\" : [ { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : {}, \"links\" : { \"self\" : \"/jobs/123123\" } } ] }", "title": "Response"}, {"location": "cozy-stack/jobs/#patch-jobstriggerstrigger-id", "text": "This route can be used to change the frequency of execution of a @cron trigger, or the message of any trigger.", "title": "PATCH /jobs/triggers/:trigger-id"}, {"location": "cozy-stack/jobs/#request_10", "text": "PATCH /jobs/triggers/123123 HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 0 0 * * 0\" } } }", "title": "Request"}, {"location": "cozy-stack/jobs/#response_10", "text": "{ \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 0 0 * * 0\" , \"worker\" : \"sendmail\" , \"options\" : { \"timeout\" : 60 , \"max_exec_count\" : 3 } }, \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_6", "text": "To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb PATCH . A konnector can also call this endpoint for one of its triggers (no permission required).", "title": "Permissions"}, {"location": "cozy-stack/jobs/#post-jobstriggerstrigger-idlaunch", "text": "Launch a trigger manually given its ID and return the created job. Note: this endpoint can be used to create a job for a @client trigger. In that case, the job won\u2019t be executed on the server but by the client. And the client must call PATCH /jobs/:job-id when the job is completed (success or error).", "title": "POST /jobs/triggers/:trigger-id/launch"}, {"location": "cozy-stack/jobs/#request_11", "text": "POST /jobs/triggers/123123/launch HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#response_11", "text": "{ \"data\" : { \"type\" : \"io.cozy.jobs\" , \"id\" : \"123123\" , \"attributes\" : { \"domain\" : \"me.cozy.localhost\" , \"worker\" : \"sendmail\" , \"options\" : {}, \"state\" : \"running\" , \"queued_at\" : \"2016-09-19T12:35:08Z\" , \"started_at\" : \"2016-09-19T12:35:08Z\" , \"error\" : \"\" }, \"links\" : { \"self\" : \"/jobs/123123\" } } }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_7", "text": "To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb POST .", "title": "Permissions"}, {"location": "cozy-stack/jobs/#delete-jobstriggerstrigger-id", "text": "Delete a trigger given its ID.", "title": "DELETE /jobs/triggers/:trigger-id"}, {"location": "cozy-stack/jobs/#request_12", "text": "DELETE /jobs/triggers/123123 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#permissions_8", "text": "To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb DELETE . A konnector can also call this endpoint for one of its triggers (no permission required).", "title": "Permissions"}, {"location": "cozy-stack/jobs/#get-jobstriggers", "text": "Get the list of triggers. This route only accept Worker and Type query parameters and returns the trigger but also in attributes its current_state (the same current_state returned by GET /jobs/triggers/:trigger-id ). Be warned that /data/io.cozy.triggers/_find does not return this current_state attribute and you\u2019ll need to query /jobs/triggers/:trigger-id to have it. Query parameters (with comma-separated values): Type : to filter on the trigger type ( @cron , @in , etc.) Worker : to filter only triggers associated with a specific worker.", "title": "GET /jobs/triggers"}, {"location": "cozy-stack/jobs/#request_13", "text": "GET /jobs/triggers?Worker=konnector&Type=@cron,@in,@at HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/jobs/#response_12", "text": "{ \"data\" : [ { \"type\" : \"io.cozy.triggers\" , \"id\" : \"123123\" , \"arguments\" : \"0 40 0 * * *\" , \"current_state\" : { \"last_error\" : \"LOGIN_FAILED\" , \"last_executed_job_id\" : \"abc\" , \"last_execution\" : \"2019-01-07T08:23:22.069902888Z\" , \"last_failed_job_id\" : \"abcd\" , \"last_failure\" : \"2019-01-07T08:23:22.069902888Z\" , \"last_manual_execution\" : \"2019-01-07T08:23:22.069902888Z\" , \"last_manual_job_id\" : \"azer\" , \"status\" : \"errored\" , \"trigger_id\" : \"123123\" }, \"debounce\" : \"\" , \"domain\" : \"xxx.mycozy.cloud\" , \"message\" : { \"konnector\" : \"slug\" , \"account\" : \"XXX\" }, \"options\" : null , \"type\" : \"@cron\" , \"worker\" : \"konnector\" , \"id\" : \"123123\" , \"links\" : { \"self\" : \"/jobs/triggers/123123\" } } ] }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_9", "text": "To use this endpoint, an application needs a permission on the type io.cozy.triggers for the verb GET . When used on a specific worker, the permission can be specified on the worker field.", "title": "Permissions"}, {"location": "cozy-stack/jobs/#post-jobswebhookstrigger-id", "text": "This endpoint is used for creating a job (for example executing a konnector or a service). It requires no permission, but a trigger of type @webhook must have been created before using this endpoint. Its body must be a JSON that will be available to the konnector or to the service through the process.env['COZY_PAYLOAD'] variable. It is possible to pass a Manual=true parameter in the query-string if the job is interactive. It will give it an higher priority in the queues.", "title": "POST /jobs/webhooks/:trigger-id"}, {"location": "cozy-stack/jobs/#request_14", "text": "POST /jobs/webhooks/f34c74d0-0c91-0139-5af5-543d7eb8149c HTTP / 1.1 Content-Type : application/json { \"account_id\" : \"0672e560\" }", "title": "Request"}, {"location": "cozy-stack/jobs/#response_13", "text": "HTTP/1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/jobs/#post-jobswebhooksbi", "text": "This endpoint is used to create jobs for banking konnectors. It requires a payload with the format defined by Budget Insight and an Authorization header with a Bearer token, where a trigger and an account can be found on this instance matching their data. The event type and the URL of the BI API (on the good environment) are also sent in the query string.", "title": "POST /jobs/webhooks/bi"}, {"location": "cozy-stack/jobs/#request_15", "text": "POST /jobs/webhooks/bi?event=CONNECTION_SYNCED&bi_url=https://.../ HTTP / 1.1 Content-Type : application/json Authorization : Bearer token-from-bi Host : cozy.example.com", "title": "Request"}, {"location": "cozy-stack/jobs/#response_14", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/jobs/#delete-jobspurge", "text": "This endpoint allows to purge old jobs of an instance. Some parameters can be given to this route: duration is the duration of jobs to keep. This is a human-readable string (integer+suffix). For example: \u201c3W\u201d will keep jobs up to 3 weeks \u201c2M\u201d will keep jobs up to 2 months workers is a comma-separated list of workers to apply the purge job.", "title": "DELETE /jobs/purge"}, {"location": "cozy-stack/jobs/#request_16", "text": "DELETE /jobs/purge HTTP / 1.1 Accept : application/json", "title": "Request"}, {"location": "cozy-stack/jobs/#response_15", "text": "{ \"deleted\" : 42 }", "title": "Response"}, {"location": "cozy-stack/jobs/#permissions_10", "text": "To use this endpoint, an application needs a permission on the type io.cozy.jobs for the verb DELETE .", "title": "Permissions"}, {"location": "cozy-stack/jobs/#worker-pool", "text": "The consuming side of the job queue is handled by a worker pool. On a monolithic cozy-stack, the worker pool has a configurable fixed size of workers. The default value is not yet determined. Each time a worker has finished a job, it check the queue and based on the priority and the queued date of the job, picks a new job to execute.", "title": "Worker pool"}, {"location": "cozy-stack/jobs/#permissions_11", "text": "In order to prevent jobs from leaking informations between applications, we may need to add filtering per applications: for instance one queue per applications. We should also have an explicit check on the permissions of the applications before launching a job scheduled by an application. For more information, refer to our permission document .", "title": "Permissions"}, {"location": "cozy-stack/jobs/#multi-stack", "text": "When some instances are served by several stacks, the scheduling and running of jobs can be distributed on the stacks. The synchronization is done via redis. For scheduling, there is one important key in redis: triggers . It\u2019s a sorted set. The members are the identifiants of the triggers (with the domain name), and the score are the timestamp of the next time the trigger should occur. During the short period of time where a trigger is processed, its key is moved to scheduling (another sorted set). So, even if a stack crash during processing a trigger, this trigger won\u2019t be lost. For @event triggers, we don\u2019t use the same mechanism. Each stack has all the triggers in memory and is responsible to trigger them for the events generated by the HTTP requests of their API. They also publish them on redis: this pub/sub is used for the realtime API.", "title": "Multi-stack"}, {"location": "cozy-stack/konnectors-dev/", "text": "Table of contents running a konnector locally \u00b6 Locally but linked to a Cozy \u00b6 This method requires a working cozy-stack. It will allow you to run the konnector outside the cozy-stack but saves the data inside the cozy-stack. This can be useful when your konnector is not available in one of the registries but you still want to save you data in your real Cozy. You can find a detailed explanation inside the linking your konnector to a cozy page. Installed from a local directory \u00b6 This method requires a working cozy-stack with the admin permissions and the cozy-stack CLI. It will allow you to install your konnector exactly like it was published in a registry. This can be a good way to check locally if everything works well before publishing to the registry. Installing the konnector \u00b6 First build it: yarn build Start your cozy-stack server with the --dev flag. If you have the cozy-stack source code locally you can run this following command for example: go run . serve --dev --config ~/.config/cozy/config.yaml --mailhog --fs-url=file://localhost ${ PWD } /storage --konnectors-cmd ${ PWD } /scripts/konnector-dev-run.sh You will need to have a valid configuration file . Then you just have to run: cozy-stack konnectors install files:///build Be careful to point the /build folder inside your konnector folder! Run the konnector \u00b6 Once connected to your Cozy instance (probably http://cozy.localhost:8080 ) you should have a new icon with your konnector name. Once you click on it, you will be asked the informations required to run the konnector. Once saved, the konnector will start running. After modifying the konnector, clicking on the Synchronize button will fetch the new code an run it with the changes.", "title": "Running a konnector locally"}, {"location": "cozy-stack/konnectors-dev/#running-a-konnector-locally", "text": "", "title": "running a konnector locally"}, {"location": "cozy-stack/konnectors-dev/#locally-but-linked-to-a-cozy", "text": "This method requires a working cozy-stack. It will allow you to run the konnector outside the cozy-stack but saves the data inside the cozy-stack. This can be useful when your konnector is not available in one of the registries but you still want to save you data in your real Cozy. You can find a detailed explanation inside the linking your konnector to a cozy page.", "title": "Locally but linked to a Cozy"}, {"location": "cozy-stack/konnectors-dev/#installed-from-a-local-directory", "text": "This method requires a working cozy-stack with the admin permissions and the cozy-stack CLI. It will allow you to install your konnector exactly like it was published in a registry. This can be a good way to check locally if everything works well before publishing to the registry.", "title": "Installed from a local directory"}, {"location": "cozy-stack/konnectors-dev/#installing-the-konnector", "text": "First build it: yarn build Start your cozy-stack server with the --dev flag. If you have the cozy-stack source code locally you can run this following command for example: go run . serve --dev --config ~/.config/cozy/config.yaml --mailhog --fs-url=file://localhost ${ PWD } /storage --konnectors-cmd ${ PWD } /scripts/konnector-dev-run.sh You will need to have a valid configuration file . Then you just have to run: cozy-stack konnectors install files:///build Be careful to point the /build folder inside your konnector folder!", "title": "Installing the konnector"}, {"location": "cozy-stack/konnectors-dev/#run-the-konnector", "text": "Once connected to your Cozy instance (probably http://cozy.localhost:8080 ) you should have a new icon with your konnector name. Once you click on it, you will be asked the informations required to run the konnector. Once saved, the konnector will start running. After modifying the konnector, clicking on the Synchronize button will fetch the new code an run it with the changes.", "title": "Run the konnector"}, {"location": "cozy-stack/konnectors-workflow/", "text": "Table of contents Konnectors workflow \u00b6 TL;DR \u00b6 Types \u00b6 Accounts \u00b6 io.cozy.accounts contains information for an account, including those for authentication (technically, they are encrypted by cozy-stack before being saved in CouchDB, but we will show them as the konnectors will see them): { \"auth\" : { \"login\" : \"000000000\" , \"password\" : \"**********\" }, \"folderPath\" : \"/Administratif/Free Mobile\" , \"label\" : \"freemobile\" , \"namePath\" : \"Free Mobile\" } Accounts are manipulated through the /data/ API. Decryption \u00b6 The decryption of the credentials is reserved to requests coming from konnectors and services. For services, it is only available on /data/io.cozy.acconts/:account-id with an additional include=credentials parameter. Aggregator accounts \u00b6 Some konnectors are based on an aggregator service. An aggregator is declared in the konnector manifest and specify an accountId property. When Cozy-Home detects this property, it checks if an account with this given id exists. If not, it creates it. Every account created for a konnector based on an aggregator is then related to this aggregator account. This relationship is called parent account. { \"auth\" : { \"login\" : \"000000000\" , \"password\" : \"**********\" }, \"folderPath\" : \"/Administratif/Bankbank\" , \"label\" : \"Bankbank\" , \"namePath\" : \"Bankbank\" , \"relationships\" : { \"parent\" : { \"data\" : { \"_id\" : \"service-aggregator-account\" , \"_type\" : \"io.cozy.accounts\" } } } } Note: you can read more about the accounts doctype here . Konnectors \u00b6 io.cozy.konnectors are installed similarly to io.cozy.apps (see doc ) Permissions \u00b6 Like client-side applications, each konnector has an associated io.cozy.permissions . These permissions are those listed on the manifest of the konnectors, and the stack will add a permission for the files on the folder choosen by the user. Triggers \u00b6 io.cozy.triggers are used to define when konnectors are launched. See https://docs.cozy.io/en/cozy-stack/jobs/#post-jobstriggers Complete flow example \u00b6 As a user, from the expenses management app, I have a clean flow to configure a connector to retrieve my travel expenses 1 - User is in my-expenses and clicks on [configure travels] 2 - my-expenses triggers an intent cozy . intents . start ( \"CREATE\" , \"io.cozy.konnectors\" , { category : \"transport\" }); 3 - the Store app catch the intent, fetch all available konnectors and let the user choose GET /registry?... HTTP / 1.1 4 - the user chooses the trainline konnector. Its manifest looks like this: { \"name\" : \"Trainline\" , \"type\" : \"konnector\" , \"slug\" : \"konnector-trainline\" , \"description\" : \"Konnector for trainline . com\" , \"source\" : \"https://github.com/konnectors/trainlines.git@build\" , \"developer\" : { \"name\" : \"XXX\" , \"url\" : \"https://www.xxx.fr\" }, \"version\" : \"3.0.0\" , \"licence\" : \"AGPL-3.0\" , \"fields\" : { \"login\" : { \"type\" : \"text\" }, \"password\" : { \"type\" : \"password\" }, \"advancedFields\" : { \"folderPath\" : { \"advanced\" : true , \"isRequired\" : false } } }, \"category\" : \"transport\" , \"frequency\" : \"weekly\" , \"permissions\" : { \"events\" : { \"description\" : \"Connect train bill with event in your calendar\" , \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"PATCH\" ] } } } 5 - the user clicks on install, and the install starts: POST /konnectors/trainline HTTP / 1.1 6 - the Store then uses an intent to know which app can configure this konnector: cozy . intents . start ( \"REDIRECT\" , \"io.cozy.accounts\" , { slug : \"trainline\" }); 7 - the Store redirects to the Home. The Home asks the user for account config and create a folder to save the PDFs. 8 - the Home also add a Reference from the konnector to the folder to prevent any accidental folder deletion: POST /files/123-selected-folder-id-123/relationships/referenced_by { \"data\" : [ { \"type\" : \"io.cozy.konnectors\" , \"id\" : \"io.cozy.konnectors/trainlines\" } ] } 9 - then the Home can create the account: POST /data/io.cozy.accounts HTTP / 1.1 { \"account_type\" : \"trainline\" , \"auth\" : { \"login\" : \"xxxx\" , \"password\" : \"yyyyy\" }, \"folderPath\" : \"/Administrative/Trainline\" } HTTP / 1.1 200 OK { \"_id\" : \"123-account-id-123\" , \"_rev\" : \"1-asasasasa\" , \"account_type\" : \"trainline\" , \"auth\" : { \"login\" : \"xxxx\" }, \"folderPath\" : \"/Administrative/Trainline\" } 10 - the Home create the trigger: POST /jobs/io.cozy.triggers { \"data\" : { \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 0 0 0 1 1 \" , \"worker\" : \"konnector\" , \"message\" : { \"konnector\" : \"trainline\" , \"account\" : \"5165621628784562148955\" , \"folder_to_save\" : \"877854878455\" } } } } 11 - and, finally, the Home runs the konnector for the first time: POST /jobs/triggers/abc159753/launch HTTP / 1.1 12 - the Home uses the realtime to be informed if the konnector fails to login or succeeds to import the PDFs. If the user wants to use several account, the Home can setup several triggers for the same konnector & various accounts. Konnector Worker specs \u00b6 Prepare the execution \u00b6 The cozy-stack prepares the execution of the konnector by doing these steps: it checks that the konnector is not in maintenance in the registry (except for manual execution) it ensures that the konnector has a folder where it can write its files, and has the permission to write in this folder. Execute the konnector \u00b6 Start the konnector through nsjail, passing as ENV variables: - `COZY_URL`: the starting instance URL - `COZY_CREDENTIALS`: security token to communicate with Cozy - `COZY_FIELDS`: JSON-encoded message with the arguments from the trigger - `COZY_PAYLOAD`: JSON-encoded payload from the HTTP request (@webhook trigger) - `COZY_PARAMETERS`: JSON-encoded parameters from the konnector manifest - `COZY_LANGUAGE`: the language field of the konnector (eg. \"node\" etc.) - `COZY_LOCALE`: the locale of the user (eg. \"en\" etc.) - `COZY_TIME_LIMIT`: how much time the konnector can run before being killed - `COZY_JOB_ID`: id of the job - `COZY_TRIGGER_ID`: id of the trigger that has created the job - `COZY_JOB_MANUAL_EXECUTION`: whether the job was started manually (in Home) or automatically (via a cron trigger or event) The konnector process can send events trough its stdout (newline separated JSON object), the konnector worker pass these events to the realtime hub as io.cozy.jobs.events . Only JSON formatted events are forwarded to the client-side through realtime Otherwise formatted lines (such as node Error) will be kept in some system logs. Konnectors should NOT log the received account login values in production. Konnector error handling \u00b6 The konnector can output json formated messages as stated before (the events) and those events will be typed and formatted like this: { type : \"messagetype\" , // can be \"debug\", \"info\", \"warning\", \"error\", and \"critical\" message : \"message\" // can be any string } If there is an error or critical message, the execution will be seen as a failure by cozy-stack. It\u2019s also the case if the konnector reaches the timeout or returns with a non-zero status code. Note: debug and info level are not transmitted to syslog, except if the instance is in debug mode. It would be too verbose to do otherwise. The message can start with a known keyword that could have special meanings for cozy-stack or for statistical analysis of konnector health. Known keywords are listed in the konnector tutorial When a connector throw an error of either LOGIN_FAILED or any error starting with USER_ACTION_NEEDED (with the exception of USER_ACTION_NEEDED.CGU_FORM ), meaning that the user needs to execute an action on provider\u2019s website (either changing its credentials or acknowledging something on provider website), then cozy-stack will skip all subsequent automatic executions to avoid querying the provider site and blocking user account. Manual execution by the user will still be possible to unlock the konnector/account when the user thinks it is now ready to be run again. Account deleted \u00b6 When an account is deleted, or a konnector is going to be uninstalled, the konnector is executed with the account_deleted field to true, so it can clean the account remotely. OAuth (and service secrets) \u00b6 Doctypes \u00b6 io.cozy.konnectors gives their desiderata for an account { \"fields\" : { \"account\" : { \"doctype\" : \"io.cozy.accounts\" , \"account_type\" : \"maif\" , \"scope\" : \"openid profile offline_access\" } } } io.cozy.accounts contains authentication information for an account, as well as the associated scope { \"name\" : \"Mon Compte Maif\" , \"account_type\" : \"maif\" , \"status\" : \"connected\" , \"oauth\" : { \"access_token\" : \"akosaksoakso\" , \"refresh_token\" : \"okoakozkaozk\" , \"scope\" : \"openid profile offline_access\" } } io.cozy.account_types contains the oauth configuration: { \"_id\" : \"service.example\" , \"grant_mode\" : \"authorization_code\" , \"client_id\" : \"the registered client id\" , \"client_secret\" : \"client_secret is necessary for server-flow\" , \"auth_endpoint\" : \"https://service.example/auth\" , \"token_endpoint\" : \"https://api.service.example/token\" } io.cozy.account_types are not accessible to the applications: they are injected directly in CouchDB in a global database secrets/io-cozy-account_types . Secrets that are not OAuth \u00b6 The io.cozy.account_types doctype can also be used for storing secrets that are not related to OAuth. The document still need to be injected manually in secrets/io-cozy-account_types : { \"_id\": \"service.example\", \"grant_mode\": \"secret\", \"slug\": \"service\", \"secret\": \"th1$_1$_th3_s3cr3t!\" } Note : grant_mode must be secret (or bi_webauth+secret , or bi_webview+secret , or authorization_code+secret ), slug must be the slug of the konnector, but secret can be a map instead of a simple string if several secrets are needed for this service. The secret is given to the konnector in the COZY_PARAMETERS env variable. Overloading an account type for a given context \u00b6 It is possible to use a different account type for a given context, by creating a new document with an id prefix by the context name and / . For example, a different secret can be used in the foobar context by injecting this document in secrets/io-cozy-account_types : { \"_id\": \"foobar/service.example\", \"grant_mode\": \"secret\", \"slug\": \"service\", \"secret\": \"th1$_1$_n0t_th3_s4m3_s3cr3t!\" } Reminder OAuth flow \u00b6 Service is the website from which konnector aims to retrieve informations. Stack is the cozy stack. OAuth is divided in 3 steps: Client Registration: the client application (the Stack) needs to be registered with the Service Obtaining & Refreshing Authorization: all the steps from client_id to access_token , the Stack will handle those Using the access_token : ideally, the konnector should only concern itself with this part; it receives an access_token and uses it. Client Registration \u00b6 Before beginning the Grant process, most Services require the application to be registered with a defined redirect_uri . There are a lot of options, which we will choose from when actually implementing konnectors using them. Manually \u00b6 Most services requires a human developer to create the client manually and define its redirect_uri. However each instance has its own domain, so for these services, we will need to: A. Register a \u201cproxy\u201d client , which is a static page performing redirections as needed, as was done for Facebook events in v2 konnectors. We will register a well known cozy domain, like oauth-proxy.cozy.io and registers it with all providers. The use and risks associated with this domain should be made clear to the user. B. Register each Stack with a redirect_uri on the main stack domain, if we go this way, the register_uri below moves from bob.cozy.rocks/accounts/service/redirect to oauthcallback.cozy.rocks/accounts/service/redirect and the domain will be prepended to the state. This is feasible at cozy scale, but requires more knowledge and work for self-hosters. Example: Google \u00b6 For example, these are the steps for creating the google account_type for the stack at .mycozy.cloud: Go to https://console.developers.google.com Select or Create Project (up left near the logo) Enable desired APIs (TBD with usages) Click \u201cCredentials\u201d Create credentials > Oauth Client ID > Web application Set redirectURI to https://oauthcallback.mycozy.cloud/accounts/google/redirect Copy and paste provided Client ID and Client Secret. Then save the data in the console http PUT localhost:5984/secrets%2Fio-cozy-account_types/google grant_mode=authorization_code redirect_uri=\"https://oauthcallback.mycozy.cloud/accounts/google/redirect\" token_mode=basic token_endpoint=\"https://www.googleapis.com/oauth2/v4/token\" auth_endpoint=\"https://accounts.google.com/o/oauth2/v2/auth\" client_id=$CLIENT_ID client_secret=$CLIENT_SECRET Dynamic Registration Protocol \u00b6 A few services allows client to register programatically through the Dynamic Client Registration Protocol RFC7591 , we should allow the Stack to register using this protocol when we first need to implement a Konnector connecting to such a Service. No redirect_url enforcement \u00b6 A few services allows to specify arbitrary redirect_url without registering beforehand as a client. Authorization Grant flows \u00b6 webserver flow (Authorization Code Grant) \u00b6 A. In the cozy app (Home) give a link < a href = \"https://bob.cozy.rocks/accounts/service-name/start? scope=photos& state=1234zyx\" > Notes: the scope may depends on other fields being configured (checkboxes), this will be described in json in the konnectors manifest. The format will be determined upon implementation; to limit bandwidth and risk of state corruption, the cozy app should save its state under a random key into localStorage, the key is then passed as the state in this query; a third parameter, slug , can be added to redirect to this app instead of the home. B. Service lets the user login, allows or denies the scope, then redirects to https://oauthcallback.cozy.rocks/accounts/service-name/redirect? code=AUTH_CODE_HERE& state=1234zyx C. The Stack does Server side this request: POST /oauth/access_token HTTP / 1.1 Host : api.service.example Content-Type : application/x-www-form-urlencoded grant_type=authorization_code& code=AUTH_CODE_HERE& redirect_uri=https://oauthcallback.cozy.rocks/accounts/service-name/redirect& client_id=CLIENT_ID& client_secret=CLIENT_SECRET Note: the stack will also send the state parameter on this request. It is not mandatory per the OAuth 2.0 spec, and the skip_state_on_token option can be used to cancel this behavior if the provider throw an error if this parameter is present. D. The Service responds (server side) with: { \"access_token\" : \"ACCESS_TOKEN\" , \"token_type\" : \"bearer\" , \"expires_in\" : 2592000 , \"refresh_token\" : \"REFRESH_TOKEN\" , \"scope\" : \"read\" , \"uid\" : 100101 , \"info\" : { \"name\" : \"Claude Douillet\" , \"email\" : \"claude.douillet@example.com\" } } This whole object is saved as-is into a io.cozy.accounts \u2018s extras field. The known fields access_token , refresh_token & scope will be also saved on the account\u2019s oauth itself E. The Stack redirect the user to the cozy app: HTTP / 1.1 302 Found Location : https://bob-home.cozy.rocks/?state=1234zyx&account=accountID The Cozy app checks that the state is expected, and restores its state to the form but whith account completed. SPA flow (Implicit grant) \u00b6 A. The cozy app gives a link: < a href = \"https://service.example/auth? (url) response_type=token& client_id=CLIENT_ID& redirect_uri=https://bob-home.cozy.rocks/& scope=photos& state=1234zyx\" > See server-flow for state rules. B. Service lets the user login, allows or denies the scope, then redirects to https://bob-home.cozy.rocks/?access_token=ACCESS_TOKEN&state=1234zyx C. The Cozy app adds the token to the io.cozy.accounts and save it before starting konnector. Accessing data \u00b6 Once we have an account, the Cozy app starts the konnector with the proper account id. The konnector can then fetch the account and use its access_token to performs a request to fetch data: POST /resource HTTP / 1.1 Host : api.service.example Authorization : Bearer ACCESS_TOKEN Refreshing token \u00b6 When using the server-flow, we also get a refresh_token. It is used to get a new access_token when it expires. However, if konnectors are responsible for refreshing token there is a race condition risk: (konnector A) GET https://api.service.com/resource TOKEN1 -> expired (konnector B) GET https://api.service.com/resource TOKEN1 -> expired (konnector A) POST https://api.service.com/token REFRESH_TOKEN -> TOKEN2a (konnector B) POST https://api.service.com/token REFRESH_TOKEN -> TOKEN2b (konnector A) GET https://api.service.com/token TOKEN2a -> invalid To avoid this, the stack will be responsible to perform token refresh. A konnector can requires the stack to refresh an account token with an HTTP request. POST /accounts/:accountType/:accountID/refresh HTTP / 1.1 Host : bob.cozy.rocks Konnectors Marketplace Requirements \u00b6 The following is a few points to be careful for in konnectors when we start allowing non-cozy developped OAuth konnectors. With SPA flow, because of advanced security concerns (confused deputy problem), cozy should validate the access_token . However, the way to do that depends on the provider and cannot be described in json, it is therefore the responsibility of the konnector itself. Account types security rules \u00b6 With server flow, an evil account type with proper auth_endpoint but bad token_endpoint could retrieve a valid token as well as cozy client secret. The reviewer of an account_type should make sure both these endpoints are on domains belonging to the Service provider. Notes for MesInfos experiment \u00b6 MAIF konnector uses the webserver flow without redirect_uri validation Orange konnector uses the client-side proxy but hosted on their own servers (/!\\ redirect_uri vs redirect_url) Webauth \u00b6 For some banks integration (Paypal, Orange Bank, Revolut\u2026), Budget Insight has a workflow similar to OAuth called Webauth . It is possible to use this workflow for konnectors by registering an account type with the following parameter: grant_mode , with bi_webauth as the value (or bi_webauth+secret if there is also a secret) redirect_uri , with an URL like https://oauthcallback.mycozy.cloud/accounts/paypal/redirect client_id , with the client ID given by Budget Insight auth_endpoint , with https://{domain}.biapi.pro/2.0/webauth (with the correct domain ) reconnect_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/reconnect (idem). BI Weview \u00b6 A new integration of Budget Insight is available for all the proposed banks. This is a workflow similar to OAuth called webview It is possible to use this workflow for konnectors by registering an account type with the following parameter: grant_mode , with bi_webview+secret as the value redirect_uri , with an URL like https://oauthcallback.mycozy.cloud/accounts/paypal/redirect client_id , with the client ID given by Budget Insight auth_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/fr/connect (with the correct domain ) manage_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/reconnect (idem). reconnect_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/reconnect (idem). Manage \u00b6 The manage webview can be called with this route: GET /accounts/:accountType/:accountID/manage?code={code}&connection_id={id}&slug={slug}&state={state} HTTP / 1.1 Host : jane.cozy.example HTTP / 1.1 303 See Other Location : https://domain.biapi.pro/2.0/auth/webview/manage ?client_id={client_id} &code={code} &connection_id={id} &redirect_uri=https://oauthcallback.cozy.example/accounts/{accountType}/redirect &state={stackState} At the end of flow, the user will be redirected to https://jane-{slug}.cozy.example/?state={state} . Reconnect \u00b6 The reconnection webview can be called with this route: GET /accounts/:accountType/:accountID/reconnect?code={code}&connection_id={id}&slug={slug}&state={state} HTTP / 1.1 Host : jane.cozy.example HTTP / 1.1 303 See Other Location : https://domain.biapi.pro/2.0/auth/webview/reconnect ?client_id={client_id} &code={code} &connection_id={id} &redirect_uri=https://oauthcallback.cozy.example/accounts/{accountType}/redirect &state={stackState} At the end of flow, the user will be redirected to https://jane-{slug}.cozy.example/?state={state} . Webhook triggers \u00b6 The cloudery (or an application) can install the konnector and create an account It can also create the webhook trigger via a POST /jobs/triggers Request: POST /jobs/triggers HTTP / 1.1 Host : jane.cozy.example Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"type\" : \"@webhook\" , \"worker\" : \"konnector\" , \"message\" : { \"param_from_trigger\" : \"foo\" } } } } Response: HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"0915b6b0-0c97-0139-5af7-543d7eb8149c\" , \"attributes\" : { \"type\" : \"@webhook\" , \"worker\" : \"konnector\" , \"message\" : { \"konnector\" : \"mykonnector\" , \"param_from_trigger\" : \"foo\" } }, \"links\" : { \"self\" : \"/jobs/triggers/0915b6b0-0c97-0139-5af7-543d7eb8149c\" , \"webhook\" : \"https://jane.cozy.example/jobs/webhooks/0915b6b0-0c97-0139-5af7-543d7eb8149c\" } } } The cloudery can then give the webhook URL to the external service When the external service has new documents to import, it can call the webhook Request: POST /jobs/webhooks/0915b6b0-0c97-0139-5af7-543d7eb8149c HTTP / 1.1 Host : jane.cozy.example Content-Type : application/json { \"param_from_http_body\" : \"bar\" } Response: HTTP / 1.1 204 No Content The stack will put a job in its queue for the konnector The stack executes the konnector with: COZY_FIELDS={\"param_from_trigger\": \"foo\"} COZY_PAYLOAD={\"param_from_http_body\": \"bar\"} etc. Note: the environnement variables have a limit for their size defined by the linux kernel. If the payload is too big to fit inside the env variable, the stack will put the payload in a temporary file, and will set the COZY_PAYLOAD variable to @ + the filename of this file, like: COZY_PAYLOAD=@cozy_payload.json The konnector will fetch the documents from the external service and save them in the Cozy. Note: if the trigger has a debounce, the COZY_PAYLOAD will be an object with a payloads array, like this: COZY_PAYLOAD ={ \"payloads\" : [{ \"param_from_http_body\" : \"bar\" }]}", "title": "Workflow of the konnectors"}, {"location": "cozy-stack/konnectors-workflow/#konnectors-workflow", "text": "", "title": "Konnectors workflow"}, {"location": "cozy-stack/konnectors-workflow/#tldr", "text": "", "title": "TL;DR"}, {"location": "cozy-stack/konnectors-workflow/#types", "text": "", "title": "Types"}, {"location": "cozy-stack/konnectors-workflow/#accounts", "text": "io.cozy.accounts contains information for an account, including those for authentication (technically, they are encrypted by cozy-stack before being saved in CouchDB, but we will show them as the konnectors will see them): { \"auth\" : { \"login\" : \"000000000\" , \"password\" : \"**********\" }, \"folderPath\" : \"/Administratif/Free Mobile\" , \"label\" : \"freemobile\" , \"namePath\" : \"Free Mobile\" } Accounts are manipulated through the /data/ API.", "title": "Accounts"}, {"location": "cozy-stack/konnectors-workflow/#decryption", "text": "The decryption of the credentials is reserved to requests coming from konnectors and services. For services, it is only available on /data/io.cozy.acconts/:account-id with an additional include=credentials parameter.", "title": "Decryption"}, {"location": "cozy-stack/konnectors-workflow/#aggregator-accounts", "text": "Some konnectors are based on an aggregator service. An aggregator is declared in the konnector manifest and specify an accountId property. When Cozy-Home detects this property, it checks if an account with this given id exists. If not, it creates it. Every account created for a konnector based on an aggregator is then related to this aggregator account. This relationship is called parent account. { \"auth\" : { \"login\" : \"000000000\" , \"password\" : \"**********\" }, \"folderPath\" : \"/Administratif/Bankbank\" , \"label\" : \"Bankbank\" , \"namePath\" : \"Bankbank\" , \"relationships\" : { \"parent\" : { \"data\" : { \"_id\" : \"service-aggregator-account\" , \"_type\" : \"io.cozy.accounts\" } } } } Note: you can read more about the accounts doctype here .", "title": "Aggregator accounts"}, {"location": "cozy-stack/konnectors-workflow/#konnectors", "text": "io.cozy.konnectors are installed similarly to io.cozy.apps (see doc )", "title": "Konnectors"}, {"location": "cozy-stack/konnectors-workflow/#permissions", "text": "Like client-side applications, each konnector has an associated io.cozy.permissions . These permissions are those listed on the manifest of the konnectors, and the stack will add a permission for the files on the folder choosen by the user.", "title": "Permissions"}, {"location": "cozy-stack/konnectors-workflow/#triggers", "text": "io.cozy.triggers are used to define when konnectors are launched. See https://docs.cozy.io/en/cozy-stack/jobs/#post-jobstriggers", "title": "Triggers"}, {"location": "cozy-stack/konnectors-workflow/#complete-flow-example", "text": "As a user, from the expenses management app, I have a clean flow to configure a connector to retrieve my travel expenses 1 - User is in my-expenses and clicks on [configure travels] 2 - my-expenses triggers an intent cozy . intents . start ( \"CREATE\" , \"io.cozy.konnectors\" , { category : \"transport\" }); 3 - the Store app catch the intent, fetch all available konnectors and let the user choose GET /registry?... HTTP / 1.1 4 - the user chooses the trainline konnector. Its manifest looks like this: { \"name\" : \"Trainline\" , \"type\" : \"konnector\" , \"slug\" : \"konnector-trainline\" , \"description\" : \"Konnector for trainline . com\" , \"source\" : \"https://github.com/konnectors/trainlines.git@build\" , \"developer\" : { \"name\" : \"XXX\" , \"url\" : \"https://www.xxx.fr\" }, \"version\" : \"3.0.0\" , \"licence\" : \"AGPL-3.0\" , \"fields\" : { \"login\" : { \"type\" : \"text\" }, \"password\" : { \"type\" : \"password\" }, \"advancedFields\" : { \"folderPath\" : { \"advanced\" : true , \"isRequired\" : false } } }, \"category\" : \"transport\" , \"frequency\" : \"weekly\" , \"permissions\" : { \"events\" : { \"description\" : \"Connect train bill with event in your calendar\" , \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"PATCH\" ] } } } 5 - the user clicks on install, and the install starts: POST /konnectors/trainline HTTP / 1.1 6 - the Store then uses an intent to know which app can configure this konnector: cozy . intents . start ( \"REDIRECT\" , \"io.cozy.accounts\" , { slug : \"trainline\" }); 7 - the Store redirects to the Home. The Home asks the user for account config and create a folder to save the PDFs. 8 - the Home also add a Reference from the konnector to the folder to prevent any accidental folder deletion: POST /files/123-selected-folder-id-123/relationships/referenced_by { \"data\" : [ { \"type\" : \"io.cozy.konnectors\" , \"id\" : \"io.cozy.konnectors/trainlines\" } ] } 9 - then the Home can create the account: POST /data/io.cozy.accounts HTTP / 1.1 { \"account_type\" : \"trainline\" , \"auth\" : { \"login\" : \"xxxx\" , \"password\" : \"yyyyy\" }, \"folderPath\" : \"/Administrative/Trainline\" } HTTP / 1.1 200 OK { \"_id\" : \"123-account-id-123\" , \"_rev\" : \"1-asasasasa\" , \"account_type\" : \"trainline\" , \"auth\" : { \"login\" : \"xxxx\" }, \"folderPath\" : \"/Administrative/Trainline\" } 10 - the Home create the trigger: POST /jobs/io.cozy.triggers { \"data\" : { \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 0 0 0 1 1 \" , \"worker\" : \"konnector\" , \"message\" : { \"konnector\" : \"trainline\" , \"account\" : \"5165621628784562148955\" , \"folder_to_save\" : \"877854878455\" } } } } 11 - and, finally, the Home runs the konnector for the first time: POST /jobs/triggers/abc159753/launch HTTP / 1.1 12 - the Home uses the realtime to be informed if the konnector fails to login or succeeds to import the PDFs. If the user wants to use several account, the Home can setup several triggers for the same konnector & various accounts.", "title": "Complete flow example"}, {"location": "cozy-stack/konnectors-workflow/#konnector-worker-specs", "text": "", "title": "Konnector Worker specs"}, {"location": "cozy-stack/konnectors-workflow/#prepare-the-execution", "text": "The cozy-stack prepares the execution of the konnector by doing these steps: it checks that the konnector is not in maintenance in the registry (except for manual execution) it ensures that the konnector has a folder where it can write its files, and has the permission to write in this folder.", "title": "Prepare the execution"}, {"location": "cozy-stack/konnectors-workflow/#execute-the-konnector", "text": "Start the konnector through nsjail, passing as ENV variables: - `COZY_URL`: the starting instance URL - `COZY_CREDENTIALS`: security token to communicate with Cozy - `COZY_FIELDS`: JSON-encoded message with the arguments from the trigger - `COZY_PAYLOAD`: JSON-encoded payload from the HTTP request (@webhook trigger) - `COZY_PARAMETERS`: JSON-encoded parameters from the konnector manifest - `COZY_LANGUAGE`: the language field of the konnector (eg. \"node\" etc.) - `COZY_LOCALE`: the locale of the user (eg. \"en\" etc.) - `COZY_TIME_LIMIT`: how much time the konnector can run before being killed - `COZY_JOB_ID`: id of the job - `COZY_TRIGGER_ID`: id of the trigger that has created the job - `COZY_JOB_MANUAL_EXECUTION`: whether the job was started manually (in Home) or automatically (via a cron trigger or event) The konnector process can send events trough its stdout (newline separated JSON object), the konnector worker pass these events to the realtime hub as io.cozy.jobs.events . Only JSON formatted events are forwarded to the client-side through realtime Otherwise formatted lines (such as node Error) will be kept in some system logs. Konnectors should NOT log the received account login values in production.", "title": "Execute the konnector"}, {"location": "cozy-stack/konnectors-workflow/#konnector-error-handling", "text": "The konnector can output json formated messages as stated before (the events) and those events will be typed and formatted like this: { type : \"messagetype\" , // can be \"debug\", \"info\", \"warning\", \"error\", and \"critical\" message : \"message\" // can be any string } If there is an error or critical message, the execution will be seen as a failure by cozy-stack. It\u2019s also the case if the konnector reaches the timeout or returns with a non-zero status code. Note: debug and info level are not transmitted to syslog, except if the instance is in debug mode. It would be too verbose to do otherwise. The message can start with a known keyword that could have special meanings for cozy-stack or for statistical analysis of konnector health. Known keywords are listed in the konnector tutorial When a connector throw an error of either LOGIN_FAILED or any error starting with USER_ACTION_NEEDED (with the exception of USER_ACTION_NEEDED.CGU_FORM ), meaning that the user needs to execute an action on provider\u2019s website (either changing its credentials or acknowledging something on provider website), then cozy-stack will skip all subsequent automatic executions to avoid querying the provider site and blocking user account. Manual execution by the user will still be possible to unlock the konnector/account when the user thinks it is now ready to be run again.", "title": "Konnector error handling"}, {"location": "cozy-stack/konnectors-workflow/#account-deleted", "text": "When an account is deleted, or a konnector is going to be uninstalled, the konnector is executed with the account_deleted field to true, so it can clean the account remotely.", "title": "Account deleted"}, {"location": "cozy-stack/konnectors-workflow/#oauth-and-service-secrets", "text": "", "title": "OAuth (and service secrets)"}, {"location": "cozy-stack/konnectors-workflow/#doctypes", "text": "io.cozy.konnectors gives their desiderata for an account { \"fields\" : { \"account\" : { \"doctype\" : \"io.cozy.accounts\" , \"account_type\" : \"maif\" , \"scope\" : \"openid profile offline_access\" } } } io.cozy.accounts contains authentication information for an account, as well as the associated scope { \"name\" : \"Mon Compte Maif\" , \"account_type\" : \"maif\" , \"status\" : \"connected\" , \"oauth\" : { \"access_token\" : \"akosaksoakso\" , \"refresh_token\" : \"okoakozkaozk\" , \"scope\" : \"openid profile offline_access\" } } io.cozy.account_types contains the oauth configuration: { \"_id\" : \"service.example\" , \"grant_mode\" : \"authorization_code\" , \"client_id\" : \"the registered client id\" , \"client_secret\" : \"client_secret is necessary for server-flow\" , \"auth_endpoint\" : \"https://service.example/auth\" , \"token_endpoint\" : \"https://api.service.example/token\" } io.cozy.account_types are not accessible to the applications: they are injected directly in CouchDB in a global database secrets/io-cozy-account_types .", "title": "Doctypes"}, {"location": "cozy-stack/konnectors-workflow/#secrets-that-are-not-oauth", "text": "The io.cozy.account_types doctype can also be used for storing secrets that are not related to OAuth. The document still need to be injected manually in secrets/io-cozy-account_types : { \"_id\": \"service.example\", \"grant_mode\": \"secret\", \"slug\": \"service\", \"secret\": \"th1$_1$_th3_s3cr3t!\" } Note : grant_mode must be secret (or bi_webauth+secret , or bi_webview+secret , or authorization_code+secret ), slug must be the slug of the konnector, but secret can be a map instead of a simple string if several secrets are needed for this service. The secret is given to the konnector in the COZY_PARAMETERS env variable.", "title": "Secrets that are not OAuth"}, {"location": "cozy-stack/konnectors-workflow/#overloading-an-account-type-for-a-given-context", "text": "It is possible to use a different account type for a given context, by creating a new document with an id prefix by the context name and / . For example, a different secret can be used in the foobar context by injecting this document in secrets/io-cozy-account_types : { \"_id\": \"foobar/service.example\", \"grant_mode\": \"secret\", \"slug\": \"service\", \"secret\": \"th1$_1$_n0t_th3_s4m3_s3cr3t!\" }", "title": "Overloading an account type for a given context"}, {"location": "cozy-stack/konnectors-workflow/#reminder-oauth-flow", "text": "Service is the website from which konnector aims to retrieve informations. Stack is the cozy stack. OAuth is divided in 3 steps: Client Registration: the client application (the Stack) needs to be registered with the Service Obtaining & Refreshing Authorization: all the steps from client_id to access_token , the Stack will handle those Using the access_token : ideally, the konnector should only concern itself with this part; it receives an access_token and uses it.", "title": "Reminder OAuth flow"}, {"location": "cozy-stack/konnectors-workflow/#client-registration", "text": "Before beginning the Grant process, most Services require the application to be registered with a defined redirect_uri . There are a lot of options, which we will choose from when actually implementing konnectors using them.", "title": "Client Registration"}, {"location": "cozy-stack/konnectors-workflow/#manually", "text": "Most services requires a human developer to create the client manually and define its redirect_uri. However each instance has its own domain, so for these services, we will need to: A. Register a \u201cproxy\u201d client , which is a static page performing redirections as needed, as was done for Facebook events in v2 konnectors. We will register a well known cozy domain, like oauth-proxy.cozy.io and registers it with all providers. The use and risks associated with this domain should be made clear to the user. B. Register each Stack with a redirect_uri on the main stack domain, if we go this way, the register_uri below moves from bob.cozy.rocks/accounts/service/redirect to oauthcallback.cozy.rocks/accounts/service/redirect and the domain will be prepended to the state. This is feasible at cozy scale, but requires more knowledge and work for self-hosters.", "title": "Manually"}, {"location": "cozy-stack/konnectors-workflow/#example-google", "text": "For example, these are the steps for creating the google account_type for the stack at .mycozy.cloud: Go to https://console.developers.google.com Select or Create Project (up left near the logo) Enable desired APIs (TBD with usages) Click \u201cCredentials\u201d Create credentials > Oauth Client ID > Web application Set redirectURI to https://oauthcallback.mycozy.cloud/accounts/google/redirect Copy and paste provided Client ID and Client Secret. Then save the data in the console http PUT localhost:5984/secrets%2Fio-cozy-account_types/google grant_mode=authorization_code redirect_uri=\"https://oauthcallback.mycozy.cloud/accounts/google/redirect\" token_mode=basic token_endpoint=\"https://www.googleapis.com/oauth2/v4/token\" auth_endpoint=\"https://accounts.google.com/o/oauth2/v2/auth\" client_id=$CLIENT_ID client_secret=$CLIENT_SECRET", "title": "Example: Google"}, {"location": "cozy-stack/konnectors-workflow/#dynamic-registration-protocol", "text": "A few services allows client to register programatically through the Dynamic Client Registration Protocol RFC7591 , we should allow the Stack to register using this protocol when we first need to implement a Konnector connecting to such a Service.", "title": "Dynamic Registration Protocol"}, {"location": "cozy-stack/konnectors-workflow/#no-redirect_url-enforcement", "text": "A few services allows to specify arbitrary redirect_url without registering beforehand as a client.", "title": "No redirect_url enforcement"}, {"location": "cozy-stack/konnectors-workflow/#authorization-grant-flows", "text": "", "title": "Authorization Grant flows"}, {"location": "cozy-stack/konnectors-workflow/#webserver-flow-authorization-code-grant", "text": "A. In the cozy app (Home) give a link < a href = \"https://bob.cozy.rocks/accounts/service-name/start? scope=photos& state=1234zyx\" > Notes: the scope may depends on other fields being configured (checkboxes), this will be described in json in the konnectors manifest. The format will be determined upon implementation; to limit bandwidth and risk of state corruption, the cozy app should save its state under a random key into localStorage, the key is then passed as the state in this query; a third parameter, slug , can be added to redirect to this app instead of the home. B. Service lets the user login, allows or denies the scope, then redirects to https://oauthcallback.cozy.rocks/accounts/service-name/redirect? code=AUTH_CODE_HERE& state=1234zyx C. The Stack does Server side this request: POST /oauth/access_token HTTP / 1.1 Host : api.service.example Content-Type : application/x-www-form-urlencoded grant_type=authorization_code& code=AUTH_CODE_HERE& redirect_uri=https://oauthcallback.cozy.rocks/accounts/service-name/redirect& client_id=CLIENT_ID& client_secret=CLIENT_SECRET Note: the stack will also send the state parameter on this request. It is not mandatory per the OAuth 2.0 spec, and the skip_state_on_token option can be used to cancel this behavior if the provider throw an error if this parameter is present. D. The Service responds (server side) with: { \"access_token\" : \"ACCESS_TOKEN\" , \"token_type\" : \"bearer\" , \"expires_in\" : 2592000 , \"refresh_token\" : \"REFRESH_TOKEN\" , \"scope\" : \"read\" , \"uid\" : 100101 , \"info\" : { \"name\" : \"Claude Douillet\" , \"email\" : \"claude.douillet@example.com\" } } This whole object is saved as-is into a io.cozy.accounts \u2018s extras field. The known fields access_token , refresh_token & scope will be also saved on the account\u2019s oauth itself E. The Stack redirect the user to the cozy app: HTTP / 1.1 302 Found Location : https://bob-home.cozy.rocks/?state=1234zyx&account=accountID The Cozy app checks that the state is expected, and restores its state to the form but whith account completed.", "title": "webserver flow (Authorization Code Grant)"}, {"location": "cozy-stack/konnectors-workflow/#spa-flow-implicit-grant", "text": "A. The cozy app gives a link: < a href = \"https://service.example/auth? (url) response_type=token& client_id=CLIENT_ID& redirect_uri=https://bob-home.cozy.rocks/& scope=photos& state=1234zyx\" > See server-flow for state rules. B. Service lets the user login, allows or denies the scope, then redirects to https://bob-home.cozy.rocks/?access_token=ACCESS_TOKEN&state=1234zyx C. The Cozy app adds the token to the io.cozy.accounts and save it before starting konnector.", "title": "SPA flow (Implicit grant)"}, {"location": "cozy-stack/konnectors-workflow/#accessing-data", "text": "Once we have an account, the Cozy app starts the konnector with the proper account id. The konnector can then fetch the account and use its access_token to performs a request to fetch data: POST /resource HTTP / 1.1 Host : api.service.example Authorization : Bearer ACCESS_TOKEN", "title": "Accessing data"}, {"location": "cozy-stack/konnectors-workflow/#refreshing-token", "text": "When using the server-flow, we also get a refresh_token. It is used to get a new access_token when it expires. However, if konnectors are responsible for refreshing token there is a race condition risk: (konnector A) GET https://api.service.com/resource TOKEN1 -> expired (konnector B) GET https://api.service.com/resource TOKEN1 -> expired (konnector A) POST https://api.service.com/token REFRESH_TOKEN -> TOKEN2a (konnector B) POST https://api.service.com/token REFRESH_TOKEN -> TOKEN2b (konnector A) GET https://api.service.com/token TOKEN2a -> invalid To avoid this, the stack will be responsible to perform token refresh. A konnector can requires the stack to refresh an account token with an HTTP request. POST /accounts/:accountType/:accountID/refresh HTTP / 1.1 Host : bob.cozy.rocks", "title": "Refreshing token"}, {"location": "cozy-stack/konnectors-workflow/#konnectors-marketplace-requirements", "text": "The following is a few points to be careful for in konnectors when we start allowing non-cozy developped OAuth konnectors. With SPA flow, because of advanced security concerns (confused deputy problem), cozy should validate the access_token . However, the way to do that depends on the provider and cannot be described in json, it is therefore the responsibility of the konnector itself.", "title": "Konnectors Marketplace Requirements"}, {"location": "cozy-stack/konnectors-workflow/#account-types-security-rules", "text": "With server flow, an evil account type with proper auth_endpoint but bad token_endpoint could retrieve a valid token as well as cozy client secret. The reviewer of an account_type should make sure both these endpoints are on domains belonging to the Service provider.", "title": "Account types security rules"}, {"location": "cozy-stack/konnectors-workflow/#notes-for-mesinfos-experiment", "text": "MAIF konnector uses the webserver flow without redirect_uri validation Orange konnector uses the client-side proxy but hosted on their own servers (/!\\ redirect_uri vs redirect_url)", "title": "Notes for MesInfos experiment"}, {"location": "cozy-stack/konnectors-workflow/#webauth", "text": "For some banks integration (Paypal, Orange Bank, Revolut\u2026), Budget Insight has a workflow similar to OAuth called Webauth . It is possible to use this workflow for konnectors by registering an account type with the following parameter: grant_mode , with bi_webauth as the value (or bi_webauth+secret if there is also a secret) redirect_uri , with an URL like https://oauthcallback.mycozy.cloud/accounts/paypal/redirect client_id , with the client ID given by Budget Insight auth_endpoint , with https://{domain}.biapi.pro/2.0/webauth (with the correct domain ) reconnect_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/reconnect (idem).", "title": "Webauth"}, {"location": "cozy-stack/konnectors-workflow/#bi-weview", "text": "A new integration of Budget Insight is available for all the proposed banks. This is a workflow similar to OAuth called webview It is possible to use this workflow for konnectors by registering an account type with the following parameter: grant_mode , with bi_webview+secret as the value redirect_uri , with an URL like https://oauthcallback.mycozy.cloud/accounts/paypal/redirect client_id , with the client ID given by Budget Insight auth_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/fr/connect (with the correct domain ) manage_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/reconnect (idem). reconnect_endpoint , with https://{domain}.biapi.pro/2.0/auth/webview/reconnect (idem).", "title": "BI Weview"}, {"location": "cozy-stack/konnectors-workflow/#manage", "text": "The manage webview can be called with this route: GET /accounts/:accountType/:accountID/manage?code={code}&connection_id={id}&slug={slug}&state={state} HTTP / 1.1 Host : jane.cozy.example HTTP / 1.1 303 See Other Location : https://domain.biapi.pro/2.0/auth/webview/manage ?client_id={client_id} &code={code} &connection_id={id} &redirect_uri=https://oauthcallback.cozy.example/accounts/{accountType}/redirect &state={stackState} At the end of flow, the user will be redirected to https://jane-{slug}.cozy.example/?state={state} .", "title": "Manage"}, {"location": "cozy-stack/konnectors-workflow/#reconnect", "text": "The reconnection webview can be called with this route: GET /accounts/:accountType/:accountID/reconnect?code={code}&connection_id={id}&slug={slug}&state={state} HTTP / 1.1 Host : jane.cozy.example HTTP / 1.1 303 See Other Location : https://domain.biapi.pro/2.0/auth/webview/reconnect ?client_id={client_id} &code={code} &connection_id={id} &redirect_uri=https://oauthcallback.cozy.example/accounts/{accountType}/redirect &state={stackState} At the end of flow, the user will be redirected to https://jane-{slug}.cozy.example/?state={state} .", "title": "Reconnect"}, {"location": "cozy-stack/konnectors-workflow/#webhook-triggers", "text": "The cloudery (or an application) can install the konnector and create an account It can also create the webhook trigger via a POST /jobs/triggers Request: POST /jobs/triggers HTTP / 1.1 Host : jane.cozy.example Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"type\" : \"@webhook\" , \"worker\" : \"konnector\" , \"message\" : { \"param_from_trigger\" : \"foo\" } } } } Response: HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"0915b6b0-0c97-0139-5af7-543d7eb8149c\" , \"attributes\" : { \"type\" : \"@webhook\" , \"worker\" : \"konnector\" , \"message\" : { \"konnector\" : \"mykonnector\" , \"param_from_trigger\" : \"foo\" } }, \"links\" : { \"self\" : \"/jobs/triggers/0915b6b0-0c97-0139-5af7-543d7eb8149c\" , \"webhook\" : \"https://jane.cozy.example/jobs/webhooks/0915b6b0-0c97-0139-5af7-543d7eb8149c\" } } } The cloudery can then give the webhook URL to the external service When the external service has new documents to import, it can call the webhook Request: POST /jobs/webhooks/0915b6b0-0c97-0139-5af7-543d7eb8149c HTTP / 1.1 Host : jane.cozy.example Content-Type : application/json { \"param_from_http_body\" : \"bar\" } Response: HTTP / 1.1 204 No Content The stack will put a job in its queue for the konnector The stack executes the konnector with: COZY_FIELDS={\"param_from_trigger\": \"foo\"} COZY_PAYLOAD={\"param_from_http_body\": \"bar\"} etc. Note: the environnement variables have a limit for their size defined by the linux kernel. If the payload is too big to fit inside the env variable, the stack will put the payload in a temporary file, and will set the COZY_PAYLOAD variable to @ + the filename of this file, like: COZY_PAYLOAD=@cozy_payload.json The konnector will fetch the documents from the external service and save them in the Cozy. Note: if the trigger has a debounce, the COZY_PAYLOAD will be an object with a payloads array, like this: COZY_PAYLOAD ={ \"payloads\" : [{ \"param_from_http_body\" : \"bar\" }]}", "title": "Webhook triggers"}, {"location": "cozy-stack/konnectors/", "text": "Table of contents Konnectors \u00b6 It is possible to manage konnectors applications from the stack. The source-code of the konnector is installed on the cozy and the user can manage its execution via our job system and the konnector worker . Install a konnector \u00b6 The manifest \u00b6 An exhaustive manifest specification is available in the Cozy Apps Registry documentation POST /konnectors/:slug \u00b6 Install a konnector, ie download the files and put them in /konnectors/:slug in the virtual file system of the user, create an io.cozy.konnectors document, register the permissions, etc. This endpoint is asynchronous and returns a successful return as soon as the konnector installation has started, meaning we have successfully reached the manifest and started to fetch konnector source code. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the konnector has been installed or failed. Status codes \u00b6 202 Accepted, when the konnector installation has been accepted. 400 Bad-Request, when the manifest of the konnector could not be processed (for instance, it is not valid JSON). 404 Not Found, when the manifest or the source of the konnector is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url) Query-String \u00b6 Parameter Description Source URL from where the app can be downloaded (only for install) Request \u00b6 POST /konnectors/bank101?Source=git://github.com/cozy/cozy-bank101.git HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }] } Note : it\u2019s possible to choose a git branch by passing it in the fragment like this: POST /konnectors/bank101-dev?Source=git://github.com/cozy/cozy-bank101.git%23dev HTTP / 1.1 PUT /konnectors/:slug \u00b6 Update a konnector source code with the specified slug name. This endpoint is asynchronous and returns a successful return as soon as the konnector installation has started, meaning we have successfully reached the manifest and started to fetch konnector source code. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the konnector has been updated or failed. Request \u00b6 PUT /konnectors/bank101 HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }] } Status codes \u00b6 202 Accepted, when the konnector installation has been accepted. 400 Bad-Request, when the manifest of the konnector could not be processed (for instance, it is not valid JSON). 404 Not Found, when the konnector with the specified slug was not found or when the manifest or the source of the konnector is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url) Advanced usage \u00b6 Two optional query parameters are available for a konnector update: - PermissionsAcked : (defaults to true ) - Tells that the user accepted the permissions/ToS. It is useful if there are newer permissions or Terms Of Service and you want to be sure they were read or accepted. If set to false , the update will be blocked and the user will be told that a new konnector version is available.\\ > Note: PermissionsAcked can be skipped. \\ If an instance is in a context configured with the parameter permissions_skip_verification sets to true , permissions verification will be ignored. Source (defaults to source url installation): Use a different source to update this konnector (e.g. to install a beta or dev konnector version) Examples: \u00b6 You have a trainline konnector on a stable channel, and you want to update it to a particular beta version: PUT /konnectors/trainline?Source=https:///trainline/1.0.0-beta HTTP / 1.1 Accept : application/vnd.api+json You want to attempt the trainline konnector update, but prevent it if new permissions were added PUT /konnectors/trainline?PermissionsAcked=false HTTP / 1.1 Accept : application/vnd.api+json You can combine these parameters to use a precise konnector version and stay on another channel (when permissions are different): Install a version (e.g. 1.0.0 ). Ask an update to stable channel with PermissionsAcked to false Source will be stable , and your version remains 1.0.0 List installed konnectors \u00b6 GET /konnectors/ \u00b6 Request \u00b6 GET /konnectors/ HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }], \"links\" : {}, \"meta\" : { \"count\" : 1 } } This endpoint is paginated, default limit is currently 100 . Two flags are available to retreieve the other konnectors if there are more than 100 konnectors installed: - limit - start_key : The first following doc ID of the next konnectors The links object contains a \u01f9ext generated-link for the next docs. Request \u00b6 GET /konnectors/?limit=50 HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }, { ... }], \"links\" : { \"next\" : \"http://alice.example.com/konnectors/?limit=50&start_key=io.cozy.konnectors%2Ffookonnector\" }, \"meta\" : { \"count\" : 50 } } Get informations about a konnector \u00b6 GET /konnectors/:slug \u00b6 This route is used to retrieve informations about a konnector installed on the cozy. By calling this route, the konnector will be updated synchronously. Request \u00b6 GET /konnectors/pajemploi HTTP / 1.1 Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.konnectors\" , \"id\" : \"io.cozy.konnectors/pajemploi\" , \"attributes\" : { \"name\" : \"Pajemploi\" , \"editor\" : \"Cozy\" , \"icon\" : \"icon.svg\" , \"type\" : \"konnector\" , \"language\" : \"node\" , ... }, \"meta\" : { \"rev\" : \"8-1197cab1c9ecc89cef676567410cf7c5\" }, \"links\" : { \"self\" : \"/konnectors/pajemploi\" , \"icon\" : \"/konnectors/pajemploi/icon/1.5.2\" , \"permissions\" : \"/permissions/konnectors/pajemploi\" } } } Download the code of a konnector \u00b6 This endpoint is used by the flagship app to download the code of a konnector, in order to install it on the user\u2019s device. GET /konnectors/:slug/download & GET /konnectors/:slug/download/:version \u00b6 The first route will download a tarball of the source code of the latest installed version of the konnector. The second route will force a specific version of the konnector (and a 412 Precondition failed may be sent if the code of this specific version is not available). Request \u00b6 GET /konnectors/pajemploi/download/3.0.1 HTTP / 1.1 Authorization : Bearer flagship-token Host : cozy.example.net Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/gzip When the konnector has been installed from the registry, the stack will respond with a redirect to the registry. In that case, the downloaded tarball can be gzipped or not (the registry allows both). When the konnector is installed from another source, the stack will create a gzipped tarball and send it to the client. Uninstall a konnector \u00b6 DELETE /konnectors/:slug \u00b6 Request \u00b6 DELETE /konnectors/bank101 HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 No Content Or, if the konnector has still some accounts configured: HTTP / 1.1 202 Accepted In this case, the stack will accept the uninstall request, then it will clean the accounts (locally and remotely), and only after that, the konnector will be removed. Add a trigger \u00b6 POST /konnectors/:slug/trigger \u00b6 This endpoint creates a @cron trigger for the given konnector. The manifest is used to generate the crontab. Query-String \u00b6 Parameter Description AccountID The identifier of the io.cozy.accounts that will be used to run the konnector ExecNow true if you want to run a job just after the trigger creation Request \u00b6 POST /konnectors/pajemploi/trigger?AccountID=4eee63e069690139df83543d7eb8149c HTTP / 1.1 Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"8cfeef1069690139df84543d7eb8149c\" , \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 9 3 * * 1\" , \"worker\" : \"konnector\" , \"message\" : { \"account\" : \"4eee63e069690139df83543d7eb8149c\" , \"konnector\" : \"pajemploi\" } }, \"links\" : { \"self\" : \"/jobs/triggers/8cfeef1069690139df84543d7eb8149c\" } } } Send konnector logs to cozy-stack \u00b6 POST /konnectors/:slug/logs \u00b6 Send client-side logs to cozy-stack so they can be stored in the server\u2019s logging system. Status codes \u00b6 204 No Content, when all the log lines have been processed. 400 Bad-Request, when the JSON body is invalid. 404 Not Found, when no konnectors with the given slug could be found. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or log level does not exist) Request \u00b6 POST /konnectors/pajemploi/logs HTTP / 1.1 Accept : application/vnd.api+json [ { \"timestamp\" : \"2022-10-27T17:13:37.293Z\" , \"level\" : \"info\" , \"msg\" : \"Connecting to remote site...\" }, { \"timestamp\" : \"2022-10-27T17:13:38.382Z\" , \"level\" : \"error\" , \"msg\" : \"LOGIN_FAILED\" } ] Response \u00b6 HTTP / 1.1 204 No Content", "title": "/konnectors - Konnectors"}, {"location": "cozy-stack/konnectors/#konnectors", "text": "It is possible to manage konnectors applications from the stack. The source-code of the konnector is installed on the cozy and the user can manage its execution via our job system and the konnector worker .", "title": "Konnectors"}, {"location": "cozy-stack/konnectors/#install-a-konnector", "text": "", "title": "Install a konnector"}, {"location": "cozy-stack/konnectors/#the-manifest", "text": "An exhaustive manifest specification is available in the Cozy Apps Registry documentation", "title": "The manifest"}, {"location": "cozy-stack/konnectors/#post-konnectorsslug", "text": "Install a konnector, ie download the files and put them in /konnectors/:slug in the virtual file system of the user, create an io.cozy.konnectors document, register the permissions, etc. This endpoint is asynchronous and returns a successful return as soon as the konnector installation has started, meaning we have successfully reached the manifest and started to fetch konnector source code. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the konnector has been installed or failed.", "title": "POST /konnectors/:slug"}, {"location": "cozy-stack/konnectors/#status-codes", "text": "202 Accepted, when the konnector installation has been accepted. 400 Bad-Request, when the manifest of the konnector could not be processed (for instance, it is not valid JSON). 404 Not Found, when the manifest or the source of the konnector is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url)", "title": "Status codes"}, {"location": "cozy-stack/konnectors/#query-string", "text": "Parameter Description Source URL from where the app can be downloaded (only for install)", "title": "Query-String"}, {"location": "cozy-stack/konnectors/#request", "text": "POST /konnectors/bank101?Source=git://github.com/cozy/cozy-bank101.git HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/konnectors/#response", "text": "HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }] } Note : it\u2019s possible to choose a git branch by passing it in the fragment like this: POST /konnectors/bank101-dev?Source=git://github.com/cozy/cozy-bank101.git%23dev HTTP / 1.1", "title": "Response"}, {"location": "cozy-stack/konnectors/#put-konnectorsslug", "text": "Update a konnector source code with the specified slug name. This endpoint is asynchronous and returns a successful return as soon as the konnector installation has started, meaning we have successfully reached the manifest and started to fetch konnector source code. To make this endpoint synchronous, use the header Accept: text/event-stream . This will make a eventsource stream sending the manifest and returning when the konnector has been updated or failed.", "title": "PUT /konnectors/:slug"}, {"location": "cozy-stack/konnectors/#request_1", "text": "PUT /konnectors/bank101 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_1", "text": "HTTP / 1.1 202 Accepted Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }] }", "title": "Response"}, {"location": "cozy-stack/konnectors/#status-codes_1", "text": "202 Accepted, when the konnector installation has been accepted. 400 Bad-Request, when the manifest of the konnector could not be processed (for instance, it is not valid JSON). 404 Not Found, when the konnector with the specified slug was not found or when the manifest or the source of the konnector is not reachable. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or the Source parameter is not a proper or supported url)", "title": "Status codes"}, {"location": "cozy-stack/konnectors/#advanced-usage", "text": "Two optional query parameters are available for a konnector update: - PermissionsAcked : (defaults to true ) - Tells that the user accepted the permissions/ToS. It is useful if there are newer permissions or Terms Of Service and you want to be sure they were read or accepted. If set to false , the update will be blocked and the user will be told that a new konnector version is available.\\ > Note: PermissionsAcked can be skipped. \\ If an instance is in a context configured with the parameter permissions_skip_verification sets to true , permissions verification will be ignored. Source (defaults to source url installation): Use a different source to update this konnector (e.g. to install a beta or dev konnector version)", "title": "Advanced usage"}, {"location": "cozy-stack/konnectors/#examples", "text": "You have a trainline konnector on a stable channel, and you want to update it to a particular beta version: PUT /konnectors/trainline?Source=https:///trainline/1.0.0-beta HTTP / 1.1 Accept : application/vnd.api+json You want to attempt the trainline konnector update, but prevent it if new permissions were added PUT /konnectors/trainline?PermissionsAcked=false HTTP / 1.1 Accept : application/vnd.api+json You can combine these parameters to use a precise konnector version and stay on another channel (when permissions are different): Install a version (e.g. 1.0.0 ). Ask an update to stable channel with PermissionsAcked to false Source will be stable , and your version remains 1.0.0", "title": "Examples:"}, {"location": "cozy-stack/konnectors/#list-installed-konnectors", "text": "", "title": "List installed konnectors"}, {"location": "cozy-stack/konnectors/#get-konnectors", "text": "", "title": "GET /konnectors/"}, {"location": "cozy-stack/konnectors/#request_2", "text": "GET /konnectors/ HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }], \"links\" : {}, \"meta\" : { \"count\" : 1 } } This endpoint is paginated, default limit is currently 100 . Two flags are available to retreieve the other konnectors if there are more than 100 konnectors installed: - limit - start_key : The first following doc ID of the next konnectors The links object contains a \u01f9ext generated-link for the next docs.", "title": "Response"}, {"location": "cozy-stack/konnectors/#request_3", "text": "GET /konnectors/?limit=50 HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_3", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" , \"type\" : \"io.cozy.konnectors\" , \"meta\" : { \"rev\" : \"1-7a1f918147df94580c92b47275e4604a\" }, \"attributes\" : { \"name\" : \"bank101\" , \"state\" : \"installing\" , \"slug\" : \"bank101\" , ... }, \"links\" : { \"self\" : \"/konnectors/bank101\" } }, { ... }], \"links\" : { \"next\" : \"http://alice.example.com/konnectors/?limit=50&start_key=io.cozy.konnectors%2Ffookonnector\" }, \"meta\" : { \"count\" : 50 } }", "title": "Response"}, {"location": "cozy-stack/konnectors/#get-informations-about-a-konnector", "text": "", "title": "Get informations about a konnector"}, {"location": "cozy-stack/konnectors/#get-konnectorsslug", "text": "This route is used to retrieve informations about a konnector installed on the cozy. By calling this route, the konnector will be updated synchronously.", "title": "GET /konnectors/:slug"}, {"location": "cozy-stack/konnectors/#request_4", "text": "GET /konnectors/pajemploi HTTP / 1.1 Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.konnectors\" , \"id\" : \"io.cozy.konnectors/pajemploi\" , \"attributes\" : { \"name\" : \"Pajemploi\" , \"editor\" : \"Cozy\" , \"icon\" : \"icon.svg\" , \"type\" : \"konnector\" , \"language\" : \"node\" , ... }, \"meta\" : { \"rev\" : \"8-1197cab1c9ecc89cef676567410cf7c5\" }, \"links\" : { \"self\" : \"/konnectors/pajemploi\" , \"icon\" : \"/konnectors/pajemploi/icon/1.5.2\" , \"permissions\" : \"/permissions/konnectors/pajemploi\" } } }", "title": "Response"}, {"location": "cozy-stack/konnectors/#download-the-code-of-a-konnector", "text": "This endpoint is used by the flagship app to download the code of a konnector, in order to install it on the user\u2019s device.", "title": "Download the code of a konnector"}, {"location": "cozy-stack/konnectors/#get-konnectorsslugdownload-get-konnectorsslugdownloadversion", "text": "The first route will download a tarball of the source code of the latest installed version of the konnector. The second route will force a specific version of the konnector (and a 412 Precondition failed may be sent if the code of this specific version is not available).", "title": "GET /konnectors/:slug/download & GET /konnectors/:slug/download/:version"}, {"location": "cozy-stack/konnectors/#request_5", "text": "GET /konnectors/pajemploi/download/3.0.1 HTTP / 1.1 Authorization : Bearer flagship-token Host : cozy.example.net", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : application/gzip When the konnector has been installed from the registry, the stack will respond with a redirect to the registry. In that case, the downloaded tarball can be gzipped or not (the registry allows both). When the konnector is installed from another source, the stack will create a gzipped tarball and send it to the client.", "title": "Response"}, {"location": "cozy-stack/konnectors/#uninstall-a-konnector", "text": "", "title": "Uninstall a konnector"}, {"location": "cozy-stack/konnectors/#delete-konnectorsslug", "text": "", "title": "DELETE /konnectors/:slug"}, {"location": "cozy-stack/konnectors/#request_6", "text": "DELETE /konnectors/bank101 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_6", "text": "HTTP / 1.1 204 No Content Or, if the konnector has still some accounts configured: HTTP / 1.1 202 Accepted In this case, the stack will accept the uninstall request, then it will clean the accounts (locally and remotely), and only after that, the konnector will be removed.", "title": "Response"}, {"location": "cozy-stack/konnectors/#add-a-trigger", "text": "", "title": "Add a trigger"}, {"location": "cozy-stack/konnectors/#post-konnectorsslugtrigger", "text": "This endpoint creates a @cron trigger for the given konnector. The manifest is used to generate the crontab.", "title": "POST /konnectors/:slug/trigger"}, {"location": "cozy-stack/konnectors/#query-string_1", "text": "Parameter Description AccountID The identifier of the io.cozy.accounts that will be used to run the konnector ExecNow true if you want to run a job just after the trigger creation", "title": "Query-String"}, {"location": "cozy-stack/konnectors/#request_7", "text": "POST /konnectors/pajemploi/trigger?AccountID=4eee63e069690139df83543d7eb8149c HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_7", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.triggers\" , \"id\" : \"8cfeef1069690139df84543d7eb8149c\" , \"attributes\" : { \"type\" : \"@cron\" , \"arguments\" : \"0 9 3 * * 1\" , \"worker\" : \"konnector\" , \"message\" : { \"account\" : \"4eee63e069690139df83543d7eb8149c\" , \"konnector\" : \"pajemploi\" } }, \"links\" : { \"self\" : \"/jobs/triggers/8cfeef1069690139df84543d7eb8149c\" } } }", "title": "Response"}, {"location": "cozy-stack/konnectors/#send-konnector-logs-to-cozy-stack", "text": "", "title": "Send konnector logs to cozy-stack"}, {"location": "cozy-stack/konnectors/#post-konnectorssluglogs", "text": "Send client-side logs to cozy-stack so they can be stored in the server\u2019s logging system.", "title": "POST /konnectors/:slug/logs"}, {"location": "cozy-stack/konnectors/#status-codes_2", "text": "204 No Content, when all the log lines have been processed. 400 Bad-Request, when the JSON body is invalid. 404 Not Found, when no konnectors with the given slug could be found. 422 Unprocessable Entity, when the sent data is invalid (for example, the slug is invalid or log level does not exist)", "title": "Status codes"}, {"location": "cozy-stack/konnectors/#request_8", "text": "POST /konnectors/pajemploi/logs HTTP / 1.1 Accept : application/vnd.api+json [ { \"timestamp\" : \"2022-10-27T17:13:37.293Z\" , \"level\" : \"info\" , \"msg\" : \"Connecting to remote site...\" }, { \"timestamp\" : \"2022-10-27T17:13:38.382Z\" , \"level\" : \"error\" , \"msg\" : \"LOGIN_FAILED\" } ]", "title": "Request"}, {"location": "cozy-stack/konnectors/#response_8", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/mango/", "text": "Table of contents Mango \u00b6 Create an index for some documents \u00b6 The body should contain a index JSON field containing a fields which is an ordered array of fields to index. Request \u00b6 POST /data/:doctype/_index HTTP / 1.1 POST /data/io.cozy.events/_index HTTP / 1.1 Content-Type : application/json { \"index\" : { \"fields\" : [ \"calendar\" , \"date\" ] } } Response OK \u00b6 HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json { \"result\" : \"created\" , \"id\" : \"_design/a5f4711fc9448864a13c81dc71e660b524d7410c\" , \"name\" : \"a5f4711fc9448864a13c81dc71e660b524d7410c\" } Details \u00b6 if the doctype does not exist, the database is created. if the index already exists, a {result: \"exists\"} is returned, but the response code is still 200 design doc & name can be provided in request. This is not recommended , let couchdb handle naming and deduplication. { \"name\" : \"by-calendar-and-date\" , \"ddoc\" : \"_design/some-ddoc-name\" , \"index\" : { \"fields\" : ... } } Possible errors \u00b6 401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 500 internal server error Find documents \u00b6 Find allows to find documents using a mango selector. You can read more about mango selectors here Request \u00b6 POST /data/:doctype/_find HTTP / 1.1 POST /data/io.cozy.events/_find HTTP / 1.1 Content-Type : application/json { \"selector\" : { \"calendar\" : \"perso\" , \"date\" : { \"$gt\" : \"20161001T00:00:00\" } }, \"limit\" : 2 , \"sort\" : [ \"calendar\" , \"date\" ], \"fields\" : [ \"_id\" , \"_type\" , \"_date\" ], \"execution_stats\" : true , \"use_index\" : \"_design/a5f4711fc9448864a13c81dc71e660b524d7410c\" } Response OK \u00b6 HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json { \"docs\" : [ { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"date\" : \"20161023T160000Z\" }, { \"_id\" : \"6494e0ac-dfcb-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"date\" : \"20161013T160000Z\" } ], \"execution_stats\" : { \"total_docs_examined\" : 10 , \"results_returned\" : 2 , \"execution_time_ms\" : 8.833 }, \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJB\" , \"limit\" : 2 , \"next\" : true } Details \u00b6 If an index does not exist for the selector, an error 400 is returned The sort field must contains all fields used in selector The sort field must match an existing index It is possible to sort in reverse direction sort:[{\"calendar\":\"desc\"}, {\"date\": \"desc\"}] but all fields must be sorted in same direction. use_index is optional but recommended. execution_stats is false by default. It gives execution information about the query. See here for more details. Pagination cookbook \u00b6 Pagination of mango query should be handled by the client. The stack will limit query results to a maximum of 100 documents. This limit can be raised up to 1000 documents per page with the limit parameter, but not further. The limit applied to a query is visible in the HTTP response. If the limit cause some docs to not be returned, the response will have a next=true top level values. Then, the returned bookmark value can be used in the next query to get the missing docs. It is also possible to use skip , to paginate, although this is not recommended for performances. For more details, see the CouchDB documentation . { \"limit\" : 100 , \"next\" : true , \"docs\" : [ \"... first hundred docs ...\" ], \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76\" } If the number of docs is lower than the limit, next will be false. { \"limit\" : 100 , \"next\" : false , \"docs\" : [ \"... less than a hundred docs ...\" ] } Example: \u00b6 Index on io.cozy.events with fields [\"calendar\", \"date\"] Try to get all events for a month: \"selector\" : { \"calendar\" : \"my-calendar\" , \"date\" : { \"$gt\" : \"20161001\" , \"$lt\" : \"20161030\" } } If there is less than 100 events, the response next field will be false and there is nothing more to do. If there is more than 100 events for this month, we have a next=true in the response. To keep iterating, we can use the bookmark field we received in the next request. \"selector\" : { \"calendar\" : \"my-calendar\" , \"date\" : { \"$gte\" : \"20161001\" , \"$lt\" : \"20161030\" } } , \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76\"", "title": " /data - Mango"}, {"location": "cozy-stack/mango/#mango", "text": "", "title": "Mango"}, {"location": "cozy-stack/mango/#create-an-index-for-some-documents", "text": "The body should contain a index JSON field containing a fields which is an ordered array of fields to index.", "title": "Create an index for some documents"}, {"location": "cozy-stack/mango/#request", "text": "POST /data/:doctype/_index HTTP / 1.1 POST /data/io.cozy.events/_index HTTP / 1.1 Content-Type : application/json { \"index\" : { \"fields\" : [ \"calendar\" , \"date\" ] } }", "title": "Request"}, {"location": "cozy-stack/mango/#response-ok", "text": "HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json { \"result\" : \"created\" , \"id\" : \"_design/a5f4711fc9448864a13c81dc71e660b524d7410c\" , \"name\" : \"a5f4711fc9448864a13c81dc71e660b524d7410c\" }", "title": "Response OK"}, {"location": "cozy-stack/mango/#details", "text": "if the doctype does not exist, the database is created. if the index already exists, a {result: \"exists\"} is returned, but the response code is still 200 design doc & name can be provided in request. This is not recommended , let couchdb handle naming and deduplication. { \"name\" : \"by-calendar-and-date\" , \"ddoc\" : \"_design/some-ddoc-name\" , \"index\" : { \"fields\" : ... } }", "title": "Details"}, {"location": "cozy-stack/mango/#possible-errors", "text": "401 unauthorized (no authentication has been provided) 403 forbidden (the authentication does not provide permissions for this action) 500 internal server error", "title": "Possible errors"}, {"location": "cozy-stack/mango/#find-documents", "text": "Find allows to find documents using a mango selector. You can read more about mango selectors here", "title": "Find documents"}, {"location": "cozy-stack/mango/#request_1", "text": "POST /data/:doctype/_find HTTP / 1.1 POST /data/io.cozy.events/_find HTTP / 1.1 Content-Type : application/json { \"selector\" : { \"calendar\" : \"perso\" , \"date\" : { \"$gt\" : \"20161001T00:00:00\" } }, \"limit\" : 2 , \"sort\" : [ \"calendar\" , \"date\" ], \"fields\" : [ \"_id\" , \"_type\" , \"_date\" ], \"execution_stats\" : true , \"use_index\" : \"_design/a5f4711fc9448864a13c81dc71e660b524d7410c\" }", "title": "Request"}, {"location": "cozy-stack/mango/#response-ok_1", "text": "HTTP / 1.1 200 OK Date : Mon, 27 Sept 2016 12:28:53 GMT Content-Length : ... Content-Type : application/json { \"docs\" : [ { \"_id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"date\" : \"20161023T160000Z\" }, { \"_id\" : \"6494e0ac-dfcb-472e84a9cbee\" , \"_type\" : \"io.cozy.events\" , \"date\" : \"20161013T160000Z\" } ], \"execution_stats\" : { \"total_docs_examined\" : 10 , \"results_returned\" : 2 , \"execution_time_ms\" : 8.833 }, \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJB\" , \"limit\" : 2 , \"next\" : true }", "title": "Response OK"}, {"location": "cozy-stack/mango/#details_1", "text": "If an index does not exist for the selector, an error 400 is returned The sort field must contains all fields used in selector The sort field must match an existing index It is possible to sort in reverse direction sort:[{\"calendar\":\"desc\"}, {\"date\": \"desc\"}] but all fields must be sorted in same direction. use_index is optional but recommended. execution_stats is false by default. It gives execution information about the query. See here for more details.", "title": "Details"}, {"location": "cozy-stack/mango/#pagination-cookbook", "text": "Pagination of mango query should be handled by the client. The stack will limit query results to a maximum of 100 documents. This limit can be raised up to 1000 documents per page with the limit parameter, but not further. The limit applied to a query is visible in the HTTP response. If the limit cause some docs to not be returned, the response will have a next=true top level values. Then, the returned bookmark value can be used in the next query to get the missing docs. It is also possible to use skip , to paginate, although this is not recommended for performances. For more details, see the CouchDB documentation . { \"limit\" : 100 , \"next\" : true , \"docs\" : [ \"... first hundred docs ...\" ], \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76\" } If the number of docs is lower than the limit, next will be false. { \"limit\" : 100 , \"next\" : false , \"docs\" : [ \"... less than a hundred docs ...\" ] }", "title": "Pagination cookbook"}, {"location": "cozy-stack/mango/#example", "text": "Index on io.cozy.events with fields [\"calendar\", \"date\"] Try to get all events for a month: \"selector\" : { \"calendar\" : \"my-calendar\" , \"date\" : { \"$gt\" : \"20161001\" , \"$lt\" : \"20161030\" } } If there is less than 100 events, the response next field will be false and there is nothing more to do. If there is more than 100 events for this month, we have a next=true in the response. To keep iterating, we can use the bookmark field we received in the next request. \"selector\" : { \"calendar\" : \"my-calendar\" , \"date\" : { \"$gte\" : \"20161001\" , \"$lt\" : \"20161030\" } } , \"bookmark\" : \"g1AAAAB2eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYorGKQYpVqaJRoZm1paWFiapFkamhknGpilJiampZkYJRmC9HHA9OUAdTASpS0rCwAlah76\"", "title": "Example:"}, {"location": "cozy-stack/move-design/", "text": "Table of contents Move design \u00b6 \u201cYou will stay because you can leave\u201d - Cozy. We have made this important promise to our users, and moving a Cozy to a new hoster/address is a big part of it. That\u2019s why we have tried hard to make it smooth and robust. It means that we had to manage some complex special cases. This document is here to keep a trace of them. But, first, let\u2019s define what moving a Cozy means. When you have an instance, the \u201csource\u201d, and another instance, the \u201ctarget\u201d, the user can move their usage from the source to the target. The data is exported from the source instance, and imported on the target instance. But there is more than that. For example, the Cozy to Cozy sharings ( documentation ) will be updated to work the target instance instead of the source instance. Workflows \u00b6 Technically, a new component called Cozy-Move was created. It is a web application in Elixir/Phoenix that can be seen as a wizard to help users select from which instance and to which instance they want to move. It is possible to send a mail with a link to cozy-move, and put this link in a FAQ, and users can start the process from this link. But, if a user wants to initiate a move by them-self, they will start from the settings of their Cozy. The two workflows are available. Starting from settings \u00b6 Starting from cozy-move \u00b6 Notes \u00b6 For security, we need an interaction of the user with both instances (even if the user is already logged). There is a confirmation mail sent by the source Cozy, that counts as a interaction. For the target Cozy, a click on a page served by the stack could have been enough, but asking the password was easier to explain to the user and improve the sense of security as perceived by the user, so that was what we did. And we had to take care of that to allow or forbid swapping instances on Cozy-Move. The token exchanges are inspired by OAuth 2.0, but don\u2019t follow OAuth 2.0 as it would have made the user experience really awkwards with lots of redirections and meaningless screens. The confirmation mail is really important, as it is a safeguard if the worflows are not as robust as we think they are. Source instance \u00b6 Exporting the data from a Cozy was a feature already implemented in the stack. The user can ask an export of their Cozy: the stack will send a mail with a link, and after following the link, the user can download the data as a zip. If the VFS ( Virtual File System ) takes a lot of space, the zip will be split in several parts. When an export if part of a move, the instance is blocked to avoid any change that could increase the risk of inconsistencies during the move. And, if the move is successful, the OAuth clients are revoked to encourage the user to reconnect them on the target. Also, the source instance will be destroyed 30 days later. It gives time to the user to check that every thing is OK on their new instance, and can be used to alert other users that want to see a page shared by link of the new address of the sharing. Zip vs Tar \u00b6 The export produces a zip file (or several files if it is too large). But the stack first makes a tar file while preparing the export. At first, it looks strange, but we though that a zip will be more friendly for users, and a tar is more adapted to our constraints. A tar can be read sequentially while a zip needs random access, and it was easier to stream a tar from Swift and converts it to zip, than trying to add entries to a zip file (and we didn\u2019t want to copy the whole files from the VFS in the zip in Swift as it takes too much space). Target instance \u00b6 Importing a zip can also be done before moving: the user can go in the settings of their Cozy, gives the URL of the zip, and let the Cozy imports it. The Cozy is reset before the import: the data is erased! We would like to offer a way to merge the existing data and the data to import, but it looks really complex and we think that it is more useful to use our time on other features. At the end of the import, a mail is sent to the user to tell them that they can use again their Cozy (the instance is blocked during the reset+import). Special doctypes \u00b6 Apps \u00b6 The home, settings, and store applications are always installed on the target Cozy. And we also try to install all the webapps and konnectors from the source, but it can fail as they might not be available (e.g. the 2 Cozys don\u2019t have the same apps registry). In that case, the user will be alerted in the mail sent at the end of the import. For the permissions, we recreate them from the manifest and don\u2019t try to import them from the source instance. Email address \u00b6 The email address on the target instance is kept. We don\u2019t import the email address the user had on their source instance. The stack also keep other settings that are tied to the cloudery (UUID, ToS, context). We also update the myself document with the kept email address. Files \u00b6 The directories, files, and versions are imported. The thumbnails are not exported/imported, but rebuilt on the target instance. If the quota of the target is too small for the files from the source, we alert the user before the move. Konnectors \u00b6 See the apps section. For konnectors that have a on_delete_accounts hook, we have to use some tricks: we delete the accounts on the target instance for the reset while the instance is blocked, but the konnectors can still make requests to the stack for those executions (allowed via a flag in redis) the accounts from the source instance are not imported on the target, as they will be useless soon (when they will be deleted by the source). Sessions \u00b6 They are not imported. Sharings \u00b6 For the shared by links, we import the permission document. But the link given to other users will still go on the old instance. While this instance is not deleted, it will show a page that gives the new link. For the Cozy to Cozy sharings, the stack has a mechanism for updating them so that the other instances will now synchronize with the target. It is a bit complicated as we have to make it work if several members of a sharing has moving at the same time, and as the JWT tokens are tied to an instance and have to be renewed (access token & refresh token). Triggers \u00b6 We import the triggers for the sharings and konnectors. For the apps (services), they are recreated when installed. The trigger for the thumbnails is also recreated when the instance is reset (not imported). Note: the triggers are imported at the end to avoid creating many jobs when importing the shared files. Vault \u00b6 The bitwarden vault is encrypted with a key not available on the servers (on purpose). It makes difficult to move it automatically, but the stack can detect if the vault has been used, and in that case, show instructions to export and import the passwords.", "title": "Move design"}, {"location": "cozy-stack/move-design/#move-design", "text": "\u201cYou will stay because you can leave\u201d - Cozy. We have made this important promise to our users, and moving a Cozy to a new hoster/address is a big part of it. That\u2019s why we have tried hard to make it smooth and robust. It means that we had to manage some complex special cases. This document is here to keep a trace of them. But, first, let\u2019s define what moving a Cozy means. When you have an instance, the \u201csource\u201d, and another instance, the \u201ctarget\u201d, the user can move their usage from the source to the target. The data is exported from the source instance, and imported on the target instance. But there is more than that. For example, the Cozy to Cozy sharings ( documentation ) will be updated to work the target instance instead of the source instance.", "title": "Move design"}, {"location": "cozy-stack/move-design/#workflows", "text": "Technically, a new component called Cozy-Move was created. It is a web application in Elixir/Phoenix that can be seen as a wizard to help users select from which instance and to which instance they want to move. It is possible to send a mail with a link to cozy-move, and put this link in a FAQ, and users can start the process from this link. But, if a user wants to initiate a move by them-self, they will start from the settings of their Cozy. The two workflows are available.", "title": "Workflows"}, {"location": "cozy-stack/move-design/#starting-from-settings", "text": "", "title": "Starting from settings"}, {"location": "cozy-stack/move-design/#starting-from-cozy-move", "text": "", "title": "Starting from cozy-move"}, {"location": "cozy-stack/move-design/#notes", "text": "For security, we need an interaction of the user with both instances (even if the user is already logged). There is a confirmation mail sent by the source Cozy, that counts as a interaction. For the target Cozy, a click on a page served by the stack could have been enough, but asking the password was easier to explain to the user and improve the sense of security as perceived by the user, so that was what we did. And we had to take care of that to allow or forbid swapping instances on Cozy-Move. The token exchanges are inspired by OAuth 2.0, but don\u2019t follow OAuth 2.0 as it would have made the user experience really awkwards with lots of redirections and meaningless screens. The confirmation mail is really important, as it is a safeguard if the worflows are not as robust as we think they are.", "title": "Notes"}, {"location": "cozy-stack/move-design/#source-instance", "text": "Exporting the data from a Cozy was a feature already implemented in the stack. The user can ask an export of their Cozy: the stack will send a mail with a link, and after following the link, the user can download the data as a zip. If the VFS ( Virtual File System ) takes a lot of space, the zip will be split in several parts. When an export if part of a move, the instance is blocked to avoid any change that could increase the risk of inconsistencies during the move. And, if the move is successful, the OAuth clients are revoked to encourage the user to reconnect them on the target. Also, the source instance will be destroyed 30 days later. It gives time to the user to check that every thing is OK on their new instance, and can be used to alert other users that want to see a page shared by link of the new address of the sharing.", "title": "Source instance"}, {"location": "cozy-stack/move-design/#zip-vs-tar", "text": "The export produces a zip file (or several files if it is too large). But the stack first makes a tar file while preparing the export. At first, it looks strange, but we though that a zip will be more friendly for users, and a tar is more adapted to our constraints. A tar can be read sequentially while a zip needs random access, and it was easier to stream a tar from Swift and converts it to zip, than trying to add entries to a zip file (and we didn\u2019t want to copy the whole files from the VFS in the zip in Swift as it takes too much space).", "title": "Zip vs Tar"}, {"location": "cozy-stack/move-design/#target-instance", "text": "Importing a zip can also be done before moving: the user can go in the settings of their Cozy, gives the URL of the zip, and let the Cozy imports it. The Cozy is reset before the import: the data is erased! We would like to offer a way to merge the existing data and the data to import, but it looks really complex and we think that it is more useful to use our time on other features. At the end of the import, a mail is sent to the user to tell them that they can use again their Cozy (the instance is blocked during the reset+import).", "title": "Target instance"}, {"location": "cozy-stack/move-design/#special-doctypes", "text": "", "title": "Special doctypes"}, {"location": "cozy-stack/move-design/#apps", "text": "The home, settings, and store applications are always installed on the target Cozy. And we also try to install all the webapps and konnectors from the source, but it can fail as they might not be available (e.g. the 2 Cozys don\u2019t have the same apps registry). In that case, the user will be alerted in the mail sent at the end of the import. For the permissions, we recreate them from the manifest and don\u2019t try to import them from the source instance.", "title": "Apps"}, {"location": "cozy-stack/move-design/#email-address", "text": "The email address on the target instance is kept. We don\u2019t import the email address the user had on their source instance. The stack also keep other settings that are tied to the cloudery (UUID, ToS, context). We also update the myself document with the kept email address.", "title": "Email address"}, {"location": "cozy-stack/move-design/#files", "text": "The directories, files, and versions are imported. The thumbnails are not exported/imported, but rebuilt on the target instance. If the quota of the target is too small for the files from the source, we alert the user before the move.", "title": "Files"}, {"location": "cozy-stack/move-design/#konnectors", "text": "See the apps section. For konnectors that have a on_delete_accounts hook, we have to use some tricks: we delete the accounts on the target instance for the reset while the instance is blocked, but the konnectors can still make requests to the stack for those executions (allowed via a flag in redis) the accounts from the source instance are not imported on the target, as they will be useless soon (when they will be deleted by the source).", "title": "Konnectors"}, {"location": "cozy-stack/move-design/#sessions", "text": "They are not imported.", "title": "Sessions"}, {"location": "cozy-stack/move-design/#sharings", "text": "For the shared by links, we import the permission document. But the link given to other users will still go on the old instance. While this instance is not deleted, it will show a page that gives the new link. For the Cozy to Cozy sharings, the stack has a mechanism for updating them so that the other instances will now synchronize with the target. It is a bit complicated as we have to make it work if several members of a sharing has moving at the same time, and as the JWT tokens are tied to an instance and have to be renewed (access token & refresh token).", "title": "Sharings"}, {"location": "cozy-stack/move-design/#triggers", "text": "We import the triggers for the sharings and konnectors. For the apps (services), they are recreated when installed. The trigger for the thumbnails is also recreated when the instance is reset (not imported). Note: the triggers are imported at the end to avoid creating many jobs when importing the shared files.", "title": "Triggers"}, {"location": "cozy-stack/move-design/#vault", "text": "The bitwarden vault is encrypted with a key not available on the servers (on purpose). It makes difficult to move it automatically, but the stack can detect if the vault has been used, and in that case, show instructions to export and import the passwords.", "title": "Vault"}, {"location": "cozy-stack/move/", "text": "Table of contents Move, export and import \u00b6 Export \u00b6 A Cozy\u2019s user can ask at any time to export a snapshot of all its data and metadata. This export takes place asynchronously and is separated in two parts: a metadata tarball containing the in a JSON format all the doctypes multi-part files tarballs containing the files (or a subpart of the files). The export process is part of a worker described in the workers section of the documentation. Endpoints described in this documentation require a permission on the io.cozy.exports doctype. POST /move/exports \u00b6 This endpoint can be used to create a new export job. Exports options fields are: parts_size (optional) (int): the size in bytes of a tarball files part. max_age (optional) (duration / nanosecs): the maximum age of the export data. with_doctypes (optional) (string array): the list of exported doctypes Request \u00b6 POST /move/exports HTTP / 1.1 Host : source.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"parts_size\" : 10240 , \"with_doctypes\" : [] } } } GET /move/exports/:opaque-identifier \u00b6 This endpoint can be used to fetch the metadata of an export. Exports fields are: parts_size (int): the size in bytes of a tarball files part. parts_cursors (string array): the list of cursors to access to the different files parts. with_doctypes (string array): the list of exported doctypes (if empty of null, all doctypes are exported) state (string): the state of the export ( \"exporting\" / \"done\" / \"error\" ). created_at (string / time): the date of creation of the export expires_at (string / time): the date of expiration of the export total_size (int): the total size of the exported documents from CouchDB creation_duration (int): the amount of nanoseconds taken for the creation of the export error (string): an error string if the export is in an \"error\" state Request \u00b6 GET /move/exports/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX HTTP / 1.1 Host : source.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.exports\" , \"id\" : \"86dbb546ca49f0ed1ce0a1ff0d1b15e3\" , \"meta\" : { \"rev\" : \"2-XXX\" }, \"attributes\" : { \"parts_size\" : 10240 , \"parts_cursors\" : [ \"AAA\" , \"BBB\" , \"CCC\" ], \"with_doctypes\" : [], \"state\" : \"done\" , \"created_at\" : \"2018-05-04T08:59:37.530693972+02:00\" , \"expires_at\" : \"2018-05-11T08:59:37.530693972+02:00\" , \"total_size\" : 1123 , \"creation_duration\" : 62978511 , \"error\" : \"\" } } } GET /move/exports/data/:opaque-identifier?cursor=XXX \u00b6 This endpoint will download an archive containing the metadata and files of the user, as part of a multi-part download. The cursor given should be one of the defined in the export document parts_cursors . Only the first part of the archive contains the metadata. To get all the parts, this endpoint must be called one time with no cursor, and one time for each cursor in parts_cursors . Import \u00b6 POST /move/imports/precheck \u00b6 This endpoint can be use to check that an export can be imported from the given URL, before doing the real import. It is called from the settings application, not from the cozy-move wizard. Request \u00b6 POST /move/imports/precheck HTTP / 1.1 Host : destination.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"url\" : \"https://settings.source.cozy.localhost/#/exports/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\" } } } Responses \u00b6 204 No Content if every thing is fine 412 Precondition Failed if no archive can be found at the given URL 422 Entity Too Large if the quota is too small to import the files POST /move/imports \u00b6 This endpoint can be used to really start an import. Request \u00b6 POST /move/imports HTTP / 1.1 Host : destination.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"url\" : \"https://settings.source.cozy.localhost/#/exports/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\" } } } Responses \u00b6 HTTP / 1.1 303 See Other Location : https://destination.cozy.localhost/move/importing POST /move/importing \u00b6 This endpoint is called on the target Cozy by the source Cozy to block the instance during the move. A source parameter can be put in the query-string, with the domain of the Cozy source (for information). GET /move/importing \u00b6 This shows a page for the user to wait that the import finishes. GET /move/importing/realtime \u00b6 This is a websocket endpoint that can be used to wait for the end of the import. The server will send an event when it is done (or errored): server> {\"redirect\": \"http://cozy.localhost:8080/auth/login\"} GET /move/authorize \u00b6 This endpoint is used by cozy-move to select the cozy source. If the user is already logged in, we don\u2019t ask its password again, as the delivered token will still need a confirmation by mail to start moving the Cozy. Request \u00b6 GET /move/authorize?state=8d560d60&redirect_uri=https://move.cozycloud.cc/callback/source HTTP / 1.1 Server : source.cozy.localhost Response \u00b6 HTTP / 1.1 302 Found Location : https://move.cozycloud.cc/callback/source?code=543d7eb8149c&used=123456"a=5000000&state=8d560d60&vault=false POST /move/initialize \u00b6 This endpoint is used by the settings application to open the move wizard. Request \u00b6 POST /move/initialize HTTP / 1.1 Host : source.cozy.localhost Response \u00b6 HTTP / 1.1 307 Temporary Redirect Location : https://move.cozycloud.cc/initialize?code=834d7eb8149c&cozy_url=https://source.cozy.localhost&used=123456"a=5000000&client_id=09136b00-1778-0139-f0a7-543d7eb8149c&client_secret=NDkyZTEzMDA&vault=false POST /move/request \u00b6 This endpoint is used after the user has selected both instances on cozy-move to prepare the export and send the confirmation mail. Request \u00b6 POST /move/request HTTP / 1.1 Content-Type : application/x-www-form-urlencoded code=834d7eb8149c &target_url=https://target.cozy.localhost/ &target_token=M2EwYjlhZjAtMTc3OC0wMTM5LWYwYWMtNTQzZDdlYjgxNDlj &target_client_id=09136b00-1778-0139-f0a7-543d7eb8149c &target_client_secret=NDkyZTEzMDA Note: instead of code , we can have token , client_id , and client_secret (depending if the user has started the workflow from the settings app or from cozy-move). Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/html GET /move/go \u00b6 This endpoint is used to confirm the move. It will ask the other Cozy to block its-self during the move and pushs a job for the export. Request \u00b6 GET /move/go?secret=tNTQzZDdlYjgxNDlj HTTP / 1.1 Host : source.cozy.localhost Reponse \u00b6 HTTP / 1.1 303 See Other Location : https://target.cozy.localhost/move/importing POST /move/finalize \u00b6 When the move has finished successfully, the target Cozy calls this endpoint on the source Cozy so that it can stop the konnectors and unblock the instance. Request \u00b6 POST /move/finalize?subdomain=flat HTTP / 1.1 Host : source.cozy.localhost Reponse \u00b6 HTTP/1.1 204 No Content POST /move/abort \u00b6 If the export or the import fails during a move, the stack will call this endpoint for the other instance to unblock it. Request \u00b6 POST /move/abort HTTP / 1.1 Host : source.cozy.localhost Reponse \u00b6 HTTP/1.1 204 No Content GET /move/vault \u00b6 This shows a page for the user with instructions about how to import their vault.", "title": "/move - Move, export and import an instance"}, {"location": "cozy-stack/move/#move-export-and-import", "text": "", "title": "Move, export and import"}, {"location": "cozy-stack/move/#export", "text": "A Cozy\u2019s user can ask at any time to export a snapshot of all its data and metadata. This export takes place asynchronously and is separated in two parts: a metadata tarball containing the in a JSON format all the doctypes multi-part files tarballs containing the files (or a subpart of the files). The export process is part of a worker described in the workers section of the documentation. Endpoints described in this documentation require a permission on the io.cozy.exports doctype.", "title": "Export"}, {"location": "cozy-stack/move/#post-moveexports", "text": "This endpoint can be used to create a new export job. Exports options fields are: parts_size (optional) (int): the size in bytes of a tarball files part. max_age (optional) (duration / nanosecs): the maximum age of the export data. with_doctypes (optional) (string array): the list of exported doctypes", "title": "POST /move/exports"}, {"location": "cozy-stack/move/#request", "text": "POST /move/exports HTTP / 1.1 Host : source.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"parts_size\" : 10240 , \"with_doctypes\" : [] } } }", "title": "Request"}, {"location": "cozy-stack/move/#get-moveexportsopaque-identifier", "text": "This endpoint can be used to fetch the metadata of an export. Exports fields are: parts_size (int): the size in bytes of a tarball files part. parts_cursors (string array): the list of cursors to access to the different files parts. with_doctypes (string array): the list of exported doctypes (if empty of null, all doctypes are exported) state (string): the state of the export ( \"exporting\" / \"done\" / \"error\" ). created_at (string / time): the date of creation of the export expires_at (string / time): the date of expiration of the export total_size (int): the total size of the exported documents from CouchDB creation_duration (int): the amount of nanoseconds taken for the creation of the export error (string): an error string if the export is in an \"error\" state", "title": "GET /move/exports/:opaque-identifier"}, {"location": "cozy-stack/move/#request_1", "text": "GET /move/exports/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX HTTP / 1.1 Host : source.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.exports\" , \"id\" : \"86dbb546ca49f0ed1ce0a1ff0d1b15e3\" , \"meta\" : { \"rev\" : \"2-XXX\" }, \"attributes\" : { \"parts_size\" : 10240 , \"parts_cursors\" : [ \"AAA\" , \"BBB\" , \"CCC\" ], \"with_doctypes\" : [], \"state\" : \"done\" , \"created_at\" : \"2018-05-04T08:59:37.530693972+02:00\" , \"expires_at\" : \"2018-05-11T08:59:37.530693972+02:00\" , \"total_size\" : 1123 , \"creation_duration\" : 62978511 , \"error\" : \"\" } } }", "title": "Request"}, {"location": "cozy-stack/move/#get-moveexportsdataopaque-identifiercursorxxx", "text": "This endpoint will download an archive containing the metadata and files of the user, as part of a multi-part download. The cursor given should be one of the defined in the export document parts_cursors . Only the first part of the archive contains the metadata. To get all the parts, this endpoint must be called one time with no cursor, and one time for each cursor in parts_cursors .", "title": "GET /move/exports/data/:opaque-identifier?cursor=XXX"}, {"location": "cozy-stack/move/#import", "text": "", "title": "Import"}, {"location": "cozy-stack/move/#post-moveimportsprecheck", "text": "This endpoint can be use to check that an export can be imported from the given URL, before doing the real import. It is called from the settings application, not from the cozy-move wizard.", "title": "POST /move/imports/precheck"}, {"location": "cozy-stack/move/#request_2", "text": "POST /move/imports/precheck HTTP / 1.1 Host : destination.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"url\" : \"https://settings.source.cozy.localhost/#/exports/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\" } } }", "title": "Request"}, {"location": "cozy-stack/move/#responses", "text": "204 No Content if every thing is fine 412 Precondition Failed if no archive can be found at the given URL 422 Entity Too Large if the quota is too small to import the files", "title": "Responses"}, {"location": "cozy-stack/move/#post-moveimports", "text": "This endpoint can be used to really start an import.", "title": "POST /move/imports"}, {"location": "cozy-stack/move/#request_3", "text": "POST /move/imports HTTP / 1.1 Host : destination.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"url\" : \"https://settings.source.cozy.localhost/#/exports/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\" } } }", "title": "Request"}, {"location": "cozy-stack/move/#responses_1", "text": "HTTP / 1.1 303 See Other Location : https://destination.cozy.localhost/move/importing", "title": "Responses"}, {"location": "cozy-stack/move/#post-moveimporting", "text": "This endpoint is called on the target Cozy by the source Cozy to block the instance during the move. A source parameter can be put in the query-string, with the domain of the Cozy source (for information).", "title": "POST /move/importing"}, {"location": "cozy-stack/move/#get-moveimporting", "text": "This shows a page for the user to wait that the import finishes.", "title": "GET /move/importing"}, {"location": "cozy-stack/move/#get-moveimportingrealtime", "text": "This is a websocket endpoint that can be used to wait for the end of the import. The server will send an event when it is done (or errored): server> {\"redirect\": \"http://cozy.localhost:8080/auth/login\"}", "title": "GET /move/importing/realtime"}, {"location": "cozy-stack/move/#get-moveauthorize", "text": "This endpoint is used by cozy-move to select the cozy source. If the user is already logged in, we don\u2019t ask its password again, as the delivered token will still need a confirmation by mail to start moving the Cozy.", "title": "GET /move/authorize"}, {"location": "cozy-stack/move/#request_4", "text": "GET /move/authorize?state=8d560d60&redirect_uri=https://move.cozycloud.cc/callback/source HTTP / 1.1 Server : source.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/move/#response", "text": "HTTP / 1.1 302 Found Location : https://move.cozycloud.cc/callback/source?code=543d7eb8149c&used=123456"a=5000000&state=8d560d60&vault=false", "title": "Response"}, {"location": "cozy-stack/move/#post-moveinitialize", "text": "This endpoint is used by the settings application to open the move wizard.", "title": "POST /move/initialize"}, {"location": "cozy-stack/move/#request_5", "text": "POST /move/initialize HTTP / 1.1 Host : source.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/move/#response_1", "text": "HTTP / 1.1 307 Temporary Redirect Location : https://move.cozycloud.cc/initialize?code=834d7eb8149c&cozy_url=https://source.cozy.localhost&used=123456"a=5000000&client_id=09136b00-1778-0139-f0a7-543d7eb8149c&client_secret=NDkyZTEzMDA&vault=false", "title": "Response"}, {"location": "cozy-stack/move/#post-moverequest", "text": "This endpoint is used after the user has selected both instances on cozy-move to prepare the export and send the confirmation mail.", "title": "POST /move/request"}, {"location": "cozy-stack/move/#request_6", "text": "POST /move/request HTTP / 1.1 Content-Type : application/x-www-form-urlencoded code=834d7eb8149c &target_url=https://target.cozy.localhost/ &target_token=M2EwYjlhZjAtMTc3OC0wMTM5LWYwYWMtNTQzZDdlYjgxNDlj &target_client_id=09136b00-1778-0139-f0a7-543d7eb8149c &target_client_secret=NDkyZTEzMDA Note: instead of code , we can have token , client_id , and client_secret (depending if the user has started the workflow from the settings app or from cozy-move).", "title": "Request"}, {"location": "cozy-stack/move/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/html", "title": "Response"}, {"location": "cozy-stack/move/#get-movego", "text": "This endpoint is used to confirm the move. It will ask the other Cozy to block its-self during the move and pushs a job for the export.", "title": "GET /move/go"}, {"location": "cozy-stack/move/#request_7", "text": "GET /move/go?secret=tNTQzZDdlYjgxNDlj HTTP / 1.1 Host : source.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/move/#reponse", "text": "HTTP / 1.1 303 See Other Location : https://target.cozy.localhost/move/importing", "title": "Reponse"}, {"location": "cozy-stack/move/#post-movefinalize", "text": "When the move has finished successfully, the target Cozy calls this endpoint on the source Cozy so that it can stop the konnectors and unblock the instance.", "title": "POST /move/finalize"}, {"location": "cozy-stack/move/#request_8", "text": "POST /move/finalize?subdomain=flat HTTP / 1.1 Host : source.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/move/#reponse_1", "text": "HTTP/1.1 204 No Content", "title": "Reponse"}, {"location": "cozy-stack/move/#post-moveabort", "text": "If the export or the import fails during a move, the stack will call this endpoint for the other instance to unblock it.", "title": "POST /move/abort"}, {"location": "cozy-stack/move/#request_9", "text": "POST /move/abort HTTP / 1.1 Host : source.cozy.localhost", "title": "Request"}, {"location": "cozy-stack/move/#reponse_2", "text": "HTTP/1.1 204 No Content", "title": "Reponse"}, {"location": "cozy-stack/move/#get-movevault", "text": "This shows a page for the user with instructions about how to import their vault.", "title": "GET /move/vault"}, {"location": "cozy-stack/nextcloud/", "text": "Table of contents Proxy for a remote NextCloud \u00b6 The nextcloud konnector can be used to create an io.cozy.account for a NextCloud. Then, the stack can be used as a client for this NextCloud account. Currently, it supports files operations via WebDAV. GET /remote/nextcloud/:account/*path \u00b6 This route can be used to list the files and subdirectories inside a directory of NextCloud. With Dl=1 in the query-string, it can also be used to download a file. The :account parameter is the identifier of the NextCloud io.cozy.account . It is available with the cozyMetadata.sourceAccount of the shortcut file for example. The *path parameter is the path of the file/directory on the NextCloud. Note: a permission on GET io.cozy.files is required to use this route. Request (list) \u00b6 GET /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response (list) \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"192172\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Images\" , \"path\" : \"/Documents/Images\" , \"updated_at\" : \"Thu, 02 May 2024 09:29:53 GMT\" , \"etag\" : \"\\\"66335d11c4b91\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/192172?dir=/Documents\" } }, { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"208937\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"BugBounty.pdf\" , \"path\" : \"/Documents/BugBounty.pdf\" , \"size\" : 2947 , \"mime\" : \"application/pdf\" , \"class\" : \"pdf\" , \"updated_at\" : \"Mon, 14 Jan 2019 08:22:21 GMT\" , \"etag\" : \"\\\"dd1a602431671325b7c1538f829248d9\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/208937?dir=/Documents\" } }, { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"615827\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Music\" , \"name\" : \"/Documents/Music\" , \"updated_at\" : \"Thu, 02 May 2024 09:28:37 GMT\" , \"etag\" : \"\\\"66335cc55204b\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/615827?dir=/Documents\" } }, { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"615828\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Video\" , \"path\" : \"/Documents/Video\" , \"updated_at\" : \"Thu, 02 May 2024 09:29:53 GMT\" , \"etag\" : \"\\\"66335d11c2318\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/615828?dir=/Documents\" } } ], \"meta\" : { \"count\" : 5 } } Request (download) \u00b6 GET /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Wallpaper.jpg?Dl=1 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response (download) \u00b6 HTTP / 1.1 200 OK Content-Type : image/jpeg Content-Length : 12345 Content-Disposition : attachment; filename=\"Wallpaper.jpg\" ... Status codes \u00b6 200 OK, for a success 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the directory is not found on the NextCloud PUT /remote/nextcloud/:account/*path \u00b6 This route can be used to create a directory, or upload a file, on the NextCloud. The query-string parameter Type should be file when uploading a file. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file/directory on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route. Request (directory) \u00b6 PUT /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Images/Clouds?Type=directory HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response (directory) \u00b6 HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true } Request (file) \u00b6 PUT /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Images/sunset.jpg?Type=file HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Content-Type : image/jpeg Content-Length : 54321 ... Response (file) \u00b6 HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true } Status codes \u00b6 201 Created, when the directory has been created 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the parent directory is not found on the NextCloud 409 Conflict, when a directory or file already exists at this path on the NextCloud. DELETE /remote/nextcloud/:account/*path \u00b6 This route can be used to put a file or directory in the NextCloud trash. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file/directory on the NextCloud. Note: a permission on DELETE io.cozy.files is required to use this route. Request \u00b6 DELETE /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Images/Clouds HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 204 No Content Status codes \u00b6 204 No Content, when the file/directory has been put in the trash 400 Bad Request, when the account is not configured for NextCloud, or the To parameter is missing 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud POST /remote/nextcloud/:account/move/*path \u00b6 This route can be used to move or rename a file/directory on the NextCloud. The new path must be given with the To parameter in the query-string. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route. Request \u00b6 POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/move/Documents/wallpaper.jpg?To=/Wallpaper.jpg HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 204 No Content Status codes \u00b6 204 No Content, when the file/directory has been moved 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud 409 Conflict, when a file already exists with the new name on the NextCloud. POST /remote/nextcloud/:account/copy/*path \u00b6 This route can be used to create a copy of a file in the same directory, with a copy suffix in its name. The new name can be optionaly given with the Name parameter in the query-string, or the full path can be given with Path parameter. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route. Request \u00b6 POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/copy/Documents/wallpaper.jpg?Path=/Images/beach.jpg HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true } Status codes \u00b6 201 Created, when the file has been copied 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud 409 Conflict, when a file already exists with the new name on the NextCloud. POST /remote/nextcloud/:account/downstream/*path \u00b6 This route can be used to move/copy a file from the NextCloud to the Cozy. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. The To parameter in the query-string must be given, as the ID of the directory on the Cozy where the file will be put. By default, the file will be moved, but using Copy=true in the query-string will makes a copy. Note: a permission on POST io.cozy.files is required to use this route. Request \u00b6 POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/downstream/Documents/Images/sunset.jpg?To=b3ecbc00f4ba013c2bf418c04daba326 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"7b41fb7c31e87eeaf13a54bc32001830\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"sunset.jpg\" , \"dir_id\" : \"b3ecbc00f4ba013c2bf418c04daba326\" , \"created_at\" : \"2024-05-15T09:24:39.460655706+02:00\" , \"updated_at\" : \"2024-05-15T09:24:39.460655706+02:00\" , \"size\" : \"54321\" , \"md5sum\" : \"1B2M2Y8AsgTpgAmY7PhCfg==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"encrypted\" : false , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2024-05-15T09:24:38.971901347+02:00\" , \"updatedAt\" : \"2024-05-15T09:24:38.971901347+02:00\" , \"createdOn\" : \"https://cozy.example.net/\" , \"uploadedAt\" : \"2024-05-15T09:24:38.971901347+02:00\" , \"uploadedOn\" : \"https://cozy.example.net/\" } }, \"meta\" : { \"rev\" : \"1-cfed435c4ad72b911b31ed775e3024df\" }, \"links\" : { \"self\" : \"/files/7b41fb7c31e87eeaf13a54bc32001830\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/b3ecbc00f4ba013c2bf418c04daba326\" }, \"data\" : { \"id\" : \"b3ecbc00f4ba013c2bf418c04daba326\" , \"type\" : \"io.cozy.files\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/7b41fb7c31e87eeaf13a54bc32001830/relationships/references\" } } } } } Status codes \u00b6 201 Created, when the file has been moved from the NextCloud to the Cozy 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file is not found on the NextCloud POST /remote/nextcloud/:account/upstream/*path \u00b6 This route can be used to move/copy a file from the Cozy to the NextCloud. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. The From parameter in the query-string must be given, as the ID of the file on the Cozy that will be moved. By default, the file will be moved, but using Copy=true in the query-string will makes a copy. Note: a permission on POST io.cozy.files is required to use this route. Request \u00b6 POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/upstream/Documents/Images/sunset2.jpg?From=7b41fb7c31e87eeaf13a54bc32001830 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 204 No Content Status codes \u00b6 204 No Content, when the file has been moved from the Cozy to the NextCloud 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file is not found on the Cozy GET /remote/nextcloud/:account/trash/* \u00b6 This route can be used to list the files and directories inside the trashbin of NextCloud. Request (list) \u00b6 GET /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/trash/ HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response (list) \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"613281\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Old\" , \"path\" : \"/trash/Old.d93571568\" , \"updated_at\" : \"Tue, 25 Jun 2024 14:31:44 GMT\" , \"etag\" : \"1719326384\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/trashbin/613281?dir=/Old\" } } ] } Status codes \u00b6 200 OK, for a success 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the directory is not found on the NextCloud POST /remote/nextcloud/:account/restore/*path \u00b6 This route can be used to restore a file/directory from the trashbin on the NextCloud. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route. Request \u00b6 POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/restore/trash/Old.d93571568 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 204 No Content Status codes \u00b6 204 No Content, when the file/directory has been restored 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud 409 Conflict, when a directory or file already exists where the file/directory should be restored on the NextCloud. DELETE /remote/nextcloud/:account/trash/* \u00b6 This route can be used to delete a file in the trash. Request \u00b6 DELETE /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/trash/document-v1.docx.d64283654 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 204 No Content Status codes \u00b6 204 No Content, when the file/directory has been put in the trash 400 Bad Request, when the account is not configured for NextCloud, or the To parameter is missing 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud DELETE /remote/nextcloud/:account/trash \u00b6 This route can be used to empty the trash bin on NextCloud. Request \u00b6 DELETE /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/trash HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Response \u00b6 HTTP / 1.1 204 No Content", "title": " /remote/nextcloud - NextCloud"}, {"location": "cozy-stack/nextcloud/#proxy-for-a-remote-nextcloud", "text": "The nextcloud konnector can be used to create an io.cozy.account for a NextCloud. Then, the stack can be used as a client for this NextCloud account. Currently, it supports files operations via WebDAV.", "title": "Proxy for a remote NextCloud"}, {"location": "cozy-stack/nextcloud/#get-remotenextcloudaccountpath", "text": "This route can be used to list the files and subdirectories inside a directory of NextCloud. With Dl=1 in the query-string, it can also be used to download a file. The :account parameter is the identifier of the NextCloud io.cozy.account . It is available with the cozyMetadata.sourceAccount of the shortcut file for example. The *path parameter is the path of the file/directory on the NextCloud. Note: a permission on GET io.cozy.files is required to use this route.", "title": "GET /remote/nextcloud/:account/*path"}, {"location": "cozy-stack/nextcloud/#request-list", "text": "GET /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request (list)"}, {"location": "cozy-stack/nextcloud/#response-list", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"192172\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Images\" , \"path\" : \"/Documents/Images\" , \"updated_at\" : \"Thu, 02 May 2024 09:29:53 GMT\" , \"etag\" : \"\\\"66335d11c4b91\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/192172?dir=/Documents\" } }, { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"208937\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"BugBounty.pdf\" , \"path\" : \"/Documents/BugBounty.pdf\" , \"size\" : 2947 , \"mime\" : \"application/pdf\" , \"class\" : \"pdf\" , \"updated_at\" : \"Mon, 14 Jan 2019 08:22:21 GMT\" , \"etag\" : \"\\\"dd1a602431671325b7c1538f829248d9\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/208937?dir=/Documents\" } }, { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"615827\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Music\" , \"name\" : \"/Documents/Music\" , \"updated_at\" : \"Thu, 02 May 2024 09:28:37 GMT\" , \"etag\" : \"\\\"66335cc55204b\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/615827?dir=/Documents\" } }, { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"615828\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Video\" , \"path\" : \"/Documents/Video\" , \"updated_at\" : \"Thu, 02 May 2024 09:29:53 GMT\" , \"etag\" : \"\\\"66335d11c2318\\\"\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/files/615828?dir=/Documents\" } } ], \"meta\" : { \"count\" : 5 } }", "title": "Response (list)"}, {"location": "cozy-stack/nextcloud/#request-download", "text": "GET /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Wallpaper.jpg?Dl=1 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request (download)"}, {"location": "cozy-stack/nextcloud/#response-download", "text": "HTTP / 1.1 200 OK Content-Type : image/jpeg Content-Length : 12345 Content-Disposition : attachment; filename=\"Wallpaper.jpg\" ...", "title": "Response (download)"}, {"location": "cozy-stack/nextcloud/#status-codes", "text": "200 OK, for a success 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the directory is not found on the NextCloud", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#put-remotenextcloudaccountpath", "text": "This route can be used to create a directory, or upload a file, on the NextCloud. The query-string parameter Type should be file when uploading a file. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file/directory on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route.", "title": "PUT /remote/nextcloud/:account/*path"}, {"location": "cozy-stack/nextcloud/#request-directory", "text": "PUT /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Images/Clouds?Type=directory HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request (directory)"}, {"location": "cozy-stack/nextcloud/#response-directory", "text": "HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true }", "title": "Response (directory)"}, {"location": "cozy-stack/nextcloud/#request-file", "text": "PUT /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Images/sunset.jpg?Type=file HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG... Content-Type : image/jpeg Content-Length : 54321 ...", "title": "Request (file)"}, {"location": "cozy-stack/nextcloud/#response-file", "text": "HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true }", "title": "Response (file)"}, {"location": "cozy-stack/nextcloud/#status-codes_1", "text": "201 Created, when the directory has been created 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the parent directory is not found on the NextCloud 409 Conflict, when a directory or file already exists at this path on the NextCloud.", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#delete-remotenextcloudaccountpath", "text": "This route can be used to put a file or directory in the NextCloud trash. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file/directory on the NextCloud. Note: a permission on DELETE io.cozy.files is required to use this route.", "title": "DELETE /remote/nextcloud/:account/*path"}, {"location": "cozy-stack/nextcloud/#request", "text": "DELETE /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/Documents/Images/Clouds HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/nextcloud/#status-codes_2", "text": "204 No Content, when the file/directory has been put in the trash 400 Bad Request, when the account is not configured for NextCloud, or the To parameter is missing 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#post-remotenextcloudaccountmovepath", "text": "This route can be used to move or rename a file/directory on the NextCloud. The new path must be given with the To parameter in the query-string. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route.", "title": "POST /remote/nextcloud/:account/move/*path"}, {"location": "cozy-stack/nextcloud/#request_1", "text": "POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/move/Documents/wallpaper.jpg?To=/Wallpaper.jpg HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response_1", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/nextcloud/#status-codes_3", "text": "204 No Content, when the file/directory has been moved 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud 409 Conflict, when a file already exists with the new name on the NextCloud.", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#post-remotenextcloudaccountcopypath", "text": "This route can be used to create a copy of a file in the same directory, with a copy suffix in its name. The new name can be optionaly given with the Name parameter in the query-string, or the full path can be given with Path parameter. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route.", "title": "POST /remote/nextcloud/:account/copy/*path"}, {"location": "cozy-stack/nextcloud/#request_2", "text": "POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/copy/Documents/wallpaper.jpg?Path=/Images/beach.jpg HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response_2", "text": "HTTP / 1.1 201 Created Content-Type : application/json { \"ok\" : true }", "title": "Response"}, {"location": "cozy-stack/nextcloud/#status-codes_4", "text": "201 Created, when the file has been copied 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud 409 Conflict, when a file already exists with the new name on the NextCloud.", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#post-remotenextcloudaccountdownstreampath", "text": "This route can be used to move/copy a file from the NextCloud to the Cozy. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. The To parameter in the query-string must be given, as the ID of the directory on the Cozy where the file will be put. By default, the file will be moved, but using Copy=true in the query-string will makes a copy. Note: a permission on POST io.cozy.files is required to use this route.", "title": "POST /remote/nextcloud/:account/downstream/*path"}, {"location": "cozy-stack/nextcloud/#request_3", "text": "POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/downstream/Documents/Images/sunset.jpg?To=b3ecbc00f4ba013c2bf418c04daba326 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response_3", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"7b41fb7c31e87eeaf13a54bc32001830\" , \"attributes\" : { \"type\" : \"file\" , \"name\" : \"sunset.jpg\" , \"dir_id\" : \"b3ecbc00f4ba013c2bf418c04daba326\" , \"created_at\" : \"2024-05-15T09:24:39.460655706+02:00\" , \"updated_at\" : \"2024-05-15T09:24:39.460655706+02:00\" , \"size\" : \"54321\" , \"md5sum\" : \"1B2M2Y8AsgTpgAmY7PhCfg==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"encrypted\" : false , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2024-05-15T09:24:38.971901347+02:00\" , \"updatedAt\" : \"2024-05-15T09:24:38.971901347+02:00\" , \"createdOn\" : \"https://cozy.example.net/\" , \"uploadedAt\" : \"2024-05-15T09:24:38.971901347+02:00\" , \"uploadedOn\" : \"https://cozy.example.net/\" } }, \"meta\" : { \"rev\" : \"1-cfed435c4ad72b911b31ed775e3024df\" }, \"links\" : { \"self\" : \"/files/7b41fb7c31e87eeaf13a54bc32001830\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/b3ecbc00f4ba013c2bf418c04daba326\" }, \"data\" : { \"id\" : \"b3ecbc00f4ba013c2bf418c04daba326\" , \"type\" : \"io.cozy.files\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/7b41fb7c31e87eeaf13a54bc32001830/relationships/references\" } } } } }", "title": "Response"}, {"location": "cozy-stack/nextcloud/#status-codes_5", "text": "201 Created, when the file has been moved from the NextCloud to the Cozy 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file is not found on the NextCloud", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#post-remotenextcloudaccountupstreampath", "text": "This route can be used to move/copy a file from the Cozy to the NextCloud. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. The From parameter in the query-string must be given, as the ID of the file on the Cozy that will be moved. By default, the file will be moved, but using Copy=true in the query-string will makes a copy. Note: a permission on POST io.cozy.files is required to use this route.", "title": "POST /remote/nextcloud/:account/upstream/*path"}, {"location": "cozy-stack/nextcloud/#request_4", "text": "POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/upstream/Documents/Images/sunset2.jpg?From=7b41fb7c31e87eeaf13a54bc32001830 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response_4", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/nextcloud/#status-codes_6", "text": "204 No Content, when the file has been moved from the Cozy to the NextCloud 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file is not found on the Cozy", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#get-remotenextcloudaccounttrash", "text": "This route can be used to list the files and directories inside the trashbin of NextCloud.", "title": "GET /remote/nextcloud/:account/trash/*"}, {"location": "cozy-stack/nextcloud/#request-list_1", "text": "GET /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/trash/ HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request (list)"}, {"location": "cozy-stack/nextcloud/#response-list_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.remote.nextcloud.files\" , \"id\" : \"613281\" , \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"Old\" , \"path\" : \"/trash/Old.d93571568\" , \"updated_at\" : \"Tue, 25 Jun 2024 14:31:44 GMT\" , \"etag\" : \"1719326384\" }, \"meta\" : {}, \"links\" : { \"self\" : \"https://nextcloud.example.net/apps/files/trashbin/613281?dir=/Old\" } } ] }", "title": "Response (list)"}, {"location": "cozy-stack/nextcloud/#status-codes_7", "text": "200 OK, for a success 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the directory is not found on the NextCloud", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#post-remotenextcloudaccountrestorepath", "text": "This route can be used to restore a file/directory from the trashbin on the NextCloud. The :account parameter is the identifier of the NextCloud io.cozy.account . The *path parameter is the path of the file on the NextCloud. Note: a permission on POST io.cozy.files is required to use this route.", "title": "POST /remote/nextcloud/:account/restore/*path"}, {"location": "cozy-stack/nextcloud/#request_5", "text": "POST /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/restore/trash/Old.d93571568 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response_5", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/nextcloud/#status-codes_8", "text": "204 No Content, when the file/directory has been restored 400 Bad Request, when the account is not configured for NextCloud 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud 409 Conflict, when a directory or file already exists where the file/directory should be restored on the NextCloud.", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#delete-remotenextcloudaccounttrash", "text": "This route can be used to delete a file in the trash.", "title": "DELETE /remote/nextcloud/:account/trash/*"}, {"location": "cozy-stack/nextcloud/#request_6", "text": "DELETE /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/trash/document-v1.docx.d64283654 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response_6", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/nextcloud/#status-codes_9", "text": "204 No Content, when the file/directory has been put in the trash 400 Bad Request, when the account is not configured for NextCloud, or the To parameter is missing 401 Unauthorized, when authentication to the NextCloud fails 404 Not Found, when the account is not found or the file/directory is not found on the NextCloud", "title": "Status codes"}, {"location": "cozy-stack/nextcloud/#delete-remotenextcloudaccounttrash_1", "text": "This route can be used to empty the trash bin on NextCloud.", "title": "DELETE /remote/nextcloud/:account/trash"}, {"location": "cozy-stack/nextcloud/#request_7", "text": "DELETE /remote/nextcloud/4ab2155707bb6613a8b9463daf00381b/trash HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbG...", "title": "Request"}, {"location": "cozy-stack/nextcloud/#response_7", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/not-synchronized-vfs/", "text": "Table of contents Not synchronized directories \u00b6 What we want? \u00b6 The directories in the Virtual File System can be ignored for synchronization purpose by some clients. For example, a user may want to not synchronize their Videos directory as it takes too much space for their laptop. Or they may want to not synchronize a directory with personal documents on the desktop owned by their employer. By default, all the directories are synchronized everywhere but it is possible to tell for each directory the devices where the directory won\u2019t be synchronized. The stack tracks this with a not_synchronized_on field on the directory documents. Example \u00b6 { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"meta\" : { \"rev\" : \"1-ff3beeb456eb\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"phone\" , \"path\" : \"/Documents/phone\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" , \"konnectors\" ], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:48Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:48Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"not_synchronized_on\" : { \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on\" }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" } ] } }, \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } } } Routes \u00b6 POST /files/:dir-id/relationships/not_synchronized_on \u00b6 Ask to not synchronize a directory on one or several devices. Request \u00b6 POST /files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"f9ef4dc0-0596-0139-92e0-543d7eb8149c\" } ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"3-485d439530110\" , \"count\" : 2 }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" }, { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"f9ef4dc0-0596-0139-92e0-543d7eb8149c\" } ] } DELETE /files/:file-id/relationships/not_synchronized_on \u00b6 Ask to synchronize again the directory on one or several devices. Request \u00b6 DELETE /files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"f9ef4dc0-0596-0139-92e0-543d7eb8149c\" } ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"4-1f7ef1be3cb\" , \"count\" : 1 }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" } ] } GET /data/:type/:doc-id/relationships/not_synchronizing \u00b6 Returns all the directory ids that are not synchronized on the given device. Contents is paginated following jsonapi conventions . The default limit is 100 entries. The maximal number of entries per page is 1000. It is possible to include the whole documents for the directories by adding include=files to the query string. Request \u00b6 GET /data/io.cozy.oauth.clients/653dfdb0-0595-0139-92df-543d7eb8149c/relationships/not_synchronizing HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"11400320-07b7-0139-4fe8-543d7eb8149c\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } ] } POST /data/:type/:doc-id/relationships/not_synchronizing \u00b6 When configuring a device, it\u2019s tedious to add the not_synchronized_on for each directory individually. This route allows to make it in bulk. Request \u00b6 POST /data/io.cozy.oauth.clients/653dfdb0-0595-0139-92df-543d7eb8149c/relationships/not_synchronizing HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"38086350-07c0-0139-4fe9-543d7eb8149c\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"3d447470-07c0-0139-4fea-543d7eb8149c\" } ] } Response \u00b6 HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json Note : if one of the id is a file, the response will be a 400 Bad Request. References are only for directories. DELETE /data/:type/:doc-id/relationships/not_synchronizing \u00b6 This bulk deletion of not_synchronized_on on many directories can be useful when configuring a device. Request \u00b6 DELETE /data/io.cozy.oauth.clients/653dfdb0-0595-0139-92df-543d7eb8149c/relationships/not_synchronizing HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"38086350-07c0-0139-4fe9-543d7eb8149c\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"3d447470-07c0-0139-4fea-543d7eb8149c\" } ] } Response \u00b6 HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json Usage \u00b6 When an OAuth client makes a request for the changes feed on the io.cozy.files doctype (via /data/io.cozy.files/_changes ), the output will be filtered. If a directory or file is inside a directory with the not_synchronized_on attribute set on for this client, the document will be replaced by a fake entry with _deleted: true .", "title": " /files - Not synchronized directories"}, {"location": "cozy-stack/not-synchronized-vfs/#not-synchronized-directories", "text": "", "title": "Not synchronized directories"}, {"location": "cozy-stack/not-synchronized-vfs/#what-we-want", "text": "The directories in the Virtual File System can be ignored for synchronization purpose by some clients. For example, a user may want to not synchronize their Videos directory as it takes too much space for their laptop. Or they may want to not synchronize a directory with personal documents on the desktop owned by their employer. By default, all the directories are synchronized everywhere but it is possible to tell for each directory the devices where the directory won\u2019t be synchronized. The stack tracks this with a not_synchronized_on field on the directory documents.", "title": "What we want?"}, {"location": "cozy-stack/not-synchronized-vfs/#example", "text": "{ \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" , \"meta\" : { \"rev\" : \"1-ff3beeb456eb\" }, \"attributes\" : { \"type\" : \"directory\" , \"name\" : \"phone\" , \"path\" : \"/Documents/phone\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" , \"konnectors\" ], \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2016-09-20T18:32:48Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2016-09-20T18:32:48Z\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"not_synchronized_on\" : { \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on\" }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" } ] } }, \"links\" : { \"self\" : \"/files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } } }", "title": "Example"}, {"location": "cozy-stack/not-synchronized-vfs/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/not-synchronized-vfs/#post-filesdir-idrelationshipsnot_synchronized_on", "text": "Ask to not synchronize a directory on one or several devices.", "title": "POST /files/:dir-id/relationships/not_synchronized_on"}, {"location": "cozy-stack/not-synchronized-vfs/#request", "text": "POST /files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"f9ef4dc0-0596-0139-92e0-543d7eb8149c\" } ] }", "title": "Request"}, {"location": "cozy-stack/not-synchronized-vfs/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"3-485d439530110\" , \"count\" : 2 }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" }, { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"f9ef4dc0-0596-0139-92e0-543d7eb8149c\" } ] }", "title": "Response"}, {"location": "cozy-stack/not-synchronized-vfs/#delete-filesfile-idrelationshipsnot_synchronized_on", "text": "Ask to synchronize again the directory on one or several devices.", "title": "DELETE /files/:file-id/relationships/not_synchronized_on"}, {"location": "cozy-stack/not-synchronized-vfs/#request_1", "text": "DELETE /files/6494e0ac-dfcb-11e5-88c1-472e84a9cbee/relationships/not_synchronized_on HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"f9ef4dc0-0596-0139-92e0-543d7eb8149c\" } ] }", "title": "Request"}, {"location": "cozy-stack/not-synchronized-vfs/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"4-1f7ef1be3cb\" , \"count\" : 1 }, \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"653dfdb0-0595-0139-92df-543d7eb8149c\" } ] }", "title": "Response"}, {"location": "cozy-stack/not-synchronized-vfs/#get-datatypedoc-idrelationshipsnot_synchronizing", "text": "Returns all the directory ids that are not synchronized on the given device. Contents is paginated following jsonapi conventions . The default limit is 100 entries. The maximal number of entries per page is 1000. It is possible to include the whole documents for the directories by adding include=files to the query string.", "title": "GET /data/:type/:doc-id/relationships/not_synchronizing"}, {"location": "cozy-stack/not-synchronized-vfs/#request_2", "text": "GET /data/io.cozy.oauth.clients/653dfdb0-0595-0139-92df-543d7eb8149c/relationships/not_synchronizing HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/not-synchronized-vfs/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"11400320-07b7-0139-4fe8-543d7eb8149c\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"6494e0ac-dfcb-11e5-88c1-472e84a9cbee\" } ] }", "title": "Response"}, {"location": "cozy-stack/not-synchronized-vfs/#post-datatypedoc-idrelationshipsnot_synchronizing", "text": "When configuring a device, it\u2019s tedious to add the not_synchronized_on for each directory individually. This route allows to make it in bulk.", "title": "POST /data/:type/:doc-id/relationships/not_synchronizing"}, {"location": "cozy-stack/not-synchronized-vfs/#request_3", "text": "POST /data/io.cozy.oauth.clients/653dfdb0-0595-0139-92df-543d7eb8149c/relationships/not_synchronizing HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"38086350-07c0-0139-4fe9-543d7eb8149c\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"3d447470-07c0-0139-4fea-543d7eb8149c\" } ] }", "title": "Request"}, {"location": "cozy-stack/not-synchronized-vfs/#response_3", "text": "HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json Note : if one of the id is a file, the response will be a 400 Bad Request. References are only for directories.", "title": "Response"}, {"location": "cozy-stack/not-synchronized-vfs/#delete-datatypedoc-idrelationshipsnot_synchronizing", "text": "This bulk deletion of not_synchronized_on on many directories can be useful when configuring a device.", "title": "DELETE /data/:type/:doc-id/relationships/not_synchronizing"}, {"location": "cozy-stack/not-synchronized-vfs/#request_4", "text": "DELETE /data/io.cozy.oauth.clients/653dfdb0-0595-0139-92df-543d7eb8149c/relationships/not_synchronizing HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"38086350-07c0-0139-4fe9-543d7eb8149c\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"3d447470-07c0-0139-4fea-543d7eb8149c\" } ] }", "title": "Request"}, {"location": "cozy-stack/not-synchronized-vfs/#response_4", "text": "HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json", "title": "Response"}, {"location": "cozy-stack/not-synchronized-vfs/#usage", "text": "When an OAuth client makes a request for the changes feed on the io.cozy.files doctype (via /data/io.cozy.files/_changes ), the output will be filtered. If a directory or file is inside a directory with the not_synchronized_on attribute set on for this client, the document will be replaced by a fake entry with _deleted: true .", "title": "Usage"}, {"location": "cozy-stack/notes/", "text": "Table of contents Notes for collaborative edition \u00b6 The cozy-notes application can be used to take notes, and collaborate on them. The note is persisted as a file in the VFS, but it also has specific routes to enable the collaborative edition in real-time. The content of the file is a markdown export of the notes, except if the note has images, and it is a tar with the markdown as index.md and the images in that case. The markdown format is mostly compatible with CommonMark, but there are a few changes: we are using the consistent attribute syntax for some markups like colors and underline the tables are not saved like in GFM because we can have merged cells and several paragraphs inside a cell misc. The downloaded files can be reuploaded to the Cozy, and if the .cozy-note extension is kept, the stack will try to recreate the Prosemirror tree, making possible to use the uploaded file as a note in Cozy-Notes with realtime collaboration. Routes \u00b6 POST /notes \u00b6 It creates a note: it creates a files with the right metadata for collaborative edition. Note: a permission on POST io.cozy.files is required to use this route. Parameter \u00b6 Parameter Description title The title of the note, that will also be used for the filename dir_id The identifier of the directory where the file will be created (optional) schema The schema for prosemirror (with OrderedMap transformed as arrays) content The initial content of the note (optional) Note: if the dir_id is not given, the file will be created in a Notes directory (and this directory will have a referenced_by on the notes apps to allow to find this directory even if it is renamed or moved later). Request \u00b6 POST /notes HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"attributes\" : { \"title\" : \"My new note\" , \"dir_id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } } } } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"1-f71ee54e2\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" }] }, \"version\" : 0 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 1 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } } GET /notes \u00b6 It returns the list of notes, sorted by last update. It adds the path for the files in the response, as it can be convient for the notes application. Note: a permission on GET io.cozy.files is required to use this route. Request \u00b6 GET /notes HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"links\" : { \"next\" : \"/notes?page[cursor]=a078d6f0-04a9-0138-3e03-543d7eb8149c\" }, \"data\" : [{ \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"1-f71ee54e2\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"path\" : \"/Notes/my new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" }] }, \"version\" : 0 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 1 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } }] } GET /notes/:id \u00b6 It fetches the file with the given id. It also includes the changes in the content that have been accepted by the stack but not yet persisted to the file. Request \u00b6 GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:52Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"horizontal_rule\" }] }, \"version\" : 3 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 4 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } } GET /notes/:id/text \u00b6 It returns the content of the note as text with no formatting. Request \u00b6 GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/text HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 200 OK Content-Type : text/plain; charset=UTF-8 This is the content of the note. GET /notes/texts \u00b6 It returns the content of several notes as text with no formatting. The identifiers of the notes must be given in the query-string parameter ids , as a comma-separated list. Request \u00b6 GET /notes/texts?ids=bf0dbdb0-e1ed-0137-8548-543d7eb8149c,6bc77a60-c8fe-013c-20a9-18c04daba326 HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" : \"This is the content of the note.\" , \"6bc77a60-c8fe-013c-20a9-18c04daba326\" : \"This is the text of another note.\" } GET /notes/:id/steps?Version=xxx \u00b6 It returns the steps since the given version. If the revision is too old, and the steps are no longer available, it returns a 412 response with the whole document for the note. Request \u00b6 GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/steps?Version=3 HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json Response (success) \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 1 , \"to\" : 1 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"H\" }] }, \"version\" : 4 } }, { \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 2 , \"to\" : 2 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"ello\" }] }, \"version\" : 5 } }] } Response (failure) \u00b6 HTTP / 1.1 412 Precondition Failed Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:52Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"horizontal_rule\" }] }, \"version\" : 6 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 4 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } } PUT /notes/:id/title \u00b6 It updates the title. Request \u00b6 PUT /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/title HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"title\" : \"A new title for my note\" } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"A new title for my note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:39:37Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"A new title for my note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"horizontal_rule\" }] }, \"version\" : 3 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 4 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:39:37Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } } PATCH /notes/:id \u00b6 It sends some steps to apply on the document. The last known version of the note must be sent in the If-Match header to avoid conflicts. Request \u00b6 PATCH /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c HTTP / 1.1 Host : alice.example.net If-Match : 3 Content-Type : application/vnd.api+json { \"data\" : [{ \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 1 , \"to\" : 1 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"H\" }] } } }, { \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 2 , \"to\" : 2 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"ello\" }] } } }] } Response (success) \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"A new title for my note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"MDlmN2UwMmYxMjkwYmUyMTFkYTcwN2EyNjZmMTUzYjMgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:39:37Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"A new title for my note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" , \"text\" : \"Hello\" }] }, \"version\" : 5 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 6 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:39:37Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } } Response (failure) \u00b6 If at least one step can\u2019t be applied, they will all be discarded, and the response will be this error: HTTP / 1.1 409 Conflict Content-Type : application/vnd.api+json { \"status\" : 409 , \"Title\" : \"Conflict\" , \"Detail\" : \"Cannot apply the steps\" } PUT /notes/:id/telepointer \u00b6 It updates the position of the pointer. Request \u00b6 PUT /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/telepointer HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.telepointers\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"anchor\" : 7 , \"head\" : 12 , \"type\" : \"textSelection\" } } } Response \u00b6 HTTP / 1.1 204 No Content POST /notes/:id/sync \u00b6 It forces writing the note to the virtual file system. It may be used after the title has been changed, or when the user quits the note. Request \u00b6 POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/sync HTTP / 1.1 Response \u00b6 HTTP / 1.1 204 No Content GET /notes/:id/open \u00b6 It return the parameters to build the URL where the note can be opened. It can be on the same cozy instance, or on another instance if the note is shared. If the identifier doesn\u2019t give a note, the response will be a 404 Page not found . Request \u00b6 GET /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/open HTTP / 1.1 Host : bob.cozy.example Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.url\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"attributes\" : { \"note_id\" : \"05781bea244247fb38f2cd50262c07b5\" , \"subdomain\" : \"flat\" , \"protocol\" : \"https\" , \"instance\" : \"alice.cozy.example\" , \"sharecode\" : \"543d7eb8149c\" , \"public_name\" : \"Bob\" } } } PUT /notes/:id/schema \u00b6 It can be used to update the schema of the given note. Request \u00b6 PUT /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/schema HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"attributes\" : { \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"panel\" , { \"content\" : \"(paragraph | heading | bulletList | orderedList)+\" , \"group\" : \"block\" , \"attrs\" : { \"panelType\" : { \"default\" : \"info\" } } } ], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"version\" : 2 , \"topNode\" : \"doc\" } } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"10-241a3436007b\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-12-10T14:49:12Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" }] }, \"version\" : 0 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"panel\" , { \"content\" : \"(paragraph | heading | bullet_list | ordered_list)+\" , \"group\" : \"block\" , \"attrs\" : { \"panelType\" : { \"default\" : \"info\" } } } ], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"version\" : 2 , \"topNode\" : \"doc\" } }, \"size\" : 1 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2020-12-10T14:49:12Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } } POST /notes/:id/images \u00b6 This route can be used to upload an image for a note. The note will be transformed in a tar archive in the VFS, with the image saved inside it. This route can only be used to upload images (the content-type is checked) and requires a POST permission on the note. The filename of the image is given in the query string, via the Name parameter. In case of conflict (another image has the same name), the stack will rename this image. If the image is larger than 768px, a thumbnail will be generated. Request \u00b6 POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/images?Name=diagram.jpg HTTP / 1.1 Accept : application/vnd.api+json Content-Length : 123456 Content-Type : image/jpeg Host : cozy.example.com Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.images\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c/e57d2ec0-d281-0139-2bed-543d7eb8149c\" , \"meta\" : { \"rev\" : \"1-588ab661\" }, \"attributes\" : { \"name\" : \"diagram.jpg\" , \"mime\" : \"image/jpeg\" , \"width\" : 1000 , \"height\" : 1000 , \"willBeResized\" : true , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2021-07-12T10:58:00Z\" , \"createdByApp\" : \"notes\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2021-07-12T10:58:00Z\" , \"uploadedAt\" : \"2021-07-12T10:58:00Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"notes\" } } }, \"links\" : { \"self\" : \"/notes/f48d9370-e1ec-0137-8547-543d7eb8149c/images/e57d2ec0-d281-0139-2bed-543d7eb8149c/543d7eb8149c128b\" } } } POST /notes/:id/:image-id/copy \u00b6 Copy an existing image to another note. It is similar to POST /notes/:id/images as creating an image, but can be useful to avoid downloading and then reuploading the image content when the user makes a copy/paste. The :id and :image-id path parameters identify the source image. The destination note will be specified in the query-string, as To . Query-String \u00b6 Parameter Description To the ID of the note where the image will be copied Request \u00b6 POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/e57d2ec0-d281-0139-2bed-543d7eb8149c/copy?To=76ddf590-905e-013c-5ff2-18c04daba326 HTTP / 1.1 Accept : application/vnd.api+json Host : cozy.example.com Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.images\" , \"id\" : \"76ddf590-905e-013c-5ff2-18c04daba326/8d146530-905e-013c-5ff3-98b45e10905e\" , \"meta\" : { \"rev\" : \"1-18c04dab\" }, \"attributes\" : { \"name\" : \"diagram.jpg\" , \"mime\" : \"image/jpeg\" , \"width\" : 1000 , \"height\" : 1000 , \"willBeResized\" : true , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2024-01-08T15:18:00Z\" , \"createdByApp\" : \"notes\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2024-01-08T15:18:00Z\" , \"uploadedAt\" : \"2024-01-08T15:18:00Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"notes\" } } }, \"links\" : { \"self\" : \"/notes/76ddf590-905e-013c-5ff2-18c04daba326/images/8d146530-905e-013c-5ff3-98b45e10905e/d251f620d98e1740\" } } } Real-time via websockets \u00b6 You can subscribe to the realtime API for a document with the io.cozy.notes.events doctype, and the id of a note file. It requires a permission on this file, and it will send the events for this notes: changes of the title, the steps applied, the telepointer updates, and images processed. Example \u00b6 client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.notes.events\", \"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.documents\", \"sessionID\": \"543781490137\", \"title\": \"this is the new title of this note\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.steps\", \"sessionID\": \"543781490137\", \"version\": 6, \"stepType\": \"replace\", \"from\": 1, \"to\": 1, \"slice\": {\"content\": [{\"type\": \"text\", \"text\": \"H\"}]}}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.telepointers\", \"sessionID\": \"543781490137\", \"anchor\": 7, \"head\": 12, \"type\": \"textSelection\"}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.images\", \"image_id\": \"e57d2ec0-d281-0139-2bed-543d7eb8149c\", \"mime\": \"image/jpeg\", \"width\": 768, \"height\": 768}}}", "title": "/notes - Notes for collaborative edition"}, {"location": "cozy-stack/notes/#notes-for-collaborative-edition", "text": "The cozy-notes application can be used to take notes, and collaborate on them. The note is persisted as a file in the VFS, but it also has specific routes to enable the collaborative edition in real-time. The content of the file is a markdown export of the notes, except if the note has images, and it is a tar with the markdown as index.md and the images in that case. The markdown format is mostly compatible with CommonMark, but there are a few changes: we are using the consistent attribute syntax for some markups like colors and underline the tables are not saved like in GFM because we can have merged cells and several paragraphs inside a cell misc. The downloaded files can be reuploaded to the Cozy, and if the .cozy-note extension is kept, the stack will try to recreate the Prosemirror tree, making possible to use the uploaded file as a note in Cozy-Notes with realtime collaboration.", "title": "Notes for collaborative edition"}, {"location": "cozy-stack/notes/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/notes/#post-notes", "text": "It creates a note: it creates a files with the right metadata for collaborative edition. Note: a permission on POST io.cozy.files is required to use this route.", "title": "POST /notes"}, {"location": "cozy-stack/notes/#parameter", "text": "Parameter Description title The title of the note, that will also be used for the filename dir_id The identifier of the directory where the file will be created (optional) schema The schema for prosemirror (with OrderedMap transformed as arrays) content The initial content of the note (optional) Note: if the dir_id is not given, the file will be created in a Notes directory (and this directory will have a referenced_by on the notes apps to allow to find this directory even if it is renamed or moved later).", "title": "Parameter"}, {"location": "cozy-stack/notes/#request", "text": "POST /notes HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"attributes\" : { \"title\" : \"My new note\" , \"dir_id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } } } }", "title": "Request"}, {"location": "cozy-stack/notes/#response", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"1-f71ee54e2\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" }] }, \"version\" : 0 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 1 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } }", "title": "Response"}, {"location": "cozy-stack/notes/#get-notes", "text": "It returns the list of notes, sorted by last update. It adds the path for the files in the response, as it can be convient for the notes application. Note: a permission on GET io.cozy.files is required to use this route.", "title": "GET /notes"}, {"location": "cozy-stack/notes/#request_1", "text": "GET /notes HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/notes/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"links\" : { \"next\" : \"/notes?page[cursor]=a078d6f0-04a9-0138-3e03-543d7eb8149c\" }, \"data\" : [{ \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"1-f71ee54e2\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"path\" : \"/Notes/my new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:04Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" }] }, \"version\" : 0 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 1 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } }] }", "title": "Response"}, {"location": "cozy-stack/notes/#get-notesid", "text": "It fetches the file with the given id. It also includes the changes in the content that have been accepted by the stack but not yet persisted to the file.", "title": "GET /notes/:id"}, {"location": "cozy-stack/notes/#request_2", "text": "GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/notes/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:52Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"horizontal_rule\" }] }, \"version\" : 3 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 4 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } }", "title": "Response"}, {"location": "cozy-stack/notes/#get-notesidtext", "text": "It returns the content of the note as text with no formatting.", "title": "GET /notes/:id/text"}, {"location": "cozy-stack/notes/#request_3", "text": "GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/text HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/notes/#response_3", "text": "HTTP / 1.1 200 OK Content-Type : text/plain; charset=UTF-8 This is the content of the note.", "title": "Response"}, {"location": "cozy-stack/notes/#get-notestexts", "text": "It returns the content of several notes as text with no formatting. The identifiers of the notes must be given in the query-string parameter ids , as a comma-separated list.", "title": "GET /notes/texts"}, {"location": "cozy-stack/notes/#request_4", "text": "GET /notes/texts?ids=bf0dbdb0-e1ed-0137-8548-543d7eb8149c,6bc77a60-c8fe-013c-20a9-18c04daba326 HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/notes/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" : \"This is the content of the note.\" , \"6bc77a60-c8fe-013c-20a9-18c04daba326\" : \"This is the text of another note.\" }", "title": "Response"}, {"location": "cozy-stack/notes/#get-notesidstepsversionxxx", "text": "It returns the steps since the given version. If the revision is too old, and the steps are no longer available, it returns a 412 response with the whole document for the note.", "title": "GET /notes/:id/steps?Version=xxx"}, {"location": "cozy-stack/notes/#request_5", "text": "GET /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/steps?Version=3 HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/notes/#response-success", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [{ \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 1 , \"to\" : 1 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"H\" }] }, \"version\" : 4 } }, { \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 2 , \"to\" : 2 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"ello\" }] }, \"version\" : 5 } }] }", "title": "Response (success)"}, {"location": "cozy-stack/notes/#response-failure", "text": "HTTP / 1.1 412 Precondition Failed Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:38:52Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"horizontal_rule\" }] }, \"version\" : 6 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 4 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } }", "title": "Response (failure)"}, {"location": "cozy-stack/notes/#put-notesidtitle", "text": "It updates the title.", "title": "PUT /notes/:id/title"}, {"location": "cozy-stack/notes/#request_6", "text": "PUT /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c/title HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"title\" : \"A new title for my note\" } } }", "title": "Request"}, {"location": "cozy-stack/notes/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"A new title for my note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:39:37Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"A new title for my note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"horizontal_rule\" }] }, \"version\" : 3 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 4 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:39:37Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } }", "title": "Response"}, {"location": "cozy-stack/notes/#patch-notesid", "text": "It sends some steps to apply on the document. The last known version of the note must be sent in the If-Match header to avoid conflicts.", "title": "PATCH /notes/:id"}, {"location": "cozy-stack/notes/#request_7", "text": "PATCH /notes/bf0dbdb0-e1ed-0137-8548-543d7eb8149c HTTP / 1.1 Host : alice.example.net If-Match : 3 Content-Type : application/vnd.api+json { \"data\" : [{ \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 1 , \"to\" : 1 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"H\" }] } } }, { \"type\" : \"io.cozy.notes.steps\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"stepType\" : \"replace\" , \"from\" : 2 , \"to\" : 2 , \"slice\" : { \"content\" : [{ \"type\" : \"text\" , \"text\" : \"ello\" }] } } }] }", "title": "Request"}, {"location": "cozy-stack/notes/#response-success_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"4-1482b88a\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"A new title for my note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"MDlmN2UwMmYxMjkwYmUyMTFkYTcwN2EyNjZmMTUzYjMgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-11-05T12:39:37Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"A new title for my note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" , \"text\" : \"Hello\" }] }, \"version\" : 5 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"topNode\" : \"doc\" } }, \"size\" : 6 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2019-11-05T12:39:37Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } }", "title": "Response (success)"}, {"location": "cozy-stack/notes/#response-failure_1", "text": "If at least one step can\u2019t be applied, they will all be discarded, and the response will be this error: HTTP / 1.1 409 Conflict Content-Type : application/vnd.api+json { \"status\" : 409 , \"Title\" : \"Conflict\" , \"Detail\" : \"Cannot apply the steps\" }", "title": "Response (failure)"}, {"location": "cozy-stack/notes/#put-notesidtelepointer", "text": "It updates the position of the pointer.", "title": "PUT /notes/:id/telepointer"}, {"location": "cozy-stack/notes/#request_8", "text": "PUT /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/telepointer HTTP / 1.1 Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.telepointers\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"attributes\" : { \"sessionID\" : \"543781490137\" , \"anchor\" : 7 , \"head\" : 12 , \"type\" : \"textSelection\" } } }", "title": "Request"}, {"location": "cozy-stack/notes/#response_6", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/notes/#post-notesidsync", "text": "It forces writing the note to the virtual file system. It may be used after the title has been changed, or when the user quits the note.", "title": "POST /notes/:id/sync"}, {"location": "cozy-stack/notes/#request_9", "text": "POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/sync HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/notes/#response_7", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/notes/#get-notesidopen", "text": "It return the parameters to build the URL where the note can be opened. It can be on the same cozy instance, or on another instance if the note is shared. If the identifier doesn\u2019t give a note, the response will be a 404 Page not found .", "title": "GET /notes/:id/open"}, {"location": "cozy-stack/notes/#request_10", "text": "GET /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/open HTTP / 1.1 Host : bob.cozy.example", "title": "Request"}, {"location": "cozy-stack/notes/#response_8", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.url\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" , \"attributes\" : { \"note_id\" : \"05781bea244247fb38f2cd50262c07b5\" , \"subdomain\" : \"flat\" , \"protocol\" : \"https\" , \"instance\" : \"alice.cozy.example\" , \"sharecode\" : \"543d7eb8149c\" , \"public_name\" : \"Bob\" } } }", "title": "Response"}, {"location": "cozy-stack/notes/#put-notesidschema", "text": "It can be used to update the schema of the given note.", "title": "PUT /notes/:id/schema"}, {"location": "cozy-stack/notes/#request_11", "text": "PUT /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/schema HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.documents\" , \"attributes\" : { \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"panel\" , { \"content\" : \"(paragraph | heading | bulletList | orderedList)+\" , \"group\" : \"block\" , \"attrs\" : { \"panelType\" : { \"default\" : \"info\" } } } ], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"version\" : 2 , \"topNode\" : \"doc\" } } } }", "title": "Request"}, {"location": "cozy-stack/notes/#response_9", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"bf0dbdb0-e1ed-0137-8548-543d7eb8149c\" , \"meta\" : { \"rev\" : \"10-241a3436007b\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"My new note.cozy-note\" , \"trashed\" : false , \"md5sum\" : \"NjhiMzI5ZGE5ODkzZTM0MDk5YzdkOGFkNWNiOWM5NDAgIC0K\" , \"created_at\" : \"2019-11-05T12:38:04Z\" , \"updated_at\" : \"2019-12-10T14:49:12Z\" , \"tags\" : [], \"metadata\" : { \"title\" : \"My new note\" , \"content\" : { \"type\" : \"doc\" , \"content\" : [{ \"type\" : \"paragraph\" }] }, \"version\" : 0 , \"schema\" : { \"nodes\" : [ [ \"doc\" , { \"content\" : \"block+\" }], [ \"panel\" , { \"content\" : \"(paragraph | heading | bullet_list | ordered_list)+\" , \"group\" : \"block\" , \"attrs\" : { \"panelType\" : { \"default\" : \"info\" } } } ], [ \"paragraph\" , { \"content\" : \"inline*\" , \"group\" : \"block\" }], [ \"blockquote\" , { \"content\" : \"block+\" , \"group\" : \"block\" }], [ \"horizontal_rule\" , { \"group\" : \"block\" }], [ \"heading\" , { \"content\" : \"inline*\" , \"group\" : \"block\" , \"attrs\" : { \"level\" : { \"default\" : 1 } } } ], [ \"code_block\" , { \"content\" : \"text*\" , \"marks\" : \"\" , \"group\" : \"block\" }], [ \"text\" , { \"group\" : \"inline\" }], [ \"image\" , { \"group\" : \"inline\" , \"inline\" : true , \"attrs\" : { \"alt\" : {}, \"src\" : {}, \"title\" : {} } } ], [ \"hard_break\" , { \"group\" : \"inline\" , \"inline\" : true }], [ \"ordered_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" , \"attrs\" : { \"order\" : { \"default\" : 1 } } } ], [ \"bullet_list\" , { \"content\" : \"list_item+\" , \"group\" : \"block\" }], [ \"list_item\" , { \"content\" : \"paragraph block*\" }] ], \"marks\" : [ [ \"link\" , { \"attrs\" : { \"href\" : {}, \"title\" : {} }, \"inclusive\" : false }], [ \"em\" , {}], [ \"strong\" , {}], [ \"code\" , {}] ], \"version\" : 2 , \"topNode\" : \"doc\" } }, \"size\" : 1 , \"executable\" : false , \"class\" : \"text\" , \"mime\" : \"text/vnd.cozy.note+markdown\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2019-11-05T12:38:04Z\" , \"createdOn\" : \"https://alice.example.net/\" , \"updatedAt\" : \"2020-12-10T14:49:12Z\" , \"uploadedAt\" : \"2019-11-05T12:38:04Z\" , \"uploadedOn\" : \"https://alice.example.net/\" } }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/f48d9370-e1ec-0137-8547-543d7eb8149c\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c\" } } } } }", "title": "Response"}, {"location": "cozy-stack/notes/#post-notesidimages", "text": "This route can be used to upload an image for a note. The note will be transformed in a tar archive in the VFS, with the image saved inside it. This route can only be used to upload images (the content-type is checked) and requires a POST permission on the note. The filename of the image is given in the query string, via the Name parameter. In case of conflict (another image has the same name), the stack will rename this image. If the image is larger than 768px, a thumbnail will be generated.", "title": "POST /notes/:id/images"}, {"location": "cozy-stack/notes/#request_12", "text": "POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/images?Name=diagram.jpg HTTP / 1.1 Accept : application/vnd.api+json Content-Length : 123456 Content-Type : image/jpeg Host : cozy.example.com ", "title": "Request"}, {"location": "cozy-stack/notes/#response_10", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.images\" , \"id\" : \"f48d9370-e1ec-0137-8547-543d7eb8149c/e57d2ec0-d281-0139-2bed-543d7eb8149c\" , \"meta\" : { \"rev\" : \"1-588ab661\" }, \"attributes\" : { \"name\" : \"diagram.jpg\" , \"mime\" : \"image/jpeg\" , \"width\" : 1000 , \"height\" : 1000 , \"willBeResized\" : true , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2021-07-12T10:58:00Z\" , \"createdByApp\" : \"notes\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2021-07-12T10:58:00Z\" , \"uploadedAt\" : \"2021-07-12T10:58:00Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"notes\" } } }, \"links\" : { \"self\" : \"/notes/f48d9370-e1ec-0137-8547-543d7eb8149c/images/e57d2ec0-d281-0139-2bed-543d7eb8149c/543d7eb8149c128b\" } } }", "title": "Response"}, {"location": "cozy-stack/notes/#post-notesidimage-idcopy", "text": "Copy an existing image to another note. It is similar to POST /notes/:id/images as creating an image, but can be useful to avoid downloading and then reuploading the image content when the user makes a copy/paste. The :id and :image-id path parameters identify the source image. The destination note will be specified in the query-string, as To .", "title": "POST /notes/:id/:image-id/copy"}, {"location": "cozy-stack/notes/#query-string", "text": "Parameter Description To the ID of the note where the image will be copied", "title": "Query-String"}, {"location": "cozy-stack/notes/#request_13", "text": "POST /notes/f48d9370-e1ec-0137-8547-543d7eb8149c/e57d2ec0-d281-0139-2bed-543d7eb8149c/copy?To=76ddf590-905e-013c-5ff2-18c04daba326 HTTP / 1.1 Accept : application/vnd.api+json Host : cozy.example.com", "title": "Request"}, {"location": "cozy-stack/notes/#response_11", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notes.images\" , \"id\" : \"76ddf590-905e-013c-5ff2-18c04daba326/8d146530-905e-013c-5ff3-98b45e10905e\" , \"meta\" : { \"rev\" : \"1-18c04dab\" }, \"attributes\" : { \"name\" : \"diagram.jpg\" , \"mime\" : \"image/jpeg\" , \"width\" : 1000 , \"height\" : 1000 , \"willBeResized\" : true , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2024-01-08T15:18:00Z\" , \"createdByApp\" : \"notes\" , \"createdOn\" : \"https://cozy.example.com/\" , \"updatedAt\" : \"2024-01-08T15:18:00Z\" , \"uploadedAt\" : \"2024-01-08T15:18:00Z\" , \"uploadedOn\" : \"https://cozy.example.com/\" , \"uploadedBy\" : { \"slug\" : \"notes\" } } }, \"links\" : { \"self\" : \"/notes/76ddf590-905e-013c-5ff2-18c04daba326/images/8d146530-905e-013c-5ff3-98b45e10905e/d251f620d98e1740\" } } }", "title": "Response"}, {"location": "cozy-stack/notes/#real-time-via-websockets", "text": "You can subscribe to the realtime API for a document with the io.cozy.notes.events doctype, and the id of a note file. It requires a permission on this file, and it will send the events for this notes: changes of the title, the steps applied, the telepointer updates, and images processed.", "title": "Real-time via websockets"}, {"location": "cozy-stack/notes/#example", "text": "client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.notes.events\", \"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.documents\", \"sessionID\": \"543781490137\", \"title\": \"this is the new title of this note\"}}} server > {\"event\": \"CREATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.steps\", \"sessionID\": \"543781490137\", \"version\": 6, \"stepType\": \"replace\", \"from\": 1, \"to\": 1, \"slice\": {\"content\": [{\"type\": \"text\", \"text\": \"H\"}]}}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.telepointers\", \"sessionID\": \"543781490137\", \"anchor\": 7, \"head\": 12, \"type\": \"textSelection\"}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"f48d9370-e1ec-0137-8547-543d7eb8149c\", \"type\": \"io.cozy.notes.events\", \"doc\": {\"doctype\": \"io.cozy.notes.images\", \"image_id\": \"e57d2ec0-d281-0139-2bed-543d7eb8149c\", \"mime\": \"image/jpeg\", \"width\": 768, \"height\": 768}}}", "title": "Example"}, {"location": "cozy-stack/notifications/", "text": "Table of contents Notifications \u00b6 Cozy applications can send notifications to the user, in order to alert or notify for services message or state change that could be of interest to the user, in an asynchronous manner. These notifications are part of a \u201cNotification Center\u201d where the user can configure the behavior of these notifications and the channel in which they are sent. Firebase configuration \u00b6 The push notifications can be sent via Firebase to smartphones. By default, the key used to connect to firebase is set in the configuration file, via the notifications.fcm_credentials_file parameter. But it can be useful to have several firebase accounts when there are several applications developed by several organizations. In that case, it is possible to tell the stack to use a particular key for a given app by creating a CouchDB document inside the secrets/io-cozy-account_types database, like this: { \"_id\" : \"myapp\" , \"slug\" : \"myapp\" , \"fcm_credentials\" : { \"type\" : \"service_account\" , \"etc.\" : \"...\" } } And we can go further to restrict this to a context, by prefixing the _id with the context name and / : { \"_id\" : \"mycontext/myapp\" , \"slug\" : \"myapp\" , \"fcm_credentials\" : { \"type\" : \"service_account\" , \"etc.\" : \"...\" } } Declare application\u2019s notifications \u00b6 Each application have to declare in its manifest the notifications it needs to send. The notifications fields of the manifest can be used to define all these notifications, with the following properties: collapsible (boolean): defines a notification category for which only the last value is of interest to the user. For instance, a account-balance quota for a user\u2019s bank account: such notification is only useful as its last value. stateful (boolean): defines a notification storing a piece of state: for each new notification, the stack will check that if the last sent notification has a different state before sending it. If not, the notification will not be resent multiple (boolean): specify the possibility for a notification to have different sub-categories, defined by a programmable/dynamic identifier. collapsible and stateful properties are inherited for each sub- categories. default_priority : default priority to use, with values \u201chigh\u201d or \u201cnormal\u201d. This is propagated to the underlying mobile notifications system. templates : a link list to templates file contained in the application folder that can be used to write the content of the notification, depending on the communication channel. In this documentation, we take the example of an application with the following notification: { \"notifications\" : { \"account-balance\" : { \"description\" : \"Alert the user when its account balance is negative\" , \"collapsible\" : true , // only interested in the last value of the notification \"multiple\" : true , // require sub-categories for each account \"stateful\" : true , // piece of state to distinguish notifications \"default_priority\" : \"high\" , // high priority for this notification \"templates\" : { \"mail\" : \"file:./notifications/account-balance-mail.tpl\" } } } } For mobile application, there are two cases: if the mobile application is linked to a web app, it will use the same declaration of notifications from the manifest of the web app else, the mobile app will need to declare its notifications when registering its OAuth client . Creating a notification \u00b6 POST /notifications \u00b6 This endpoint can be used to push a new notification to the user. Notifications fields are: category (string): name of the notification category category_id (string): name of the notification sub-category if relevant (optional) title (string): title of the notification message (string): message of of the notification (optional) priority (string): priority of the notification ( high or normal ), sent to the underlying channel to prioritize the notification state (string): state of the notification. Only needed if your notification is stateful , to distinguish notifications preferred_channels (array of string): to select a list of preferred channels for this notification: either \"mobile\" , \"sms\" or \"mail\" . The stack may chose another channels. [\"mobile\", \"mail\"] means that the stack will first try to send a mobile push notification, and if it fails, it will try by mail data (map): key/value map used to create the notification from its template, or sent in the notification payload for mobiles at (string): send the notification later, at this date formatted in ISO-8601 (optional) Note that if you send a notification by sms, only the message attribute will be sent. Also, keep in mind that, depending on your sms provider, the length of the message cannot be longer than 160 characters. Request \u00b6 POST /notifications HTTP / 1.1 Host : alice.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"preferred_channels\" : [ \"mobile\" ], \"data\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } } } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notifications\" , \"id\" : \"c57a548c-7602-11e7-933b-6f27603d27da\" , \"meta\" : { \"rev\" : \"1-1f2903f9a867\" }, \"attributes\" : { \"source_id\" : \"cozy/app/bank/account-balance/my-bank\" , \"originator\" : \"app\" , \"slug\" : \"bank\" , \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"data\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } } }", "title": "/notifications - Notifications"}, {"location": "cozy-stack/notifications/#notifications", "text": "Cozy applications can send notifications to the user, in order to alert or notify for services message or state change that could be of interest to the user, in an asynchronous manner. These notifications are part of a \u201cNotification Center\u201d where the user can configure the behavior of these notifications and the channel in which they are sent.", "title": "Notifications"}, {"location": "cozy-stack/notifications/#firebase-configuration", "text": "The push notifications can be sent via Firebase to smartphones. By default, the key used to connect to firebase is set in the configuration file, via the notifications.fcm_credentials_file parameter. But it can be useful to have several firebase accounts when there are several applications developed by several organizations. In that case, it is possible to tell the stack to use a particular key for a given app by creating a CouchDB document inside the secrets/io-cozy-account_types database, like this: { \"_id\" : \"myapp\" , \"slug\" : \"myapp\" , \"fcm_credentials\" : { \"type\" : \"service_account\" , \"etc.\" : \"...\" } } And we can go further to restrict this to a context, by prefixing the _id with the context name and / : { \"_id\" : \"mycontext/myapp\" , \"slug\" : \"myapp\" , \"fcm_credentials\" : { \"type\" : \"service_account\" , \"etc.\" : \"...\" } }", "title": "Firebase configuration"}, {"location": "cozy-stack/notifications/#declare-applications-notifications", "text": "Each application have to declare in its manifest the notifications it needs to send. The notifications fields of the manifest can be used to define all these notifications, with the following properties: collapsible (boolean): defines a notification category for which only the last value is of interest to the user. For instance, a account-balance quota for a user\u2019s bank account: such notification is only useful as its last value. stateful (boolean): defines a notification storing a piece of state: for each new notification, the stack will check that if the last sent notification has a different state before sending it. If not, the notification will not be resent multiple (boolean): specify the possibility for a notification to have different sub-categories, defined by a programmable/dynamic identifier. collapsible and stateful properties are inherited for each sub- categories. default_priority : default priority to use, with values \u201chigh\u201d or \u201cnormal\u201d. This is propagated to the underlying mobile notifications system. templates : a link list to templates file contained in the application folder that can be used to write the content of the notification, depending on the communication channel. In this documentation, we take the example of an application with the following notification: { \"notifications\" : { \"account-balance\" : { \"description\" : \"Alert the user when its account balance is negative\" , \"collapsible\" : true , // only interested in the last value of the notification \"multiple\" : true , // require sub-categories for each account \"stateful\" : true , // piece of state to distinguish notifications \"default_priority\" : \"high\" , // high priority for this notification \"templates\" : { \"mail\" : \"file:./notifications/account-balance-mail.tpl\" } } } } For mobile application, there are two cases: if the mobile application is linked to a web app, it will use the same declaration of notifications from the manifest of the web app else, the mobile app will need to declare its notifications when registering its OAuth client .", "title": "Declare application's notifications"}, {"location": "cozy-stack/notifications/#creating-a-notification", "text": "", "title": "Creating a notification"}, {"location": "cozy-stack/notifications/#post-notifications", "text": "This endpoint can be used to push a new notification to the user. Notifications fields are: category (string): name of the notification category category_id (string): name of the notification sub-category if relevant (optional) title (string): title of the notification message (string): message of of the notification (optional) priority (string): priority of the notification ( high or normal ), sent to the underlying channel to prioritize the notification state (string): state of the notification. Only needed if your notification is stateful , to distinguish notifications preferred_channels (array of string): to select a list of preferred channels for this notification: either \"mobile\" , \"sms\" or \"mail\" . The stack may chose another channels. [\"mobile\", \"mail\"] means that the stack will first try to send a mobile push notification, and if it fails, it will try by mail data (map): key/value map used to create the notification from its template, or sent in the notification payload for mobiles at (string): send the notification later, at this date formatted in ISO-8601 (optional) Note that if you send a notification by sms, only the message attribute will be sent. Also, keep in mind that, depending on your sms provider, the length of the message cannot be longer than 160 characters.", "title": "POST /notifications"}, {"location": "cozy-stack/notifications/#request", "text": "POST /notifications HTTP / 1.1 Host : alice.cozy.localhost Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"attributes\" : { \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"preferred_channels\" : [ \"mobile\" ], \"data\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } } }", "title": "Request"}, {"location": "cozy-stack/notifications/#response", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.notifications\" , \"id\" : \"c57a548c-7602-11e7-933b-6f27603d27da\" , \"meta\" : { \"rev\" : \"1-1f2903f9a867\" }, \"attributes\" : { \"source_id\" : \"cozy/app/bank/account-balance/my-bank\" , \"originator\" : \"app\" , \"slug\" : \"bank\" , \"category\" : \"account-balance\" , \"category_id\" : \"my-bank\" , \"title\" : \"Your account balance is not OK\" , \"message\" : \"Warning: we have detected a negative balance in your my-bank\" , \"priority\" : \"high\" , \"state\" : \"-1\" , \"data\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } } }", "title": "Response"}, {"location": "cozy-stack/office/", "text": "Table of contents Collaborative edition of Office documents \u00b6 Diagrams \u00b6 Opening a document with OnlyOffice \u00b6 Reference: https://api.onlyoffice.com/editors/open The browser makes a request GET /office/:id/open to know the address of the OnlyOffice server The browser makes several HTTP requests to the Document Server Fetch the api.js script Open a websocket connection Send a command to load the office document The document server makes a request to the callback URL with status=1 The document server asks the file converter to load the document (via RabbitMQ?) The file converter loads the file content from the stack Saving a document with OnlyOffice \u00b6 Reference: https://api.onlyoffice.com/editors/save The browser makes requests to edit the document and close the connection when done The document server waits a bit after all clients have disconnected, and send a request to the callback URL The stack downloads the file from the document server and saves it Routes \u00b6 GET /office/:id/open \u00b6 This route returns the parameters to open an office document. There are two cases: The document is shared and should be opened on another instance (for collaborative edition) The document can be opened locally. In the first case, the response will contain the parameters of the other instance. In the second case, the parameters are for the document server of OnlyOffice. If the identifier doesn\u2019t give an office document or if there is no onlyoffice server configured, the response will be a 404 Page not found . Request \u00b6 GET /office/32e07d806f9b0139c541543d7eb8149c/open HTTP / 1.1 Host : bob.cozy.example Response (case 1) \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.office.url\" , \"id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"attributes\" : { \"document_id\" : \"b05e7c306f9c0139c542543d7eb8149c\" , \"subdomain\" : \"flat\" , \"protocol\" : \"https\" , \"instance\" : \"alice.cozy.example\" , \"sharecode\" : \"543d7eb8149c\" , \"public_name\" : \"Bob\" } } } Response (case 2) \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.office.url\" , \"id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"attributes\" : { \"document_id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"subdomain\" : \"flat\" , \"protocol\" : \"https\" , \"instance\" : \"bob.cozy.example\" , \"public_name\" : \"Bob\" , \"onlyoffice\" : { \"url\" : \"https://documentserver/\" , \"token\" : \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M\" , \"documentType\" : \"word\" , \"document\" : { \"filetype\" : \"docx\" , \"key\" : \"7c7ccc2e7137ba774b7e44de\" , \"title\" : \"Letter.docx\" , \"url\" : \"https://bob.cozy.example/files/downloads/735e6cf69af2db82/Letter.docx?Dl=1\" , \"info\" : { \"owner\" : \"Bob\" , \"uploaded\" : \"2010-07-07 3:46 PM\" } }, \"editor\" : { \"callbackUrl\" : \"https://bob.cozy.example/office/callback\" , \"lang\" : \"en\" , \"mode\" : \"edit\" } } } } } POST /office/keys/:key \u00b6 If a document is being edited while a new version is uploaded (via the desktop for example), the OO webapp should call this endpoint if the user chooses to continue editing the version on which they were working. A conflict file is created, so that no work is lost. Request \u00b6 POST /office/keys/7c7ccc2e7137ba774b7e44de HTTP / 1.1 Host : bob.cozy.example Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"meta\" : { \"rev\" : \"3-18c04daba326\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"slideshow (2).pptx\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2023-09-30T21:42:05Z\" , \"updated_at\" : \"2023-09-30T22:38:04Z\" , \"tags\" : [], \"metadata\" : {}, \"size\" : 12345 , \"executable\" : false , \"class\" : \"slide\" , \"mime\" : \"application/vnd.ms-powerpoint\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2023-09-30T21:42:05Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://bob.cozy.example/\" , \"updatedAt\" : \"2023-09-30T22:38:04Z\" , \"uploadedAt\" : \"2023-09-30T22:38:04Z\" , \"uploadedOn\" : \"https://bob.cozy.example/\" , \"uploadedBy\" : { \"slug\" : \"onlyoffice-server\" } } } } } POST /office/callback \u00b6 This is the callback handler for OnlyOffice. It is called when the document server wants to save the file. See https://api.onlyoffice.com/editors/callback Request \u00b6 POST /office/callback HTTP / 1.1 Host : bob.cozy.example Content-Type : application/json { \"actions\" : [{ \"type\" : 0 , \"userid\" : \"78e1e841\" }], \"changesurl\" : \"https://documentserver/url-to-changes.zip\" , \"key\" : \"7c7ccc2e7137ba774b7e44de\" , \"status\" : 2 , \"url\" : \"https://documentserver/url-to-edited-document.docx\" , \"users\" : [ \"6d5a81d0\" ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"error\" : 0 }", "title": "/office - Collaborative edition of Office documents"}, {"location": "cozy-stack/office/#collaborative-edition-of-office-documents", "text": "", "title": "Collaborative edition of Office documents"}, {"location": "cozy-stack/office/#diagrams", "text": "", "title": "Diagrams"}, {"location": "cozy-stack/office/#opening-a-document-with-onlyoffice", "text": "Reference: https://api.onlyoffice.com/editors/open The browser makes a request GET /office/:id/open to know the address of the OnlyOffice server The browser makes several HTTP requests to the Document Server Fetch the api.js script Open a websocket connection Send a command to load the office document The document server makes a request to the callback URL with status=1 The document server asks the file converter to load the document (via RabbitMQ?) The file converter loads the file content from the stack", "title": "Opening a document with OnlyOffice"}, {"location": "cozy-stack/office/#saving-a-document-with-onlyoffice", "text": "Reference: https://api.onlyoffice.com/editors/save The browser makes requests to edit the document and close the connection when done The document server waits a bit after all clients have disconnected, and send a request to the callback URL The stack downloads the file from the document server and saves it", "title": "Saving a document with OnlyOffice"}, {"location": "cozy-stack/office/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/office/#get-officeidopen", "text": "This route returns the parameters to open an office document. There are two cases: The document is shared and should be opened on another instance (for collaborative edition) The document can be opened locally. In the first case, the response will contain the parameters of the other instance. In the second case, the parameters are for the document server of OnlyOffice. If the identifier doesn\u2019t give an office document or if there is no onlyoffice server configured, the response will be a 404 Page not found .", "title": "GET /office/:id/open"}, {"location": "cozy-stack/office/#request", "text": "GET /office/32e07d806f9b0139c541543d7eb8149c/open HTTP / 1.1 Host : bob.cozy.example", "title": "Request"}, {"location": "cozy-stack/office/#response-case-1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.office.url\" , \"id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"attributes\" : { \"document_id\" : \"b05e7c306f9c0139c542543d7eb8149c\" , \"subdomain\" : \"flat\" , \"protocol\" : \"https\" , \"instance\" : \"alice.cozy.example\" , \"sharecode\" : \"543d7eb8149c\" , \"public_name\" : \"Bob\" } } }", "title": "Response (case 1)"}, {"location": "cozy-stack/office/#response-case-2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.office.url\" , \"id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"attributes\" : { \"document_id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"subdomain\" : \"flat\" , \"protocol\" : \"https\" , \"instance\" : \"bob.cozy.example\" , \"public_name\" : \"Bob\" , \"onlyoffice\" : { \"url\" : \"https://documentserver/\" , \"token\" : \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M\" , \"documentType\" : \"word\" , \"document\" : { \"filetype\" : \"docx\" , \"key\" : \"7c7ccc2e7137ba774b7e44de\" , \"title\" : \"Letter.docx\" , \"url\" : \"https://bob.cozy.example/files/downloads/735e6cf69af2db82/Letter.docx?Dl=1\" , \"info\" : { \"owner\" : \"Bob\" , \"uploaded\" : \"2010-07-07 3:46 PM\" } }, \"editor\" : { \"callbackUrl\" : \"https://bob.cozy.example/office/callback\" , \"lang\" : \"en\" , \"mode\" : \"edit\" } } } } }", "title": "Response (case 2)"}, {"location": "cozy-stack/office/#post-officekeyskey", "text": "If a document is being edited while a new version is uploaded (via the desktop for example), the OO webapp should call this endpoint if the user chooses to continue editing the version on which they were working. A conflict file is created, so that no work is lost.", "title": "POST /office/keys/:key"}, {"location": "cozy-stack/office/#request_1", "text": "POST /office/keys/7c7ccc2e7137ba774b7e44de HTTP / 1.1 Host : bob.cozy.example", "title": "Request"}, {"location": "cozy-stack/office/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"32e07d806f9b0139c541543d7eb8149c\" , \"meta\" : { \"rev\" : \"3-18c04daba326\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"slideshow (2).pptx\" , \"trashed\" : false , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2023-09-30T21:42:05Z\" , \"updated_at\" : \"2023-09-30T22:38:04Z\" , \"tags\" : [], \"metadata\" : {}, \"size\" : 12345 , \"executable\" : false , \"class\" : \"slide\" , \"mime\" : \"application/vnd.ms-powerpoint\" , \"cozyMetadata\" : { \"doctypeVersion\" : \"1\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2023-09-30T21:42:05Z\" , \"createdByApp\" : \"drive\" , \"createdOn\" : \"https://bob.cozy.example/\" , \"updatedAt\" : \"2023-09-30T22:38:04Z\" , \"uploadedAt\" : \"2023-09-30T22:38:04Z\" , \"uploadedOn\" : \"https://bob.cozy.example/\" , \"uploadedBy\" : { \"slug\" : \"onlyoffice-server\" } } } } }", "title": "Response"}, {"location": "cozy-stack/office/#post-officecallback", "text": "This is the callback handler for OnlyOffice. It is called when the document server wants to save the file. See https://api.onlyoffice.com/editors/callback", "title": "POST /office/callback"}, {"location": "cozy-stack/office/#request_2", "text": "POST /office/callback HTTP / 1.1 Host : bob.cozy.example Content-Type : application/json { \"actions\" : [{ \"type\" : 0 , \"userid\" : \"78e1e841\" }], \"changesurl\" : \"https://documentserver/url-to-changes.zip\" , \"key\" : \"7c7ccc2e7137ba774b7e44de\" , \"status\" : 2 , \"url\" : \"https://documentserver/url-to-edited-document.docx\" , \"users\" : [ \"6d5a81d0\" ] }", "title": "Request"}, {"location": "cozy-stack/office/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"error\" : 0 }", "title": "Response"}, {"location": "cozy-stack/permissions/", "text": "Table of contents Permissions \u00b6 When the permissions are used? \u00b6 The permissions are used when a request is made to cozy stack. It allows to let the owner of the cozy instance controls the access to her data, files and actions on them. The permissions are given in several contexts. Let\u2019s see them! Client-side apps \u00b6 When the user installs a new client-side app, she is asked to accept an initial set of permissions for this app. This set of permissions is described in the manifest of the app. Later, the application can gain more permissions via the intents and optional permissions. See below for more details. When the authentified user access a client-side app, the app receives a token from the stack that can be used in later requests to the stack as a proof of the permissions it owns. External apps via OAuth2 \u00b6 An external application can ask for permissions via the OAuth2 dance, and use them later with the access token. The permissions are in the scope parameter. Sharing with other users \u00b6 The owner of a cozy instance can share some documents and files with other users. It can be done in two ways: If the other user also has a cozy, it can be a cozy-to-cozy sharing. Else, the owner can give to him a link with a code or a shortcode. What is a permission? \u00b6 A permission gives the right for a request having it to do something on the stack. It is defined by four components. Type \u00b6 type is the attribute used in JSON-API or the doctype for the Data System. It is the only mandatory component. If just the type is specified, it gives access to all the operations on this type . For example, a permission on type io.cozy.contacts gives the right to create, read, update and delete any contact, and to fetch all the contacts. A permission on type io.cozy.files allow to access and modify any file or directory. Some known types: io.cozy.files , for files and folder in the VFS io.cozy.apps , for apps io.cozy.settings , for the settings io.cozy.jobs and io.cozy.triggers , for jobs io.cozy.oauth.clients , to list and revoke OAuth 2 clients It is also possible to use a wildcard to use a doctype and its sub-doctypes if the doctype contains at least 3 . . For example, io.cozy.bank.* will give access to io.cozy.bank , io.cozy.bank.accounts , io.cozy.bank.accounts.stats , io.cozy.bank.settings , etc. io.cozy.* will give you an error. Verbs \u00b6 It says which HTTP verbs can be used for requests to the cozy-stack. GET will give read-only access, DELETE can be used for deletions, etc. Verbs should be declared in a list, like [\"GET\", \"POST\", \"DELETE\"] , and use [\"ALL\"] as a shortcut for [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"] (it is the default). Note : HEAD is implicitely implied when GET is allowed. OPTIONS for Cross-Origin Resources Sharing is always allowed, the stack does not have the informations about the permission when it answers the request. Values \u00b6 It\u2019s possible to restrict the permissions to only some documents of a doctype, or to just some files and folders. You can give a list of ids in values . Note : a permission for a folder also gives permissions with same verbs for files and folders inside it. Selector \u00b6 By default, the values are checked with the id . But it\u2019s possible to use a selector to filter on another field . In particular, it can be used for sharing. A user may share a calendar and all the events inside it. It will be done with two permissions. The first one is for the calendar: { \"type\" : \"io.cozy.calendars\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"1355812c-d41e-11e6-8467-53be4648e3ad\" ] } And the other is for the events inside the calendar: { \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"GET\" ], \"selector\" : \"calendar-id\" , \"values\" : [ \"1355812c-d41e-11e6-8467-53be4648e3ad\" ] } What format for a permission? \u00b6 JSON \u00b6 The prefered format for permissions is JSON. Each permission is a map with the type , verbs , values and selector see above, plus a description that can be used to give more informations to the user. Only the type field is mandatory. In the manifest, the permissions are regrouped in a map. The key is not very relevant, it\u2019s just here for localization. The same key is used in the locales field to identify the permission. Example: { \"permissions\" : { \"contacts\" : { \"description\" : \"Required for autocompletion on @name\" , \"type\" : \"io.cozy.contacts\" , \"verbs\" : [ \"GET\" ] }, \"images\" : { \"description\" : \"Required for the background\" , \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" , \"POST\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] }, \"mail\" : { \"description\" : \"Required to send a congratulations email to your friends\" , \"type\" : \"io.cozy.jobs\" , \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } Inline \u00b6 OAuth2 as a scope parameter for defining the permissions given to the application. But it\u2019s only a string, not a JSON. In that case, we use a space delimited list of permissions, each permission is written compactly with : between the components. Example: io.cozy.contacts io.cozy.files:GET:io.cozy.files.music-dir io.cozy.jobs:POST:sendmail:worker Note : the verbs component can\u2019t be omitted when the values and selector are used. Inspiration \u00b6 Access control on other similar platforms Routes \u00b6 GET /permissions/self \u00b6 List the permissions for a given token Request \u00b6 GET /permissions/self HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.permissions\" , \"id\" : \"5a9c1844-d427-11e6-ab36-2b684d437b0d\" , \"attributes\" : { \"type\" : \"app\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"permissions\" : { \"contacts\" : { \"description\" : \"Required for autocompletion on @name\" , \"type\" : \"io.cozy.contacts\" , \"verbs\" : [ \"GET\" ] }, \"images\" : { \"description\" : \"Required for the background\" , \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] }, \"mail\" : { \"description\" : \"Required to send a congratulations email to your friends\" , \"type\" : \"io.cozy.jobs\" , \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } } } Special case \u00b6 The token can be a sharecode when a member of a sharing is previewing a sharing. When it is the case, the member information from the sharing is included in the response, like this: { \"data\" : { \"type\" : \"io.cozy.permissions\" , \"id\" : \"bf716babb70b73b89c870fccce00233f\" , \"attributes\" : { \"type\" : \"share-preview\" , \"source_id\" : \"io.cozy.sharings/bf716babb70b73b89c870fccce00233a\" , \"permissions\" : { \"Essai\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"c2930bef3705096d63f5c8fb60019cc0\" ] } }, \"cozyMetadata\" : { \"doctypeVersion\" : \"\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-10-19T16:12:31.440253797+02:00\" , \"createdByApp\" : \"drive\" , \"updatedAt\" : \"2020-10-19T16:12:31.440253797+02:00\" } }, \"meta\" : { \"rev\" : \"1-18c3bc158cf5039f60fefe5fc2fcad67\" }, \"links\" : { \"self\" : \"/permissions/bf716babb70b73b89c870fccce00233f\" , \"related\" : \"/sharings/bf716babb70b73b89c870fccce00233a\" } }, \"included\" : [ { \"type\" : \"io.cozy.sharings.members\" , \"attributes\" : { \"status\" : \"seen\" , \"name\" : \"Bob\" , \"email\" : \"bob@cozy.localhost\" } } ] } POST /permissions \u00b6 Create a new set of permissions. It can also associates one or more codes to it, via the codes parameter in the query string. These codes can then be sent to other people as a way to give these permissions (sharing by links). For each code created, a corresponding shortcode is generated and can be used to shorten links for sharing. The codes parameter is a comma separed list of values. The role of these values is to identify the codes if you want to revoke some of them later. A ttl parameter can also be given to make the codes expires after a delay ( bigduration format ). If the ttl does not exceed 1 hour, it is possible to add a tinycode=true parameter to the query-string to have a shortcode of 6 digits. Note : it is only possible to create a strict subset of the permissions associated to the sent token. Request \u00b6 POST /permissions?codes=bob,jane&ttl=1D HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"password\" : \"HelloWorld!\" , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"type\" : \"share\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"codes\" : { \"bob\" : \"yuot7NaiaeGugh8T\" , \"jane\" : \"Yohyoo8BHahh1lie\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" , \"jane\" : \"123456aBCdef\" }, \"expires_at\" : 1483951978 , \"password\" : true , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } } GET /permissions/:id \u00b6 Return the informations about a set of permissions Request \u00b6 GET /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"type\" : \"share\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"codes\" : { \"bob\" : \"yuot7NaiaeGugh8T\" , \"jane\" : \"Yohyoo8BHahh1lie\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" , \"jane\" : \"123456aBCdef\" }, \"expires_at\" : 1483951978 , \"password\" : true , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } } PATCH /permissions/:id \u00b6 Add permissions in this permissions set. It can be used in inter-apps context as a way to give another app the permission for some data. For example, the contact application can send a \u201c pick a photo \u201d intent to the photos application with its permission id, and the photos app can then let the user choose a photo and give the contacts application the permissions to use it. This route also accepts a document metadata to update document informations. Request to add / remove codes with a document metadata \u00b6 PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"codes\" : { \"jane\" : \"Yohyoo8BHahh1lie\" } }, \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"updatedAt\" : \"2019-05-14T12:00:37.372193145+02:00\" } } } Request to add permissions \u00b6 PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"permissions\" : { \"add-this\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"some-picture-id\" ] } } } } } Request to remove permissions \u00b6 PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"permissions\" : { \"remove-this\" : {} } } } } Reponse \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"type\" : \"share\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"codes\" : { \"bob\" : \"yuot7NaiaeGugh8T\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" }, \"expires_at\" : 1483951978 , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } } DELETE /permissions/:id \u00b6 Delete a set of permissions. For example, some permissions were used by a user to share a photo album with her friends, and then she changed her mind and cancel the sharing. Request \u00b6 DELETE /permissions/fa11561c-d645-11e6-83df-cbf577804d55 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Reponse \u00b6 HTTP / 1.1 204 No Content POST /permissions/exists \u00b6 List permissions for some documents Request \u00b6 POST /permissions/exists HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] } Reponse \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" , \"verbs\" :[ \"GET\" ] }, { \"type\" : \"io.cozy.files\" , \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"verbs\" :[ \"GET\" , \"POST\" ] } ] } PATCH /permissions/apps/:slug \u00b6 Add permissions or remove permissions to the web application with specified slug. It behaves like the PATCH /permissions/:id route. See this route for more examples. PATCH /permissions/konnectors/:slug \u00b6 Add permissions or remove permissions to the konnector with specified slug. It behaves like the PATCH /permissions/:id route. See this route for more examples. GET /permissions/doctype/:doctype/shared-by-link \u00b6 List permissions for a doctype that are used for a \u201cshare by links\u201d. This endpoint is paginated, with a default number of 30 items per page, and a limit of 100 items per page. Request \u00b6 GET /permissions/doctype/io.cozy.events/shared-by-link HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json Reponse \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.permissions\" , \"id\" : \"c47f82396d09bfcd270343c5855b30a0\" , \"attributes\" : { \"type\" : \"share\" , \"permissions\" : { \"rule0\" : { \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"PATCH\" , \"DELETE\" ], \"values\" : [ \"c47f82396d09bfcd270343c5855b0eea\" ] } }, \"codes\" : { \"bob\" : \"secret\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" } }, \"meta\" : { \"rev\" : \"1-d46b6358683b80c8d59fc55d6de54127\" }, \"links\" : { \"self\" : \"/permissions/c47f82396d09bfcd270343c5855b30a0\" } }, { \"type\" : \"io.cozy.permissions\" , \"id\" : \"c47f82396d09bfcd270343c5855b351a\" , \"attributes\" : { \"type\" : \"share\" , \"permissions\" : { \"rule0\" : { \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"c47f82396d09bfcd270343c5855b169b\" ] } }, \"codes\" : { \"bob\" : \"secret\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" } }, \"meta\" : { \"rev\" : \"1-920af658575a56e9e84685f1b09e5c23\" }, \"links\" : { \"self\" : \"/permissions/c47f82396d09bfcd270343c5855b351a\" } } ] } Permissions required: GET on the whole doctype", "title": "/permissions - Permissions"}, {"location": "cozy-stack/permissions/#permissions", "text": "", "title": "Permissions"}, {"location": "cozy-stack/permissions/#when-the-permissions-are-used", "text": "The permissions are used when a request is made to cozy stack. It allows to let the owner of the cozy instance controls the access to her data, files and actions on them. The permissions are given in several contexts. Let\u2019s see them!", "title": "When the permissions are used?"}, {"location": "cozy-stack/permissions/#client-side-apps", "text": "When the user installs a new client-side app, she is asked to accept an initial set of permissions for this app. This set of permissions is described in the manifest of the app. Later, the application can gain more permissions via the intents and optional permissions. See below for more details. When the authentified user access a client-side app, the app receives a token from the stack that can be used in later requests to the stack as a proof of the permissions it owns.", "title": "Client-side apps"}, {"location": "cozy-stack/permissions/#external-apps-via-oauth2", "text": "An external application can ask for permissions via the OAuth2 dance, and use them later with the access token. The permissions are in the scope parameter.", "title": "External apps via OAuth2"}, {"location": "cozy-stack/permissions/#sharing-with-other-users", "text": "The owner of a cozy instance can share some documents and files with other users. It can be done in two ways: If the other user also has a cozy, it can be a cozy-to-cozy sharing. Else, the owner can give to him a link with a code or a shortcode.", "title": "Sharing with other users"}, {"location": "cozy-stack/permissions/#what-is-a-permission", "text": "A permission gives the right for a request having it to do something on the stack. It is defined by four components.", "title": "What is a permission?"}, {"location": "cozy-stack/permissions/#type", "text": "type is the attribute used in JSON-API or the doctype for the Data System. It is the only mandatory component. If just the type is specified, it gives access to all the operations on this type . For example, a permission on type io.cozy.contacts gives the right to create, read, update and delete any contact, and to fetch all the contacts. A permission on type io.cozy.files allow to access and modify any file or directory. Some known types: io.cozy.files , for files and folder in the VFS io.cozy.apps , for apps io.cozy.settings , for the settings io.cozy.jobs and io.cozy.triggers , for jobs io.cozy.oauth.clients , to list and revoke OAuth 2 clients It is also possible to use a wildcard to use a doctype and its sub-doctypes if the doctype contains at least 3 . . For example, io.cozy.bank.* will give access to io.cozy.bank , io.cozy.bank.accounts , io.cozy.bank.accounts.stats , io.cozy.bank.settings , etc. io.cozy.* will give you an error.", "title": "Type"}, {"location": "cozy-stack/permissions/#verbs", "text": "It says which HTTP verbs can be used for requests to the cozy-stack. GET will give read-only access, DELETE can be used for deletions, etc. Verbs should be declared in a list, like [\"GET\", \"POST\", \"DELETE\"] , and use [\"ALL\"] as a shortcut for [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"] (it is the default). Note : HEAD is implicitely implied when GET is allowed. OPTIONS for Cross-Origin Resources Sharing is always allowed, the stack does not have the informations about the permission when it answers the request.", "title": "Verbs"}, {"location": "cozy-stack/permissions/#values", "text": "It\u2019s possible to restrict the permissions to only some documents of a doctype, or to just some files and folders. You can give a list of ids in values . Note : a permission for a folder also gives permissions with same verbs for files and folders inside it.", "title": "Values"}, {"location": "cozy-stack/permissions/#selector", "text": "By default, the values are checked with the id . But it\u2019s possible to use a selector to filter on another field . In particular, it can be used for sharing. A user may share a calendar and all the events inside it. It will be done with two permissions. The first one is for the calendar: { \"type\" : \"io.cozy.calendars\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"1355812c-d41e-11e6-8467-53be4648e3ad\" ] } And the other is for the events inside the calendar: { \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"GET\" ], \"selector\" : \"calendar-id\" , \"values\" : [ \"1355812c-d41e-11e6-8467-53be4648e3ad\" ] }", "title": "Selector"}, {"location": "cozy-stack/permissions/#what-format-for-a-permission", "text": "", "title": "What format for a permission?"}, {"location": "cozy-stack/permissions/#json", "text": "The prefered format for permissions is JSON. Each permission is a map with the type , verbs , values and selector see above, plus a description that can be used to give more informations to the user. Only the type field is mandatory. In the manifest, the permissions are regrouped in a map. The key is not very relevant, it\u2019s just here for localization. The same key is used in the locales field to identify the permission. Example: { \"permissions\" : { \"contacts\" : { \"description\" : \"Required for autocompletion on @name\" , \"type\" : \"io.cozy.contacts\" , \"verbs\" : [ \"GET\" ] }, \"images\" : { \"description\" : \"Required for the background\" , \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" , \"POST\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] }, \"mail\" : { \"description\" : \"Required to send a congratulations email to your friends\" , \"type\" : \"io.cozy.jobs\" , \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } }", "title": "JSON"}, {"location": "cozy-stack/permissions/#inline", "text": "OAuth2 as a scope parameter for defining the permissions given to the application. But it\u2019s only a string, not a JSON. In that case, we use a space delimited list of permissions, each permission is written compactly with : between the components. Example: io.cozy.contacts io.cozy.files:GET:io.cozy.files.music-dir io.cozy.jobs:POST:sendmail:worker Note : the verbs component can\u2019t be omitted when the values and selector are used.", "title": "Inline"}, {"location": "cozy-stack/permissions/#inspiration", "text": "Access control on other similar platforms", "title": "Inspiration"}, {"location": "cozy-stack/permissions/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/permissions/#get-permissionsself", "text": "List the permissions for a given token", "title": "GET /permissions/self"}, {"location": "cozy-stack/permissions/#request", "text": "GET /permissions/self HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/permissions/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.permissions\" , \"id\" : \"5a9c1844-d427-11e6-ab36-2b684d437b0d\" , \"attributes\" : { \"type\" : \"app\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"permissions\" : { \"contacts\" : { \"description\" : \"Required for autocompletion on @name\" , \"type\" : \"io.cozy.contacts\" , \"verbs\" : [ \"GET\" ] }, \"images\" : { \"description\" : \"Required for the background\" , \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] }, \"mail\" : { \"description\" : \"Required to send a congratulations email to your friends\" , \"type\" : \"io.cozy.jobs\" , \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } } }", "title": "Response"}, {"location": "cozy-stack/permissions/#special-case", "text": "The token can be a sharecode when a member of a sharing is previewing a sharing. When it is the case, the member information from the sharing is included in the response, like this: { \"data\" : { \"type\" : \"io.cozy.permissions\" , \"id\" : \"bf716babb70b73b89c870fccce00233f\" , \"attributes\" : { \"type\" : \"share-preview\" , \"source_id\" : \"io.cozy.sharings/bf716babb70b73b89c870fccce00233a\" , \"permissions\" : { \"Essai\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"c2930bef3705096d63f5c8fb60019cc0\" ] } }, \"cozyMetadata\" : { \"doctypeVersion\" : \"\" , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-10-19T16:12:31.440253797+02:00\" , \"createdByApp\" : \"drive\" , \"updatedAt\" : \"2020-10-19T16:12:31.440253797+02:00\" } }, \"meta\" : { \"rev\" : \"1-18c3bc158cf5039f60fefe5fc2fcad67\" }, \"links\" : { \"self\" : \"/permissions/bf716babb70b73b89c870fccce00233f\" , \"related\" : \"/sharings/bf716babb70b73b89c870fccce00233a\" } }, \"included\" : [ { \"type\" : \"io.cozy.sharings.members\" , \"attributes\" : { \"status\" : \"seen\" , \"name\" : \"Bob\" , \"email\" : \"bob@cozy.localhost\" } } ] }", "title": "Special case"}, {"location": "cozy-stack/permissions/#post-permissions", "text": "Create a new set of permissions. It can also associates one or more codes to it, via the codes parameter in the query string. These codes can then be sent to other people as a way to give these permissions (sharing by links). For each code created, a corresponding shortcode is generated and can be used to shorten links for sharing. The codes parameter is a comma separed list of values. The role of these values is to identify the codes if you want to revoke some of them later. A ttl parameter can also be given to make the codes expires after a delay ( bigduration format ). If the ttl does not exceed 1 hour, it is possible to add a tinycode=true parameter to the query-string to have a shortcode of 6 digits. Note : it is only possible to create a strict subset of the permissions associated to the sent token.", "title": "POST /permissions"}, {"location": "cozy-stack/permissions/#request_1", "text": "POST /permissions?codes=bob,jane&ttl=1D HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"password\" : \"HelloWorld!\" , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } }", "title": "Request"}, {"location": "cozy-stack/permissions/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"type\" : \"share\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"codes\" : { \"bob\" : \"yuot7NaiaeGugh8T\" , \"jane\" : \"Yohyoo8BHahh1lie\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" , \"jane\" : \"123456aBCdef\" }, \"expires_at\" : 1483951978 , \"password\" : true , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } }", "title": "Response"}, {"location": "cozy-stack/permissions/#get-permissionsid", "text": "Return the informations about a set of permissions", "title": "GET /permissions/:id"}, {"location": "cozy-stack/permissions/#request_2", "text": "GET /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/permissions/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"type\" : \"share\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"codes\" : { \"bob\" : \"yuot7NaiaeGugh8T\" , \"jane\" : \"Yohyoo8BHahh1lie\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" , \"jane\" : \"123456aBCdef\" }, \"expires_at\" : 1483951978 , \"password\" : true , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } }", "title": "Response"}, {"location": "cozy-stack/permissions/#patch-permissionsid", "text": "Add permissions in this permissions set. It can be used in inter-apps context as a way to give another app the permission for some data. For example, the contact application can send a \u201c pick a photo \u201d intent to the photos application with its permission id, and the photos app can then let the user choose a photo and give the contacts application the permissions to use it. This route also accepts a document metadata to update document informations.", "title": "PATCH /permissions/:id"}, {"location": "cozy-stack/permissions/#request-to-add-remove-codes-with-a-document-metadata", "text": "PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"codes\" : { \"jane\" : \"Yohyoo8BHahh1lie\" } }, \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"updatedAt\" : \"2019-05-14T12:00:37.372193145+02:00\" } } }", "title": "Request to add / remove codes with a document metadata"}, {"location": "cozy-stack/permissions/#request-to-add-permissions", "text": "PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"permissions\" : { \"add-this\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"some-picture-id\" ] } } } } }", "title": "Request to add permissions"}, {"location": "cozy-stack/permissions/#request-to-remove-permissions", "text": "PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : { \"attributes\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"permissions\" : { \"remove-this\" : {} } } } }", "title": "Request to remove permissions"}, {"location": "cozy-stack/permissions/#reponse", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"type\" : \"io.cozy.permissions\" , \"attributes\" : { \"type\" : \"share\" , \"source_id\" : \"io.cozy.apps/my-awesome-game\" , \"codes\" : { \"bob\" : \"yuot7NaiaeGugh8T\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" }, \"expires_at\" : 1483951978 , \"permissions\" : { \"images\" : { \"type\" : \"io.cozy.files\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"io.cozy.files.music-dir\" ] } } } } }", "title": "Reponse"}, {"location": "cozy-stack/permissions/#delete-permissionsid", "text": "Delete a set of permissions. For example, some permissions were used by a user to share a photo album with her friends, and then she changed her mind and cancel the sharing.", "title": "DELETE /permissions/:id"}, {"location": "cozy-stack/permissions/#request_3", "text": "DELETE /permissions/fa11561c-d645-11e6-83df-cbf577804d55 HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ", "title": "Request"}, {"location": "cozy-stack/permissions/#reponse_1", "text": "HTTP / 1.1 204 No Content", "title": "Reponse"}, {"location": "cozy-stack/permissions/#post-permissionsexists", "text": "List permissions for some documents", "title": "POST /permissions/exists"}, {"location": "cozy-stack/permissions/#request_4", "text": "POST /permissions/exists HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4cfbd8be-8968-11e6-9708-ef55b7c20863\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] }", "title": "Request"}, {"location": "cozy-stack/permissions/#reponse_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" , \"verbs\" :[ \"GET\" ] }, { \"type\" : \"io.cozy.files\" , \"id\" : \"a340d5e0-d647-11e6-b66c-5fc9ce1e17c6\" , \"verbs\" :[ \"GET\" , \"POST\" ] } ] }", "title": "Reponse"}, {"location": "cozy-stack/permissions/#patch-permissionsappsslug", "text": "Add permissions or remove permissions to the web application with specified slug. It behaves like the PATCH /permissions/:id route. See this route for more examples.", "title": "PATCH /permissions/apps/:slug"}, {"location": "cozy-stack/permissions/#patch-permissionskonnectorsslug", "text": "Add permissions or remove permissions to the konnector with specified slug. It behaves like the PATCH /permissions/:id route. See this route for more examples.", "title": "PATCH /permissions/konnectors/:slug"}, {"location": "cozy-stack/permissions/#get-permissionsdoctypedoctypeshared-by-link", "text": "List permissions for a doctype that are used for a \u201cshare by links\u201d. This endpoint is paginated, with a default number of 30 items per page, and a limit of 100 items per page.", "title": "GET /permissions/doctype/:doctype/shared-by-link"}, {"location": "cozy-stack/permissions/#request_5", "text": "GET /permissions/doctype/io.cozy.events/shared-by-link HTTP / 1.1 Host : cozy.example.net Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ Content-Type : application/vnd.api+json Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/permissions/#reponse_3", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.permissions\" , \"id\" : \"c47f82396d09bfcd270343c5855b30a0\" , \"attributes\" : { \"type\" : \"share\" , \"permissions\" : { \"rule0\" : { \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"PATCH\" , \"DELETE\" ], \"values\" : [ \"c47f82396d09bfcd270343c5855b0eea\" ] } }, \"codes\" : { \"bob\" : \"secret\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" } }, \"meta\" : { \"rev\" : \"1-d46b6358683b80c8d59fc55d6de54127\" }, \"links\" : { \"self\" : \"/permissions/c47f82396d09bfcd270343c5855b30a0\" } }, { \"type\" : \"io.cozy.permissions\" , \"id\" : \"c47f82396d09bfcd270343c5855b351a\" , \"attributes\" : { \"type\" : \"share\" , \"permissions\" : { \"rule0\" : { \"type\" : \"io.cozy.events\" , \"verbs\" : [ \"GET\" ], \"values\" : [ \"c47f82396d09bfcd270343c5855b169b\" ] } }, \"codes\" : { \"bob\" : \"secret\" }, \"shortcodes\" : { \"bob\" : \"abcdeFGHIJ01\" } }, \"meta\" : { \"rev\" : \"1-920af658575a56e9e84685f1b09e5c23\" }, \"links\" : { \"self\" : \"/permissions/c47f82396d09bfcd270343c5855b351a\" } } ] } Permissions required: GET on the whole doctype", "title": "Reponse"}, {"location": "cozy-stack/pouchdb-quirks/", "text": "Table of contents Pouchdb Mango Quirks \u00b6 The findings below were obtained while working on sorting performance in Cozy Drive. For reference, the final PR can be seen here . Understanding what\u2019s going on \u00b6 Before diving into some of the quirks, it\u2019s important to understand some things when it comes to Pouchdb and especially Mango queries. First, you can add a plugin called pouchdb-debug and enable extra logs with PouchDB.debug.enable( \"pouchdb:find\" ); . This will add explanation about the queries you run in the console and it\u2019s very helpful to understand what\u2019s going on under the hood. You will realize that Pouchdb operates in 2 phases: one part of your query may be done using indexes, and the other may be done in memory. Long story short: anything done in memory has significant performance impacts, especially as the number of items gets larger. A more detailed guide can be found here . About indexes \u00b6 Creating an index takes some time, but the first query will also take time \u2014 you are encouraged to warm up the indexes by firing a query that uses it before it is actually needed. An exemple implementation can be found here . If there is a change in the underlying documents, the index will be partially recalculated on the next query. The post-replication callback may be a good place to warm up the index again. By default, Pouch will try to find the best index to use on your query. For more advanced queries, you generally want to force it with the use_index option. If the query and the index you force are not compatible, Pouch will emit an error and not run the query at all. Indexing more than one field \u00b6 Creating an index on several fields is not the same as creating multiple indexes on one field each. The effects of a single index on multiple fields is illustrated in the official docs and is important to understand. Furthermore, the order in which fields are indexed on a multi-index is significant, most notably when it comes to sorting. If you declare an index on the fields ['name', 'age'] , you should also sort them by ['name', 'age'] . Sorting them in a different order or using other fields will likely be done in memory and kill your performance. Avoiding in memory selectors \u00b6 Filtering results with a selector on a field that has not been indexed is almost guaranteed to be done in memory and should be avoided. Since you can\u2019t have too many indexes, some filtering may have to be done in your own code \u2014 but if you can narrow down the results beforehand, that shouldn\u2019t be a problem. Even selectors on indexed field may end up being done in memory. Operators that don\u2019t rely on equality such as $ne should typically be avoided. Even equality operators run on secondary fields tend to be done in memory, and should therefor be used with care.", "title": " /data - PouchDB Quirks"}, {"location": "cozy-stack/pouchdb-quirks/#pouchdb-mango-quirks", "text": "The findings below were obtained while working on sorting performance in Cozy Drive. For reference, the final PR can be seen here .", "title": "Pouchdb Mango Quirks"}, {"location": "cozy-stack/pouchdb-quirks/#understanding-whats-going-on", "text": "Before diving into some of the quirks, it\u2019s important to understand some things when it comes to Pouchdb and especially Mango queries. First, you can add a plugin called pouchdb-debug and enable extra logs with PouchDB.debug.enable( \"pouchdb:find\" ); . This will add explanation about the queries you run in the console and it\u2019s very helpful to understand what\u2019s going on under the hood. You will realize that Pouchdb operates in 2 phases: one part of your query may be done using indexes, and the other may be done in memory. Long story short: anything done in memory has significant performance impacts, especially as the number of items gets larger. A more detailed guide can be found here .", "title": "Understanding what's going on"}, {"location": "cozy-stack/pouchdb-quirks/#about-indexes", "text": "Creating an index takes some time, but the first query will also take time \u2014 you are encouraged to warm up the indexes by firing a query that uses it before it is actually needed. An exemple implementation can be found here . If there is a change in the underlying documents, the index will be partially recalculated on the next query. The post-replication callback may be a good place to warm up the index again. By default, Pouch will try to find the best index to use on your query. For more advanced queries, you generally want to force it with the use_index option. If the query and the index you force are not compatible, Pouch will emit an error and not run the query at all.", "title": "About indexes"}, {"location": "cozy-stack/pouchdb-quirks/#indexing-more-than-one-field", "text": "Creating an index on several fields is not the same as creating multiple indexes on one field each. The effects of a single index on multiple fields is illustrated in the official docs and is important to understand. Furthermore, the order in which fields are indexed on a multi-index is significant, most notably when it comes to sorting. If you declare an index on the fields ['name', 'age'] , you should also sort them by ['name', 'age'] . Sorting them in a different order or using other fields will likely be done in memory and kill your performance.", "title": "Indexing more than one field"}, {"location": "cozy-stack/pouchdb-quirks/#avoiding-in-memory-selectors", "text": "Filtering results with a selector on a field that has not been indexed is almost guaranteed to be done in memory and should be avoided. Since you can\u2019t have too many indexes, some filtering may have to be done in your own code \u2014 but if you can narrow down the results beforehand, that shouldn\u2019t be a problem. Even selectors on indexed field may end up being done in memory. Operators that don\u2019t rely on equality such as $ne should typically be avoided. Even equality operators run on secondary fields tend to be done in memory, and should therefor be used with care.", "title": "Avoiding in memory selectors"}, {"location": "cozy-stack/public/", "text": "Table of contents Public routes \u00b6 These routes are public: no authentication is required for them. Avatar \u00b6 GET /public/avatar \u00b6 Returns an image chosen by the user as their avatar. If no image has been chosen, a fallback will be used, depending of the fallback parameter in the query-string: default : a default image that shows the Cozy Cloud logo, but it can be overriden by dynamic assets per context initials : a generated image with the initials of the owner\u2019s public name 404 : just a 404 - Not found error. Prelogin \u00b6 GET /public/prelogin \u00b6 This route returns information that could be useful to show a login page (like in the flagship app). Request \u00b6 GET /public/prelogin HTTP / 1.1 Host : cozy.localhost:8080 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"Kdf\" : 0 , \"KdfIterations\" : 100000 , \"OIDC\" : false , \"FranceConnect\" : false , \"locale\" : \"en\" , \"magic_link\" : false , \"name\" : \"Claude\" } Response when the instance has not been onboarded \u00b6 HTTP / 1.1 412 Precondition failed Content-Type : application/json { \"error\" : \"the instance has not been onboarded\" }", "title": "/public - Public"}, {"location": "cozy-stack/public/#public-routes", "text": "These routes are public: no authentication is required for them.", "title": "Public routes"}, {"location": "cozy-stack/public/#avatar", "text": "", "title": "Avatar"}, {"location": "cozy-stack/public/#get-publicavatar", "text": "Returns an image chosen by the user as their avatar. If no image has been chosen, a fallback will be used, depending of the fallback parameter in the query-string: default : a default image that shows the Cozy Cloud logo, but it can be overriden by dynamic assets per context initials : a generated image with the initials of the owner\u2019s public name 404 : just a 404 - Not found error.", "title": "GET /public/avatar"}, {"location": "cozy-stack/public/#prelogin", "text": "", "title": "Prelogin"}, {"location": "cozy-stack/public/#get-publicprelogin", "text": "This route returns information that could be useful to show a login page (like in the flagship app).", "title": "GET /public/prelogin"}, {"location": "cozy-stack/public/#request", "text": "GET /public/prelogin HTTP / 1.1 Host : cozy.localhost:8080", "title": "Request"}, {"location": "cozy-stack/public/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"Kdf\" : 0 , \"KdfIterations\" : 100000 , \"OIDC\" : false , \"FranceConnect\" : false , \"locale\" : \"en\" , \"magic_link\" : false , \"name\" : \"Claude\" }", "title": "Response"}, {"location": "cozy-stack/public/#response-when-the-instance-has-not-been-onboarded", "text": "HTTP / 1.1 412 Precondition failed Content-Type : application/json { \"error\" : \"the instance has not been onboarded\" }", "title": "Response when the instance has not been onboarded"}, {"location": "cozy-stack/realtime-internals/", "text": "Table of contents Realtime internals \u00b6 The stack has a realtime package, which can be seen as a pub/sub of events. Most events are created by the CouchDB package when a document is created, updated or deleted, but there are also some synthetic events like the end of the initial synchronization of a Cozy to Cozy sharing. Those events can be sent via the realtime websockets to clients and can be used by the scheduler to fire triggers. There are two versions of the Hub implementation: an in-memory one, and a redis one. The in-memory one is used by the developers and the self-hosted instances. The redis one is used when there are several stacks, to send the events from one stack to the others, and then use the in-memory hub internally. Model \u00b6 Let\u2019s start by the most basic unit. The EventsChan is go channel for sending events. Then, we have the topic. There is one topic per doctype of an instance if there is at least one subscriber for it. It receives events via its broadcast channel. The mem hub is where the stack keeps the list of topics. There is a mutex to protect against race conditions (a sync.Map is not enough, as we also need to initialize topics). The redis hub is here to ensure that each stack can publish the events in its own mem hub. It also has the concept of \u201cfirehose\u201d: it is a special topic where every events created on this stack are published. It is used by the scheduler for the events trigger. The mem hub is not used for that, as we don\u2019t want to fire the same triggers n times (one on each stack), but only once. And then, we have the subscribers. A subscriber is used to receive events. It is tied to an instance (via the prefixer) and can subscribes to doctypes. With the instance + doctype, the hub can find the right topic, and adds the subscriber to the subs map of the topic. We have the notion of filter because the subscriber may want to receive the events for the whole doctype (subscribe) or just for some identifiers (watch). Workflow of a realtime event (redis hub) \u00b6 A client connects to the realtime websocket and subscribe to some doctypes The stack creates a Subscriber for it and connects it to the mem hub. Another client sends an HTTP request, which is makes a CouchDB write This create an event to publish on the redis hub The event is sent to redis (PUB command) Each stack listens to redis and receive this event The redis hub send the event to the mem hub The mem hub finds the topic for this event, sees that there is subscriber for it, and forward it the event The subscriber sends the event to the client The redis hub also send the event to the firehose topic (only on the stack where the event was created) The redis scheduler is listening to the broadcast and receive the events With this event, the redis scheduler can look at the matching triggers, and fire them", "title": "Realtime internals"}, {"location": "cozy-stack/realtime-internals/#realtime-internals", "text": "The stack has a realtime package, which can be seen as a pub/sub of events. Most events are created by the CouchDB package when a document is created, updated or deleted, but there are also some synthetic events like the end of the initial synchronization of a Cozy to Cozy sharing. Those events can be sent via the realtime websockets to clients and can be used by the scheduler to fire triggers. There are two versions of the Hub implementation: an in-memory one, and a redis one. The in-memory one is used by the developers and the self-hosted instances. The redis one is used when there are several stacks, to send the events from one stack to the others, and then use the in-memory hub internally.", "title": "Realtime internals"}, {"location": "cozy-stack/realtime-internals/#model", "text": "Let\u2019s start by the most basic unit. The EventsChan is go channel for sending events. Then, we have the topic. There is one topic per doctype of an instance if there is at least one subscriber for it. It receives events via its broadcast channel. The mem hub is where the stack keeps the list of topics. There is a mutex to protect against race conditions (a sync.Map is not enough, as we also need to initialize topics). The redis hub is here to ensure that each stack can publish the events in its own mem hub. It also has the concept of \u201cfirehose\u201d: it is a special topic where every events created on this stack are published. It is used by the scheduler for the events trigger. The mem hub is not used for that, as we don\u2019t want to fire the same triggers n times (one on each stack), but only once. And then, we have the subscribers. A subscriber is used to receive events. It is tied to an instance (via the prefixer) and can subscribes to doctypes. With the instance + doctype, the hub can find the right topic, and adds the subscriber to the subs map of the topic. We have the notion of filter because the subscriber may want to receive the events for the whole doctype (subscribe) or just for some identifiers (watch).", "title": "Model"}, {"location": "cozy-stack/realtime-internals/#workflow-of-a-realtime-event-redis-hub", "text": "A client connects to the realtime websocket and subscribe to some doctypes The stack creates a Subscriber for it and connects it to the mem hub. Another client sends an HTTP request, which is makes a CouchDB write This create an event to publish on the redis hub The event is sent to redis (PUB command) Each stack listens to redis and receive this event The redis hub send the event to the mem hub The mem hub finds the topic for this event, sees that there is subscriber for it, and forward it the event The subscriber sends the event to the client The redis hub also send the event to the firehose topic (only on the stack where the event was created) The redis scheduler is listening to the broadcast and receive the events With this event, the redis scheduler can look at the matching triggers, and fire them", "title": "Workflow of a realtime event (redis hub)"}, {"location": "cozy-stack/realtime/", "text": "Table of contents Realtime \u00b6 The stack offers a way for applications to be notified in real-time of what happens on the server via a websocket connection. We start with a normal websocket handshake. Websockets include a protocol description in handshake, the protocol described below is hereby named io.cozy.websocket . Changes to the websocket protocol should be given versions, support for older version should be maintained when reasonable. GET /realtime/ HTTP / 1.1 Host : mycozy.example.com Upgrade : websocket Connection : Upgrade Origin : http://calendar.mycozy.example.com Sec-WebSocket-Key : x3JrandomLkh9GBhXDw== Sec-WebSocket-Protocol : io.cozy.websocket Sec-WebSocket-Version : 13 Then messages are sent using json: client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.files\"}} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.contacts\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"idA\", \"rev\": \"2-705...\", \"type\": \"io.cozy.contacts\", \"doc\": {embeded doc ...}}} server > {\"event\": \"DELETED\", \"payload\": {\"id\": \"idA\", \"rev\": \"3-541...\", \"type\": \"io.cozy.contacts\"}} client > {\"method\": \"UNSUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.contacts\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"idB\", \"rev\": \"6-457...\", \"type\": \"io.cozy.files\", \"doc\": {embeded doc ...}}} AUTH \u00b6 It must be the first command to be sent. The client gives its token with this command, and the stack will use it to know which are the permissions of the app. {\"method\": \"AUTH\", \"payload\": \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhcHAiLCJpYXQiOjE0OTg4MTY1OTEsImlzcyI6ImNvenkudG9vbHM6ODA4MCIsInN1YiI6Im1pbmkifQ.eH9DhoHz7rg8gR7noAiKfeo8eL3Q_PzyuskO_x3T8Hlh9q_IV-4zqoGtjTiO7luD6_VcLboEU-6o3XBek84VTg\"} SUBSCRIBE \u00b6 A client can send a SUBSCRIBE request to be notified of changes. The payload is a selector for the events it wishes to receive For now the only possible selector is on type & optionally id. { \"method\" : \"SUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" }} { \"method\" : \"SUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" , \"id\" : \"idA\" }} In order to subscribe, a client must have permission GET on the passed selector. Otherwise an error is passed in the message feed. server > {\"event\": \"error\", \"payload\": { \"status\": \"403 Forbidden\" \"code\": \"forbidden\" \"title\":\"The Application can't subscribe to io.cozy.files\" \"source\": {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\":\"io.cozy.files\"} } }} UNSUBSCRIBE \u00b6 A client can send an UNSUBSCRIBE request to no longer be notified of changes from a previous request. { \"method\" : \"UNSUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" }} { \"method\" : \"UNSUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" , \"id\" : \"idA\" }} Response messages \u00b6 A message sent by the server after a subscribe will be a JSON object with two keys at root: event and payload . event will be one of CREATED , UPDATED , DELETED (when a document is written in CouchDB), NOTIFIED (see below), or error . The payload will be a map with type , id , and doc . The payload can also contain an optional old with the old values for the document in case of UPDATED or DELETED . Synthetic types \u00b6 The stack an inject some synthetic events for documents that are not persisted in CouchDB like classical doctypes: Auth confirmations Initial sync for sharings Thumbnails for files Telepointers for notes POST /realtime/:doctype/:id \u00b6 This route can be used to send documents in the real-time without having to persist them in CouchDB (and they can\u2019t be used for triggers). A permission on POST for the document :doctype/:id is required to use this endpoint. Request \u00b6 POST /realtime/io.cozy.jobs/2c577f00-145a-0138-f569-543d7eb8149c HTTP / 1.1 Content-Type : application/json { \"subtype\" : \"progress\" , \"imported\" : 10 , \"total\" : 42 } Response \u00b6 HTTP / 1.1 204 No Content Websocket \u00b6 server > {\"event\": \"NOTIFIED\", \"payload\": {\"id\": \"2c577f00-145a-0138-f569-543d7eb8149c\", \"type\": \"io.cozy.jobs\", \"doc\": {\"subtype\": \"progress\", \"imported\": 10, \"total\": 42}}}", "title": "/realtime - Realtime"}, {"location": "cozy-stack/realtime/#realtime", "text": "The stack offers a way for applications to be notified in real-time of what happens on the server via a websocket connection. We start with a normal websocket handshake. Websockets include a protocol description in handshake, the protocol described below is hereby named io.cozy.websocket . Changes to the websocket protocol should be given versions, support for older version should be maintained when reasonable. GET /realtime/ HTTP / 1.1 Host : mycozy.example.com Upgrade : websocket Connection : Upgrade Origin : http://calendar.mycozy.example.com Sec-WebSocket-Key : x3JrandomLkh9GBhXDw== Sec-WebSocket-Protocol : io.cozy.websocket Sec-WebSocket-Version : 13 Then messages are sent using json: client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.files\"}} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.contacts\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"idA\", \"rev\": \"2-705...\", \"type\": \"io.cozy.contacts\", \"doc\": {embeded doc ...}}} server > {\"event\": \"DELETED\", \"payload\": {\"id\": \"idA\", \"rev\": \"3-541...\", \"type\": \"io.cozy.contacts\"}} client > {\"method\": \"UNSUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.contacts\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"idB\", \"rev\": \"6-457...\", \"type\": \"io.cozy.files\", \"doc\": {embeded doc ...}}}", "title": "Realtime"}, {"location": "cozy-stack/realtime/#auth", "text": "It must be the first command to be sent. The client gives its token with this command, and the stack will use it to know which are the permissions of the app. {\"method\": \"AUTH\", \"payload\": \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhcHAiLCJpYXQiOjE0OTg4MTY1OTEsImlzcyI6ImNvenkudG9vbHM6ODA4MCIsInN1YiI6Im1pbmkifQ.eH9DhoHz7rg8gR7noAiKfeo8eL3Q_PzyuskO_x3T8Hlh9q_IV-4zqoGtjTiO7luD6_VcLboEU-6o3XBek84VTg\"}", "title": "AUTH"}, {"location": "cozy-stack/realtime/#subscribe", "text": "A client can send a SUBSCRIBE request to be notified of changes. The payload is a selector for the events it wishes to receive For now the only possible selector is on type & optionally id. { \"method\" : \"SUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" }} { \"method\" : \"SUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" , \"id\" : \"idA\" }} In order to subscribe, a client must have permission GET on the passed selector. Otherwise an error is passed in the message feed. server > {\"event\": \"error\", \"payload\": { \"status\": \"403 Forbidden\" \"code\": \"forbidden\" \"title\":\"The Application can't subscribe to io.cozy.files\" \"source\": {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\":\"io.cozy.files\"} } }}", "title": "SUBSCRIBE"}, {"location": "cozy-stack/realtime/#unsubscribe", "text": "A client can send an UNSUBSCRIBE request to no longer be notified of changes from a previous request. { \"method\" : \"UNSUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" }} { \"method\" : \"UNSUBSCRIBE\" , \"payload\" : { \"type\" : \"[desired doctype]\" , \"id\" : \"idA\" }}", "title": "UNSUBSCRIBE"}, {"location": "cozy-stack/realtime/#response-messages", "text": "A message sent by the server after a subscribe will be a JSON object with two keys at root: event and payload . event will be one of CREATED , UPDATED , DELETED (when a document is written in CouchDB), NOTIFIED (see below), or error . The payload will be a map with type , id , and doc . The payload can also contain an optional old with the old values for the document in case of UPDATED or DELETED .", "title": "Response messages"}, {"location": "cozy-stack/realtime/#synthetic-types", "text": "The stack an inject some synthetic events for documents that are not persisted in CouchDB like classical doctypes: Auth confirmations Initial sync for sharings Thumbnails for files Telepointers for notes", "title": "Synthetic types"}, {"location": "cozy-stack/realtime/#post-realtimedoctypeid", "text": "This route can be used to send documents in the real-time without having to persist them in CouchDB (and they can\u2019t be used for triggers). A permission on POST for the document :doctype/:id is required to use this endpoint.", "title": "POST /realtime/:doctype/:id"}, {"location": "cozy-stack/realtime/#request", "text": "POST /realtime/io.cozy.jobs/2c577f00-145a-0138-f569-543d7eb8149c HTTP / 1.1 Content-Type : application/json { \"subtype\" : \"progress\" , \"imported\" : 10 , \"total\" : 42 }", "title": "Request"}, {"location": "cozy-stack/realtime/#response", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/realtime/#websocket", "text": "server > {\"event\": \"NOTIFIED\", \"payload\": {\"id\": \"2c577f00-145a-0138-f569-543d7eb8149c\", \"type\": \"io.cozy.jobs\", \"doc\": {\"subtype\": \"progress\", \"imported\": 10, \"total\": 42}}}", "title": "Websocket"}, {"location": "cozy-stack/references-docs-in-vfs/", "text": "Table of contents References of documents in the Virtual File System \u00b6 What we want? \u00b6 Cozy applications can use data from the Data System and files from the Virtual File System. Of course, sometimes a link between data and files can be useful. For example, the application can have an album with photos. The album will be a document in CouchDB (with a title and other fields), but il will also list the files to use as photos. A direct way to do that is storing the files IDs in the album document. It\u2019s simple and will work pretty well if the files are manipulated only from this application. But, files are often accessed from other apps, like cozy-desktop and cozy-drive. To improve the User eXperience, it should be nice to alert the user when a file in an album is modified or deleted. When a file is modified, we can offer the user the choice between keeping the original version in the album, or using the new modified file. When a file is moved to the trash, we can alert the user and let him/her restore the file. Cozy-desktop, cozy-drive, and the other apps can\u2019t scan all the documents with many different doctypes to find all the references to a file to detect such cases. The goal of this document is to offer a way to do that, and it is called References . The references of a file are listed in its JSON-API representation in the references field, within the relationships object of data . Example \u00b6 { \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.txt\" , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references\" }, \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } } Routes \u00b6 POST /files/:file-id/relationships/referenced_by \u00b6 Add on a file one or more references to documents Request \u00b6 POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/relationships/referenced_by HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0\" } ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"2-de8d0ba2\" , \"count\" : 2 }, \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" }, { \"type\" : \"io.cozy.playlists\" , \"id\" : \"f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0\" } ] } DELETE /files/:file-id/relationships/referenced_by \u00b6 Remove one or more references to documents on a file Request \u00b6 DELETE /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/relationships/referenced_by HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0\" } ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"3-7ab812c0\" , \"count\" : 1 }, \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] } GET /data/:type/:doc-id/relationships/references \u00b6 Returns all the files id associated to an album or playlist. Contents is paginated following jsonapi conventions . The default limit is 100 entries. The maximal number of entries per page is 1000. It\u2019s also possible to sort the files by their datetime (for photos) with the sort query parameter: ?sort=datetime . Request \u00b6 GET /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4504f55c-e2e4-11e6-88f2-d77aeecab549\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4587727a-e2e4-11e6-bfe9-ef1be7df7f26\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"45d591d0-e2e4-11e6-ab9a-ff3b218e31cc\" } ] } POST /data/:type/:doc-id/relationships/references \u00b6 When creating an album or a playlist, it\u2019s tedious to add the references to it for each file individually. This route allows to make it in bulk. Request \u00b6 POST /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4504f55c-e2e4-11e6-88f2-d77aeecab549\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4587727a-e2e4-11e6-bfe9-ef1be7df7f26\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"45d591d0-e2e4-11e6-ab9a-ff3b218e31cc\" } ] } Response \u00b6 HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json DELETE /data/:type/:doc-id/relationships/references \u00b6 This bulk deletion of references on many files can be useful when an album or playlist is deleted. Request \u00b6 DELETE /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4504f55c-e2e4-11e6-88f2-d77aeecab549\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4587727a-e2e4-11e6-bfe9-ef1be7df7f26\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"45d591d0-e2e4-11e6-ab9a-ff3b218e31cc\" } ] } Response \u00b6 HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json Usage \u00b6 Modification of a referenced file \u00b6 Before an application updates a file, it can check if the file has some references. If it is the case, it may offer to the user two choices: update the file with the new version (the albums and playlists will use the new version) save the new version as a new file and preserve the old file (the old file may be moved to a originals directory). Moving a referenced file to the trash \u00b6 Before an application moves a file to the trash, if the file has some references, it should ask the user if they really want to trash the file. And it should also removes the references before trashing the file. Implementation \u00b6 The references are persisted in the io.cozy.files documents in CouchDB. A mango index is used to fetch all the files that are associated to a given document (for GET /data/:type/:doc-id/relationships/references ). For request to update or move to trash a file, it is easy to fetch its CouchDB document to see if it has a reference. But it is more difficult when moving a folder to trash. To do that, we need two requests to fetch the number of references in a folder. 1/ Get all descendant folders from a given folder, with a CouchDB View: map = function ( doc ) { if ( doc . type === \"folder\" ) emit ( doc . path ); }; query = { startkey : parent_folder_path + \"/\" , endkey : parent_folder_path + \"/\\uFFFF\" }; 2/ Get the total number of \u201creferenced\u201d file for this folders list, with a map/reduce CouchDB view: map = function ( doc ) { if ( doc . referenced != null ) emit ( doc . parentID ) } reduce = count query = { keys : [ list from above ]}", "title": " /files - References of documents in VFS"}, {"location": "cozy-stack/references-docs-in-vfs/#references-of-documents-in-the-virtual-file-system", "text": "", "title": "References of documents in the Virtual File System"}, {"location": "cozy-stack/references-docs-in-vfs/#what-we-want", "text": "Cozy applications can use data from the Data System and files from the Virtual File System. Of course, sometimes a link between data and files can be useful. For example, the application can have an album with photos. The album will be a document in CouchDB (with a title and other fields), but il will also list the files to use as photos. A direct way to do that is storing the files IDs in the album document. It\u2019s simple and will work pretty well if the files are manipulated only from this application. But, files are often accessed from other apps, like cozy-desktop and cozy-drive. To improve the User eXperience, it should be nice to alert the user when a file in an album is modified or deleted. When a file is modified, we can offer the user the choice between keeping the original version in the album, or using the new modified file. When a file is moved to the trash, we can alert the user and let him/her restore the file. Cozy-desktop, cozy-drive, and the other apps can\u2019t scan all the documents with many different doctypes to find all the references to a file to detect such cases. The goal of this document is to offer a way to do that, and it is called References . The references of a file are listed in its JSON-API representation in the references field, within the relationships object of data .", "title": "What we want?"}, {"location": "cozy-stack/references-docs-in-vfs/#example", "text": "{ \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"9152d568-7e7c-11e6-a377-37cbfb190b4b\" , \"meta\" : { \"rev\" : \"1-0e6d5b72\" }, \"attributes\" : { \"type\" : \"file\" , \"name\" : \"hello.txt\" , \"md5sum\" : \"ODZmYjI2OWQxOTBkMmM4NQo=\" , \"created_at\" : \"2016-09-19T12:38:04Z\" , \"updated_at\" : \"2016-09-19T12:38:04Z\" , \"tags\" : [], \"size\" : 12 , \"executable\" : false , \"class\" : \"document\" , \"mime\" : \"text/plain\" }, \"relationships\" : { \"parent\" : { \"links\" : { \"related\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" }, \"data\" : { \"type\" : \"io.cozy.files\" , \"id\" : \"fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81\" } }, \"referenced_by\" : { \"links\" : { \"self\" : \"/files/fce1a6c0-dfc5-11e5-8d1a-1f854d4aaf81/relationships/references\" }, \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] } }, \"links\" : { \"self\" : \"/files/9152d568-7e7c-11e6-a377-37cbfb190b4b\" } } }", "title": "Example"}, {"location": "cozy-stack/references-docs-in-vfs/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/references-docs-in-vfs/#post-filesfile-idrelationshipsreferenced_by", "text": "Add on a file one or more references to documents", "title": "POST /files/:file-id/relationships/referenced_by"}, {"location": "cozy-stack/references-docs-in-vfs/#request", "text": "POST /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/relationships/referenced_by HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0\" } ] }", "title": "Request"}, {"location": "cozy-stack/references-docs-in-vfs/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"2-de8d0ba2\" , \"count\" : 2 }, \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" }, { \"type\" : \"io.cozy.playlists\" , \"id\" : \"f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0\" } ] }", "title": "Response"}, {"location": "cozy-stack/references-docs-in-vfs/#delete-filesfile-idrelationshipsreferenced_by", "text": "Remove one or more references to documents on a file", "title": "DELETE /files/:file-id/relationships/referenced_by"}, {"location": "cozy-stack/references-docs-in-vfs/#request_1", "text": "DELETE /files/9152d568-7e7c-11e6-a377-37cbfb190b4b/relationships/referenced_by HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"f2625cc0-e2d6-11e6-a0d5-cfbbfb141af0\" } ] }", "title": "Request"}, {"location": "cozy-stack/references-docs-in-vfs/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"rev\" : \"3-7ab812c0\" , \"count\" : 1 }, \"data\" : [ { \"type\" : \"io.cozy.playlists\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" } ] }", "title": "Response"}, {"location": "cozy-stack/references-docs-in-vfs/#get-datatypedoc-idrelationshipsreferences", "text": "Returns all the files id associated to an album or playlist. Contents is paginated following jsonapi conventions . The default limit is 100 entries. The maximal number of entries per page is 1000. It\u2019s also possible to sort the files by their datetime (for photos) with the sort query parameter: ?sort=datetime .", "title": "GET /data/:type/:doc-id/relationships/references"}, {"location": "cozy-stack/references-docs-in-vfs/#request_2", "text": "GET /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/references-docs-in-vfs/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4504f55c-e2e4-11e6-88f2-d77aeecab549\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4587727a-e2e4-11e6-bfe9-ef1be7df7f26\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"45d591d0-e2e4-11e6-ab9a-ff3b218e31cc\" } ] }", "title": "Response"}, {"location": "cozy-stack/references-docs-in-vfs/#post-datatypedoc-idrelationshipsreferences", "text": "When creating an album or a playlist, it\u2019s tedious to add the references to it for each file individually. This route allows to make it in bulk.", "title": "POST /data/:type/:doc-id/relationships/references"}, {"location": "cozy-stack/references-docs-in-vfs/#request_3", "text": "POST /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4504f55c-e2e4-11e6-88f2-d77aeecab549\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4587727a-e2e4-11e6-bfe9-ef1be7df7f26\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"45d591d0-e2e4-11e6-ab9a-ff3b218e31cc\" } ] }", "title": "Request"}, {"location": "cozy-stack/references-docs-in-vfs/#response_3", "text": "HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json", "title": "Response"}, {"location": "cozy-stack/references-docs-in-vfs/#delete-datatypedoc-idrelationshipsreferences", "text": "This bulk deletion of references on many files can be useful when an album or playlist is deleted.", "title": "DELETE /data/:type/:doc-id/relationships/references"}, {"location": "cozy-stack/references-docs-in-vfs/#request_4", "text": "DELETE /data/io.cozy.playlists/e9308dc2-e2e3-11e6-b685-fb88662613d4/relationships/references HTTP / 1.1 Content-Type : application/vnd.api+json Accept : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.files\" , \"id\" : \"417c4e58-e2e4-11e6-b7dc-2b68ed7b77f4\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4504f55c-e2e4-11e6-88f2-d77aeecab549\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"4587727a-e2e4-11e6-bfe9-ef1be7df7f26\" }, { \"type\" : \"io.cozy.files\" , \"id\" : \"45d591d0-e2e4-11e6-ab9a-ff3b218e31cc\" } ] }", "title": "Request"}, {"location": "cozy-stack/references-docs-in-vfs/#response_4", "text": "HTTP / 1.1 204 No Content Content-Type : application/vnd.api+json", "title": "Response"}, {"location": "cozy-stack/references-docs-in-vfs/#usage", "text": "", "title": "Usage"}, {"location": "cozy-stack/references-docs-in-vfs/#modification-of-a-referenced-file", "text": "Before an application updates a file, it can check if the file has some references. If it is the case, it may offer to the user two choices: update the file with the new version (the albums and playlists will use the new version) save the new version as a new file and preserve the old file (the old file may be moved to a originals directory).", "title": "Modification of a referenced file"}, {"location": "cozy-stack/references-docs-in-vfs/#moving-a-referenced-file-to-the-trash", "text": "Before an application moves a file to the trash, if the file has some references, it should ask the user if they really want to trash the file. And it should also removes the references before trashing the file.", "title": "Moving a referenced file to the trash"}, {"location": "cozy-stack/references-docs-in-vfs/#implementation", "text": "The references are persisted in the io.cozy.files documents in CouchDB. A mango index is used to fetch all the files that are associated to a given document (for GET /data/:type/:doc-id/relationships/references ). For request to update or move to trash a file, it is easy to fetch its CouchDB document to see if it has a reference. But it is more difficult when moving a folder to trash. To do that, we need two requests to fetch the number of references in a folder. 1/ Get all descendant folders from a given folder, with a CouchDB View: map = function ( doc ) { if ( doc . type === \"folder\" ) emit ( doc . path ); }; query = { startkey : parent_folder_path + \"/\" , endkey : parent_folder_path + \"/\\uFFFF\" }; 2/ Get the total number of \u201creferenced\u201d file for this folders list, with a map/reduce CouchDB view: map = function ( doc ) { if ( doc . referenced != null ) emit ( doc . parentID ) } reduce = count query = { keys : [ list from above ]}", "title": "Implementation"}, {"location": "cozy-stack/registry-publish/", "text": "Table of contents Apps registry publication \u00b6 Automate publication \u00b6 The following tutorial explains how to connect your continuous integration based on Travis to automatically publish new versions on the apps registry. In this tutorial, we assume: you have a token allowing you to publish applications for your editor : AbCdEf you are working on a repository plugged on travis and named on github cozy/cozy-example You first need to add the token to your travis configuration file .travis.yml . To do so, you need the travis utility to encrypt its value. $ travis encrypt REGISTRY_TOKEN = AbCdEf --add -r cozy/cozy-example Please add the following to your .travis.yml file: secure: \"jUAjkXNXfGIXyx2MKnnJ5HwCzhrQ29SaWBTmRpU6Rwi2XRieCnb2+MKZtjVcmEjfvJO38VjPozW2F4MYIxRXf9cD+ZRAEroZRcRSNHpoi/FJ6Ra767H7AbFDGpSSUSx7UDeZbSRNazCXJ55F/JaCq6F3XGeurrJbJ/tvMoIEvjg4qcOJpBgSxXEeyEnx5L3zbDoIqDo8hx9UtZoisiTC3TGq1CGFPe35VXnv/g23Uwg2Wux1drXXnMVghoVM8SDuoE9gf4LfppVHbYmowm25tylsvNKESbYiwJIkvPciPl2rABplJLJ4nuVpeWKHx1g+bChzlR5rhgXVJidua//yFD28xWS1+j+FhCGcYuPttYTntBVTiif0DVKS3gC1FFbf2ktgJVT7nYN2z0arhdPeK7Wtv8R+0SqlXUfBA/nam1pAS1xg2MTekVKxw+FmW0r6Ct4/Dta4d4XWsYiPMBrUOaCAqo+TkxBrVvM/LcM91ua33GKzMRLmKgbDY2k7lQpt3xA0Se02p4yiWcpN+3JzwVNRkuAQfw79ItJzhBP7ZTaQMwDByD/sN4ybhICWxTOLRh6kgfw+Xxv86aADvMVwfPcLljfk5Ot3kfLyaIyqrkIF9ePGSblt7RGzHiOECFr8qUtoGQAfekM+NmKzFSkeJU8t0EvHMen1NOsZhTemx9Q=\" Like said, you need to add this block of ciphered data in the .travis.yml . This will allow you to use the REGISTRY_TOKEN variable in your deployment script. Then you can adapt this script as your after_deploy or after_success script. It contains environment variables that you can adapt as your need: COZY_APP_VERSION : the version string of the deployed version COZY_APP_PARAMETERS : an optional JSON object (string, object or array) that will parameterize the application on its execution. COZY_BUILD_URL : the URL of the deployed tarball for your application COZY_BUILD_BRANCH : the name of the build branch from which the script creates dev releases #!/bin/bash set -e # Environnment variables: # COZY_APP_VERSION: the version string of the deployed version # COZY_BUILD_URL: the URL of the deployed tarball for your application # COZY_BUILD_BRANCH: the name of the build branch from which the script # creates dev releases [ -z \" ${ COZY_BUILD_BRANCH } \" ] && COZY_BUILD_BRANCH = \"master\" [ -z \" ${ COZY_APP_PARAMETERS } \" ] && COZY_APP_PARAMETERS = \"null\" if [ \" ${ TRAVIS_PULL_REQUEST } \" ! = \"false\" ] ; then echo \"No deployment: in pull-request\" exit 0 fi if [ \" ${ TRAVIS_BRANCH } \" ! = \" ${ COZY_BUILD_BRANCH } \" ] && [ -z \" ${ TRAVIS_TAG } \" ] ; then printf 'No deployment: not in %s branch nor tag (TRAVIS_BRANCH=%s TRAVIS_TAG=%s)\\n' \" ${ COZY_BUILD_BRANCH } \" \" ${ TRAVIS_BRANCH } \" \" ${ TRAVIS_TAG } \" exit 0 fi if ! jq <<< \" ${ COZY_APP_PARAMETERS } \" > /dev/null ; then printf \"Could not parse COZY_APP_PARAMETERS=%s as JSON\\n\" \" ${ COZY_APP_PARAMETERS } \" exit 1 fi if [ -z \" ${ COZY_APP_VERSION } \" ] ; then if [ -n \" ${ TRAVIS_TAG } \" ] ; then COZY_APP_VERSION = \" ${ TRAVIS_TAG } \" else manfile = $( find \" ${ TRAVIS_BUILD_DIR } \" \\( -name \"manifest.webapp\" -o -name \"manifest.konnector\" \\) | head -n1 ) COZY_APP_VERSION = \" $( jq -r '.version' < \" ${ manfile } \" ) -dev. ${ TRAVIS_COMMIT } \" fi fi if [ -z \" ${ COZY_BUILD_URL } \" ] ; then url = \"https://github.com/ ${ TRAVIS_REPO_SLUG } /archive\" if [ -n \" ${ TRAVIS_TAG } \" ] ; then COZY_BUILD_URL = \" ${ url } / ${ TRAVIS_TAG } .tar.gz\" else COZY_BUILD_URL = \" ${ url } / ${ TRAVIS_COMMIT } .tar.gz\" fi fi shasum = $( curl -sSL --fail \" ${ COZY_BUILD_URL } \" | shasum -a 256 | cut -d \" \" -f1 ) printf 'Publishing version \"%s\" from \"%s\" (%s)\\n' \" ${ COZY_APP_VERSION } \" \" ${ COZY_BUILD_URL } \\n\" \" ${ shasum } \" curl -sS --fail -X POST \\ -H \"Content-Type: application/json\" \\ -H \"Authorization: Token ${ REGISTRY_TOKEN } \" \\ -d \"{\\\"version\\\": \\\" ${ COZY_APP_VERSION } \\\", \\\"url\\\": \\\" ${ COZY_BUILD_URL } \\\", \\\"sha256\\\": \\\" ${ shasum } \\\", \\\"parameters\\\": ${ COZY_APP_PARAMETERS } }\" \\ \"https://registry.cozy.io/registry/versions\" Access to our official apps registry \u00b6 In order to access to our official repository, you need a token for a specific editor. To do so, concact us directly at the address contact@cozycloud.cc with a mail using the following title prefix: [registry] and precising the name of the editor of your application. We will provide you with the correct token.", "title": "Registry publish"}, {"location": "cozy-stack/registry-publish/#apps-registry-publication", "text": "", "title": "Apps registry publication"}, {"location": "cozy-stack/registry-publish/#automate-publication", "text": "The following tutorial explains how to connect your continuous integration based on Travis to automatically publish new versions on the apps registry. In this tutorial, we assume: you have a token allowing you to publish applications for your editor : AbCdEf you are working on a repository plugged on travis and named on github cozy/cozy-example You first need to add the token to your travis configuration file .travis.yml . To do so, you need the travis utility to encrypt its value. $ travis encrypt REGISTRY_TOKEN = AbCdEf --add -r cozy/cozy-example Please add the following to your .travis.yml file: secure: \"jUAjkXNXfGIXyx2MKnnJ5HwCzhrQ29SaWBTmRpU6Rwi2XRieCnb2+MKZtjVcmEjfvJO38VjPozW2F4MYIxRXf9cD+ZRAEroZRcRSNHpoi/FJ6Ra767H7AbFDGpSSUSx7UDeZbSRNazCXJ55F/JaCq6F3XGeurrJbJ/tvMoIEvjg4qcOJpBgSxXEeyEnx5L3zbDoIqDo8hx9UtZoisiTC3TGq1CGFPe35VXnv/g23Uwg2Wux1drXXnMVghoVM8SDuoE9gf4LfppVHbYmowm25tylsvNKESbYiwJIkvPciPl2rABplJLJ4nuVpeWKHx1g+bChzlR5rhgXVJidua//yFD28xWS1+j+FhCGcYuPttYTntBVTiif0DVKS3gC1FFbf2ktgJVT7nYN2z0arhdPeK7Wtv8R+0SqlXUfBA/nam1pAS1xg2MTekVKxw+FmW0r6Ct4/Dta4d4XWsYiPMBrUOaCAqo+TkxBrVvM/LcM91ua33GKzMRLmKgbDY2k7lQpt3xA0Se02p4yiWcpN+3JzwVNRkuAQfw79ItJzhBP7ZTaQMwDByD/sN4ybhICWxTOLRh6kgfw+Xxv86aADvMVwfPcLljfk5Ot3kfLyaIyqrkIF9ePGSblt7RGzHiOECFr8qUtoGQAfekM+NmKzFSkeJU8t0EvHMen1NOsZhTemx9Q=\" Like said, you need to add this block of ciphered data in the .travis.yml . This will allow you to use the REGISTRY_TOKEN variable in your deployment script. Then you can adapt this script as your after_deploy or after_success script. It contains environment variables that you can adapt as your need: COZY_APP_VERSION : the version string of the deployed version COZY_APP_PARAMETERS : an optional JSON object (string, object or array) that will parameterize the application on its execution. COZY_BUILD_URL : the URL of the deployed tarball for your application COZY_BUILD_BRANCH : the name of the build branch from which the script creates dev releases #!/bin/bash set -e # Environnment variables: # COZY_APP_VERSION: the version string of the deployed version # COZY_BUILD_URL: the URL of the deployed tarball for your application # COZY_BUILD_BRANCH: the name of the build branch from which the script # creates dev releases [ -z \" ${ COZY_BUILD_BRANCH } \" ] && COZY_BUILD_BRANCH = \"master\" [ -z \" ${ COZY_APP_PARAMETERS } \" ] && COZY_APP_PARAMETERS = \"null\" if [ \" ${ TRAVIS_PULL_REQUEST } \" ! = \"false\" ] ; then echo \"No deployment: in pull-request\" exit 0 fi if [ \" ${ TRAVIS_BRANCH } \" ! = \" ${ COZY_BUILD_BRANCH } \" ] && [ -z \" ${ TRAVIS_TAG } \" ] ; then printf 'No deployment: not in %s branch nor tag (TRAVIS_BRANCH=%s TRAVIS_TAG=%s)\\n' \" ${ COZY_BUILD_BRANCH } \" \" ${ TRAVIS_BRANCH } \" \" ${ TRAVIS_TAG } \" exit 0 fi if ! jq <<< \" ${ COZY_APP_PARAMETERS } \" > /dev/null ; then printf \"Could not parse COZY_APP_PARAMETERS=%s as JSON\\n\" \" ${ COZY_APP_PARAMETERS } \" exit 1 fi if [ -z \" ${ COZY_APP_VERSION } \" ] ; then if [ -n \" ${ TRAVIS_TAG } \" ] ; then COZY_APP_VERSION = \" ${ TRAVIS_TAG } \" else manfile = $( find \" ${ TRAVIS_BUILD_DIR } \" \\( -name \"manifest.webapp\" -o -name \"manifest.konnector\" \\) | head -n1 ) COZY_APP_VERSION = \" $( jq -r '.version' < \" ${ manfile } \" ) -dev. ${ TRAVIS_COMMIT } \" fi fi if [ -z \" ${ COZY_BUILD_URL } \" ] ; then url = \"https://github.com/ ${ TRAVIS_REPO_SLUG } /archive\" if [ -n \" ${ TRAVIS_TAG } \" ] ; then COZY_BUILD_URL = \" ${ url } / ${ TRAVIS_TAG } .tar.gz\" else COZY_BUILD_URL = \" ${ url } / ${ TRAVIS_COMMIT } .tar.gz\" fi fi shasum = $( curl -sSL --fail \" ${ COZY_BUILD_URL } \" | shasum -a 256 | cut -d \" \" -f1 ) printf 'Publishing version \"%s\" from \"%s\" (%s)\\n' \" ${ COZY_APP_VERSION } \" \" ${ COZY_BUILD_URL } \\n\" \" ${ shasum } \" curl -sS --fail -X POST \\ -H \"Content-Type: application/json\" \\ -H \"Authorization: Token ${ REGISTRY_TOKEN } \" \\ -d \"{\\\"version\\\": \\\" ${ COZY_APP_VERSION } \\\", \\\"url\\\": \\\" ${ COZY_BUILD_URL } \\\", \\\"sha256\\\": \\\" ${ shasum } \\\", \\\"parameters\\\": ${ COZY_APP_PARAMETERS } }\" \\ \"https://registry.cozy.io/registry/versions\"", "title": "Automate publication"}, {"location": "cozy-stack/registry-publish/#access-to-our-official-apps-registry", "text": "In order to access to our official repository, you need a token for a specific editor. To do so, concact us directly at the address contact@cozycloud.cc with a mail using the following title prefix: [registry] and precising the name of the editor of your application. We will provide you with the correct token.", "title": "Access to our official apps registry"}, {"location": "cozy-stack/registry/", "text": "Table of contents Apps registry \u00b6 The apps registry is a place where developers can submit their applications, both web apps and konnectors. The applications metadata are stored and versioned. It can be used by a cozy to list applications to be installed, and for auto-updating the applications. We define the applications registry as an API. This should allow us to defer the real implementation of the registry storage and allow different store implementations. The stack itself implement the querying part of the registry API , proxying the request to the registries attached to the instance . Publishing on our official registries \u00b6 In order for you to publish on our official registries, please follow this howto describing how to obtain a token and parameter you repository to automatically publish versions. Channels \u00b6 We differentiate three channels of release for each application: stable: for stable releases beta: for application that can be tested in advance dev: for the latest releases directly from the trunk of the repository For each of these channels, the version string has a different format which differentiate the version channel: stable: X.Y.Z where X , Y and Z are positive or null integers. beta: X.Y.Z-beta.M where X , Y , Z and M are positive or null integers dev: X.Y.Z-dev.checksum where X , Y and Z are positive or null integers and checksum is a unique identifier of the dev release (typically a shasum of the git commit) Version order \u00b6 TLDR: 1.0.0-dev._ < 1.0.0 and 1.0.0-beta._ < 1.0.0 , make sure you upgrade your app version after publishing stable. The order used to determine the latest version of a channel is the following: - `1.0.0-dev.* < 1.0.0 (dev < stable)` - `1.0.0-beta.* < 1.0.0 (beta < stable)` - `1.0.0-beta.1 < 1.0.0-beta.2` To order beta and dev releases, we apply a sort by their creation date. Objects \u00b6 Two types of objects are managed in the registry: applications and versions. Application \u00b6 An application described a specific package. It is linked to multiple versions (releases) of the application. An application object is mutable . An application object contains the following fields: slug : the application slug (unique) type : the application type (\u201cwebapp\u201d or \u201ckonnector\u201d) editor : the application editor name versions : an object containing all the channels versions latest_version : the latest available version maintenance_activated : boolean, true when the maintenance mode is activated on the application maintenance_options : present only if maintenance_activated is true, object with the following fields: flag_infra_maintenance : bool, true iff the maintenance is internal to the cozy infrastructure flag_short_maintenance : bool, true iff the maintenance is a short maintenance, waiting for a correction on our side flag_disallow_manual_exec : bool, true iff the maintenance will disallow the execution on the application, even when manually executed messages : a list of localized messages containing a short and long information messages explaining the maintenance state label : integer for a confidence grade from 0 to 5 (A to F), labelling the application from a user privacy standpoint. It is calculated from the data_usage_commitment and data_usage_commitment_by fields. data_usage_commitment : specify a technical commitment from the application editor: user_ciphered : technical commitment that the user\u2019s data is encrypted and can only be known by him. user_reserved : commitment that the data is only used for the user, to directly offer its service. none : no commitment data_usage_commitment_by : specify what entity is taking the commitment: cozy : the commitment is taken by cozy editor : the commitment is taken by the application\u2019s editor none : no commitment is taken Example: { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"editor\" : \"cozy\" , \"versions\" : { \"stable\" : [ \"3.1.1\" ], \"beta\" : [ \"3.1.1-beta.1\" ], \"dev\" : [ \"3.1.1-dev.7a8354f74b50d7beead7719252a18ed45f55d070\" ] }, \"latest_version\" : { /* */ } } Version \u00b6 A version object describe a specific release of an application. A version object is immutable . An application version object contains the following fields: slug : the application slug type : the application type (webapp, konnector, \u2026) manifest : the entire manifest defined in the package created_at : date of the release creation url : URL of the tarball containing the application at specified version size : the size of the application package (uncompressed) in bytes as string sha256 : the sha256 checksum of the application content tar_prefix : optional tar prefix directory specified to properly extract the application content The version string should follow the channels rule. Example: { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.2\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"url\" : \"http://.../3.1.2\" , \"size\" : \"1000\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"manifest\" : { /* ... */ }, \"maintenance_activated\" : true , \"maintenance_options\" : { \"flag_infra_maintenance\" : true , \"flag_short_maintenance\" : false , \"flag_disallow_manual_exec\" : true , \"messages\" : { \"en\" : { \"long_message\" : \"The app is currently in maintenance because of ....\" , \"short_message\" : \"The app is currently in maintenance\" }, \"fr\" : { \"long_message\" : \"L'application est en cours de maintenance \u00e0 cause de ...\" , \"short_message\" : \"L'application est en cours de maintenance\" } } } } APIs: Adding to registry \u00b6 These APIs can be used to add elements to the registry. POST /registry \u00b6 This route register or modify an application to the registry. The content of the request should be a json object of an application. Status codes \u00b6 201 Created, when the application has been successfully added 409 Conflict, when an application with the same slug already exists 400 Bad request, if the given application data is malformed (bad slug, missing editor, \u2026) Request \u00b6 POST /registry HTTP / 1.1 Authorization : Token AbCdE { \"slug\" : \"drive\" , \"editor\" : \"cozy\" , \"name\" : { \"en\" : \"Drive\" , \"fr\" : \"Drive\" }, \"description\" : { \"en\" : \"The drive application\" }, \"repository\" : \"https://github.com/cozy/cozy-drive\" } POST /registry/:app \u00b6 This route adds a version of an already registered application to the registry to the specified channel (stable, beta or dev). The content of the manifest file extracted from the application data is used to fill the fields of the version. Before adding the application version to the registry, the registry should check the following: the manifest file contained in the tarball should be checked and have its fields checked against the application properties the application content should check the sha256 checksum Fields of the object sent to this request: url : the url where the application tarball is stored sha256 : the sha256 checksum of the tarball version : the version value (should match the one in the manifest) parameters? : an optional json value (any) that will override the parameters field of the manifest icon? : an optional path to override the icon field of the manifest screenshots? : and optional array of path to override the screenshots field of the manifest Status codes \u00b6 201 Created, when the version has been successfully added to the registry 409 Conflict, when the version already exists 404 Not Found, when the application does not exist 412 Precondition Failed, when the sent application data is invalid (could not fetch data URL, bad checksum, bad manifest in the tarball\u2026) 400 Bad request, when the request is invalid (bad checksum encoding, bad URL\u2026) Request \u00b6 Request to add a stable release: POST /registry/drive HTTP / 1.1 Authorization : Token AbCdE { \"version\" : \"3.1.2\" , \"url\" : \"https://github.com/cozy/cozy-drive/archive/v3.1.2.tar.gz\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" } Request to add a development release: POST /registry/drive HTTP / 1.1 Authorization : Token AbCdE { \"version\" : \"3.1.2-dev.7a1618dff78ba445650f266bbe334cbc9176f03a\" , \"url\" : \"https://github.com/cozy/cozy-photos-v3/archive/7a1618dff78ba445650f266bbe334cbc9176f03a.zip\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" } Request to add a version with optional parameters: POST /registry/drive HTTP / 1.1 Authorization : Token AbCdE { \"version\" : \"3.1.2\" , \"url\" : \"https://github.com/cozy/cozy-photos-v3/archive/7a1618dff78ba445650f266bbe334cbc9176f03a.zip\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"parameters\" : { \"foo\" : \"bar\" , \"baz\" : 123 } } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/json Location : http://.../3.1.2 { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.2-dev.7a1618dff78ba445650f266bbe334cbc9176f03a\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"url\" : \"http://.../7a1618dff78ba445650f266bbe334cbc9176f03a.zip\" , \"size\" : \"1000\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"manifest\" : { /* ... */ } } APIs: Querying registry \u00b6 These routes define the querying part of a registry to access to the available applications and versions. These APIs are also implemented directly by the cozy-stack. GET /registry \u00b6 Get the list of all applications. A pagination scheme is available via the limit and cursor query parameter. The filter[???] query parameters can be used to filter by fields values. Filtering is allowed on the following fields: type editor Sorting is allowed on the following fields: slug type editor created_at Query-String \u00b6 Parameter Description cursor the cursor of the last application on the previous page limit the maximum number of applications to show filter[] a filter to apply on fields of the application sort name of the field on which to apply the sort of the list versionsChannel the channels from which we list the version numbers latestChannelVersion the channel from which we select the latest version Request \u00b6 GET /registry?filter[category]=main&limit=20&sort=slug&versionsChannel=dev&latestChannelVersion=beta HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"data\" : [ { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"editor\" : \"cozy\" , \"versions\" : { \"stable\" : [ \"3.1.1\" ], \"beta\" : [ \"3.1.1-beta.1\" ], \"dev\" : [ \"3.1.1-dev.7a8354f74b50d7beead7719252a18ed45f55d070\" ] }, \"latest_version\" : { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1-beta.1\" , \"url\" : \"http://.../3.1.1-beta.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } } }, { // ... } ], \"meta\" : { \"count\" : 2 , \"next_cursor\" : \"...\" } } GET /registry/:app \u00b6 Get an application object by slug. Request \u00b6 GET /registry/drive HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"slug\" : \"drive\" , \"editor\" : \"cozy\" , \"latest_version\" : { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } }, \"versions\" : { \"stable\" : [ \"3.1.1\" ], \"beta\" : [ \"3.1.1-beta.1\" ], \"dev\" : [ \"3.1.1-dev.7a8354f74b50d7beead7719252a18ed45f55d070\" ] } } GET /registry/:app/icon \u00b6 Get the current application icon. Request \u00b6 GET /registry/drive/icon HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : image/svg+xml GET /registry/:app/partnership_icon \u00b6 Get the current application partnership_icon. Request \u00b6 GET /registry/drive/partnership_icon HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : image/svg+xml GET /registry/:app/screenshots/:filename \u00b6 Get the screenshot with the specified filename from the field screenshots of the application. Request \u00b6 GET /registry/drive/screenshots/screen1.jpg HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : image/jpeg ... GET /registry/:app/:version \u00b6 Get an application version. Request \u00b6 GET /registry/drive/3.1.1 HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } } GET /registry/:app/:channel/latest \u00b6 Get the latest version available on the specified channel. Request \u00b6 GET /registry/drive/dev/latest HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } } GET /registry/maintenance \u00b6 Get the list of applications (and konnectors) with maintenance mode activated. Request \u00b6 GET /registry/maintenance HTTP / 1.1 Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json [ { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ }, \"maintenance_activated\" : true , \"maintenance_options\" : { \"flag_infra_maintenance\" : true , \"flag_short_maintenance\" : false , \"flag_disallow_manual_exec\" : true } } ] Attaching a cozy-stack to a registry or a list of registries \u00b6 In the configuration file of a stack, a registries namespace is added. This namespace can contain a list of URL for the different registries attached to the stack. The stack itself implements the querying API of a registry. When querying this API, to ask for an application, the stack uses this hierarchy of registries to proxy or redirect the user. The hierarchy can also be contextualised to specify different registries to different contexts. The default context is applied lastly. Examples: \u00b6 registries : - https://myregistry.home/ - https://main.registry.cozy.io/ # In this example, a \"context1\" instance will have the equivalent of the # following list of registries: # # - https://context1.registry.cozy.io/ # - https://myregistry.home/ # - https://registry.cozy.io/ # registries : context1 : - https://context1.registry.cozy.io/ context2 : - https://context2.registry.cozy.io/ default : - https://myregistry.home/ - https://registry.cozy.io/ Authentication \u00b6 The authentication is based on a token that allow you to publish applications and versions with for one specific editor name. This token is base64 encoded. In order to receive this token, please take a look at the page on publication on the registry .", "title": " /apps - Apps registry"}, {"location": "cozy-stack/registry/#apps-registry", "text": "The apps registry is a place where developers can submit their applications, both web apps and konnectors. The applications metadata are stored and versioned. It can be used by a cozy to list applications to be installed, and for auto-updating the applications. We define the applications registry as an API. This should allow us to defer the real implementation of the registry storage and allow different store implementations. The stack itself implement the querying part of the registry API , proxying the request to the registries attached to the instance .", "title": "Apps registry"}, {"location": "cozy-stack/registry/#publishing-on-our-official-registries", "text": "In order for you to publish on our official registries, please follow this howto describing how to obtain a token and parameter you repository to automatically publish versions.", "title": "Publishing on our official registries"}, {"location": "cozy-stack/registry/#channels", "text": "We differentiate three channels of release for each application: stable: for stable releases beta: for application that can be tested in advance dev: for the latest releases directly from the trunk of the repository For each of these channels, the version string has a different format which differentiate the version channel: stable: X.Y.Z where X , Y and Z are positive or null integers. beta: X.Y.Z-beta.M where X , Y , Z and M are positive or null integers dev: X.Y.Z-dev.checksum where X , Y and Z are positive or null integers and checksum is a unique identifier of the dev release (typically a shasum of the git commit)", "title": "Channels"}, {"location": "cozy-stack/registry/#version-order", "text": "TLDR: 1.0.0-dev._ < 1.0.0 and 1.0.0-beta._ < 1.0.0 , make sure you upgrade your app version after publishing stable. The order used to determine the latest version of a channel is the following: - `1.0.0-dev.* < 1.0.0 (dev < stable)` - `1.0.0-beta.* < 1.0.0 (beta < stable)` - `1.0.0-beta.1 < 1.0.0-beta.2` To order beta and dev releases, we apply a sort by their creation date.", "title": "Version order"}, {"location": "cozy-stack/registry/#objects", "text": "Two types of objects are managed in the registry: applications and versions.", "title": "Objects"}, {"location": "cozy-stack/registry/#application", "text": "An application described a specific package. It is linked to multiple versions (releases) of the application. An application object is mutable . An application object contains the following fields: slug : the application slug (unique) type : the application type (\u201cwebapp\u201d or \u201ckonnector\u201d) editor : the application editor name versions : an object containing all the channels versions latest_version : the latest available version maintenance_activated : boolean, true when the maintenance mode is activated on the application maintenance_options : present only if maintenance_activated is true, object with the following fields: flag_infra_maintenance : bool, true iff the maintenance is internal to the cozy infrastructure flag_short_maintenance : bool, true iff the maintenance is a short maintenance, waiting for a correction on our side flag_disallow_manual_exec : bool, true iff the maintenance will disallow the execution on the application, even when manually executed messages : a list of localized messages containing a short and long information messages explaining the maintenance state label : integer for a confidence grade from 0 to 5 (A to F), labelling the application from a user privacy standpoint. It is calculated from the data_usage_commitment and data_usage_commitment_by fields. data_usage_commitment : specify a technical commitment from the application editor: user_ciphered : technical commitment that the user\u2019s data is encrypted and can only be known by him. user_reserved : commitment that the data is only used for the user, to directly offer its service. none : no commitment data_usage_commitment_by : specify what entity is taking the commitment: cozy : the commitment is taken by cozy editor : the commitment is taken by the application\u2019s editor none : no commitment is taken Example: { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"editor\" : \"cozy\" , \"versions\" : { \"stable\" : [ \"3.1.1\" ], \"beta\" : [ \"3.1.1-beta.1\" ], \"dev\" : [ \"3.1.1-dev.7a8354f74b50d7beead7719252a18ed45f55d070\" ] }, \"latest_version\" : { /* */ } }", "title": "Application"}, {"location": "cozy-stack/registry/#version", "text": "A version object describe a specific release of an application. A version object is immutable . An application version object contains the following fields: slug : the application slug type : the application type (webapp, konnector, \u2026) manifest : the entire manifest defined in the package created_at : date of the release creation url : URL of the tarball containing the application at specified version size : the size of the application package (uncompressed) in bytes as string sha256 : the sha256 checksum of the application content tar_prefix : optional tar prefix directory specified to properly extract the application content The version string should follow the channels rule. Example: { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.2\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"url\" : \"http://.../3.1.2\" , \"size\" : \"1000\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"manifest\" : { /* ... */ }, \"maintenance_activated\" : true , \"maintenance_options\" : { \"flag_infra_maintenance\" : true , \"flag_short_maintenance\" : false , \"flag_disallow_manual_exec\" : true , \"messages\" : { \"en\" : { \"long_message\" : \"The app is currently in maintenance because of ....\" , \"short_message\" : \"The app is currently in maintenance\" }, \"fr\" : { \"long_message\" : \"L'application est en cours de maintenance \u00e0 cause de ...\" , \"short_message\" : \"L'application est en cours de maintenance\" } } } }", "title": "Version"}, {"location": "cozy-stack/registry/#apis-adding-to-registry", "text": "These APIs can be used to add elements to the registry.", "title": "APIs: Adding to registry"}, {"location": "cozy-stack/registry/#post-registry", "text": "This route register or modify an application to the registry. The content of the request should be a json object of an application.", "title": "POST /registry"}, {"location": "cozy-stack/registry/#status-codes", "text": "201 Created, when the application has been successfully added 409 Conflict, when an application with the same slug already exists 400 Bad request, if the given application data is malformed (bad slug, missing editor, \u2026)", "title": "Status codes"}, {"location": "cozy-stack/registry/#request", "text": "POST /registry HTTP / 1.1 Authorization : Token AbCdE { \"slug\" : \"drive\" , \"editor\" : \"cozy\" , \"name\" : { \"en\" : \"Drive\" , \"fr\" : \"Drive\" }, \"description\" : { \"en\" : \"The drive application\" }, \"repository\" : \"https://github.com/cozy/cozy-drive\" }", "title": "Request"}, {"location": "cozy-stack/registry/#post-registryapp", "text": "This route adds a version of an already registered application to the registry to the specified channel (stable, beta or dev). The content of the manifest file extracted from the application data is used to fill the fields of the version. Before adding the application version to the registry, the registry should check the following: the manifest file contained in the tarball should be checked and have its fields checked against the application properties the application content should check the sha256 checksum Fields of the object sent to this request: url : the url where the application tarball is stored sha256 : the sha256 checksum of the tarball version : the version value (should match the one in the manifest) parameters? : an optional json value (any) that will override the parameters field of the manifest icon? : an optional path to override the icon field of the manifest screenshots? : and optional array of path to override the screenshots field of the manifest", "title": "POST /registry/:app"}, {"location": "cozy-stack/registry/#status-codes_1", "text": "201 Created, when the version has been successfully added to the registry 409 Conflict, when the version already exists 404 Not Found, when the application does not exist 412 Precondition Failed, when the sent application data is invalid (could not fetch data URL, bad checksum, bad manifest in the tarball\u2026) 400 Bad request, when the request is invalid (bad checksum encoding, bad URL\u2026)", "title": "Status codes"}, {"location": "cozy-stack/registry/#request_1", "text": "Request to add a stable release: POST /registry/drive HTTP / 1.1 Authorization : Token AbCdE { \"version\" : \"3.1.2\" , \"url\" : \"https://github.com/cozy/cozy-drive/archive/v3.1.2.tar.gz\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" } Request to add a development release: POST /registry/drive HTTP / 1.1 Authorization : Token AbCdE { \"version\" : \"3.1.2-dev.7a1618dff78ba445650f266bbe334cbc9176f03a\" , \"url\" : \"https://github.com/cozy/cozy-photos-v3/archive/7a1618dff78ba445650f266bbe334cbc9176f03a.zip\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" } Request to add a version with optional parameters: POST /registry/drive HTTP / 1.1 Authorization : Token AbCdE { \"version\" : \"3.1.2\" , \"url\" : \"https://github.com/cozy/cozy-photos-v3/archive/7a1618dff78ba445650f266bbe334cbc9176f03a.zip\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"parameters\" : { \"foo\" : \"bar\" , \"baz\" : 123 } }", "title": "Request"}, {"location": "cozy-stack/registry/#response", "text": "HTTP / 1.1 201 Created Content-Type : application/json Location : http://.../3.1.2 { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.2-dev.7a1618dff78ba445650f266bbe334cbc9176f03a\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"url\" : \"http://.../7a1618dff78ba445650f266bbe334cbc9176f03a.zip\" , \"size\" : \"1000\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"manifest\" : { /* ... */ } }", "title": "Response"}, {"location": "cozy-stack/registry/#apis-querying-registry", "text": "These routes define the querying part of a registry to access to the available applications and versions. These APIs are also implemented directly by the cozy-stack.", "title": "APIs: Querying registry"}, {"location": "cozy-stack/registry/#get-registry", "text": "Get the list of all applications. A pagination scheme is available via the limit and cursor query parameter. The filter[???] query parameters can be used to filter by fields values. Filtering is allowed on the following fields: type editor Sorting is allowed on the following fields: slug type editor created_at", "title": "GET /registry"}, {"location": "cozy-stack/registry/#query-string", "text": "Parameter Description cursor the cursor of the last application on the previous page limit the maximum number of applications to show filter[] a filter to apply on fields of the application sort name of the field on which to apply the sort of the list versionsChannel the channels from which we list the version numbers latestChannelVersion the channel from which we select the latest version", "title": "Query-String"}, {"location": "cozy-stack/registry/#request_2", "text": "GET /registry?filter[category]=main&limit=20&sort=slug&versionsChannel=dev&latestChannelVersion=beta HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"data\" : [ { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"editor\" : \"cozy\" , \"versions\" : { \"stable\" : [ \"3.1.1\" ], \"beta\" : [ \"3.1.1-beta.1\" ], \"dev\" : [ \"3.1.1-dev.7a8354f74b50d7beead7719252a18ed45f55d070\" ] }, \"latest_version\" : { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1-beta.1\" , \"url\" : \"http://.../3.1.1-beta.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } } }, { // ... } ], \"meta\" : { \"count\" : 2 , \"next_cursor\" : \"...\" } }", "title": "Response"}, {"location": "cozy-stack/registry/#get-registryapp", "text": "Get an application object by slug.", "title": "GET /registry/:app"}, {"location": "cozy-stack/registry/#request_3", "text": "GET /registry/drive HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"slug\" : \"drive\" , \"editor\" : \"cozy\" , \"latest_version\" : { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } }, \"versions\" : { \"stable\" : [ \"3.1.1\" ], \"beta\" : [ \"3.1.1-beta.1\" ], \"dev\" : [ \"3.1.1-dev.7a8354f74b50d7beead7719252a18ed45f55d070\" ] } }", "title": "Response"}, {"location": "cozy-stack/registry/#get-registryappicon", "text": "Get the current application icon.", "title": "GET /registry/:app/icon"}, {"location": "cozy-stack/registry/#request_4", "text": "GET /registry/drive/icon HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_3", "text": "HTTP / 1.1 200 OK Content-Type : image/svg+xml ", "title": "Response"}, {"location": "cozy-stack/registry/#get-registryapppartnership_icon", "text": "Get the current application partnership_icon.", "title": "GET /registry/:app/partnership_icon"}, {"location": "cozy-stack/registry/#request_5", "text": "GET /registry/drive/partnership_icon HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : image/svg+xml ", "title": "Response"}, {"location": "cozy-stack/registry/#get-registryappscreenshotsfilename", "text": "Get the screenshot with the specified filename from the field screenshots of the application.", "title": "GET /registry/:app/screenshots/:filename"}, {"location": "cozy-stack/registry/#request_6", "text": "GET /registry/drive/screenshots/screen1.jpg HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : image/jpeg ...", "title": "Response"}, {"location": "cozy-stack/registry/#get-registryappversion", "text": "Get an application version.", "title": "GET /registry/:app/:version"}, {"location": "cozy-stack/registry/#request_7", "text": "GET /registry/drive/3.1.1 HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_6", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } }", "title": "Response"}, {"location": "cozy-stack/registry/#get-registryappchannellatest", "text": "Get the latest version available on the specified channel.", "title": "GET /registry/:app/:channel/latest"}, {"location": "cozy-stack/registry/#request_8", "text": "GET /registry/drive/dev/latest HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_7", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ } }", "title": "Response"}, {"location": "cozy-stack/registry/#get-registrymaintenance", "text": "Get the list of applications (and konnectors) with maintenance mode activated.", "title": "GET /registry/maintenance"}, {"location": "cozy-stack/registry/#request_9", "text": "GET /registry/maintenance HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/registry/#response_8", "text": "HTTP / 1.1 200 OK Content-Type : application/json [ { \"slug\" : \"drive\" , \"type\" : \"webapp\" , \"version\" : \"3.1.1\" , \"url\" : \"http://.../3.1.1\" , \"sha256\" : \"466aa0815926fdbf33fda523af2b9bf34520906ffbb9bf512ddf20df2992a46f\" , \"size\" : \"1000\" , \"created_at\" : \"2017-07-05T07:54:40.982Z\" , \"manifest\" : { /* ... */ }, \"maintenance_activated\" : true , \"maintenance_options\" : { \"flag_infra_maintenance\" : true , \"flag_short_maintenance\" : false , \"flag_disallow_manual_exec\" : true } } ]", "title": "Response"}, {"location": "cozy-stack/registry/#attaching-a-cozy-stack-to-a-registry-or-a-list-of-registries", "text": "In the configuration file of a stack, a registries namespace is added. This namespace can contain a list of URL for the different registries attached to the stack. The stack itself implements the querying API of a registry. When querying this API, to ask for an application, the stack uses this hierarchy of registries to proxy or redirect the user. The hierarchy can also be contextualised to specify different registries to different contexts. The default context is applied lastly.", "title": "Attaching a cozy-stack to a registry or a list of registries"}, {"location": "cozy-stack/registry/#examples", "text": "registries : - https://myregistry.home/ - https://main.registry.cozy.io/ # In this example, a \"context1\" instance will have the equivalent of the # following list of registries: # # - https://context1.registry.cozy.io/ # - https://myregistry.home/ # - https://registry.cozy.io/ # registries : context1 : - https://context1.registry.cozy.io/ context2 : - https://context2.registry.cozy.io/ default : - https://myregistry.home/ - https://registry.cozy.io/", "title": "Examples:"}, {"location": "cozy-stack/registry/#authentication", "text": "The authentication is based on a token that allow you to publish applications and versions with for one specific editor name. This token is base64 encoded. In order to receive this token, please take a look at the page on publication on the registry .", "title": "Authentication"}, {"location": "cozy-stack/release/", "text": "Table of contents Building a release \u00b6 To build a release of cozy-stack, a build.sh script can automate the work. The release option of this script will generate a binary with a name containing the version of the file, along with a SHA-256 sum of the binary. You can use a local.env at the root of the repository to add your default values for environment variables. See ./scripts/build.sh --help for more informations. COZY_ENV = development GOOS = linux GOARCH = amd64 ./scripts/build.sh release The version string is deterministic and reflects entirely the state of the working-directory from which the release is built from. It is generated using the following format: [-][-dirty][-dev] Where: : closest annotated tag of the current working directory. If no tag is present, is uses the string \u201cv0\u201d. This is not allowed in a production release. : number of commits after the closest tag if the current working directory does not point exactly to a tag dirty : added if the working if the working-directory is not clean (contains un-commited modifications). This is not allowed in production release. dev : added for a development mode release Sprint release \u00b6 At the end of a sprint, we release different versions of the stack: \u201cNaked\u201d stack, for GNU/Linux amd64/arm, FreeBSD amd64 Docker image for cozy-app-dev Production docker image for cozy-stack Debian/Ubuntu self-hosting packages The release process is as follow: Create a tag x.y.z and push it The release is created by GitHub Actions with .github/workflows/release.yml GitHub Actions build all artifacts and publish them as release artifacts and docker images on Docker Hub: The binaries are generated by GitHub Actions by the script ./scripts/build.sh cozy-stack production docker image is built by the script ./scripts/docker/production/release.sh cozy-app-dev docker image is built by the script ./scripts/docker/cozy-app-dev/release.sh The deb packages are generated with the scripts in ./scripts/packaging", "title": "Build a release"}, {"location": "cozy-stack/release/#building-a-release", "text": "To build a release of cozy-stack, a build.sh script can automate the work. The release option of this script will generate a binary with a name containing the version of the file, along with a SHA-256 sum of the binary. You can use a local.env at the root of the repository to add your default values for environment variables. See ./scripts/build.sh --help for more informations. COZY_ENV = development GOOS = linux GOARCH = amd64 ./scripts/build.sh release The version string is deterministic and reflects entirely the state of the working-directory from which the release is built from. It is generated using the following format: [-][-dirty][-dev] Where: : closest annotated tag of the current working directory. If no tag is present, is uses the string \u201cv0\u201d. This is not allowed in a production release. : number of commits after the closest tag if the current working directory does not point exactly to a tag dirty : added if the working if the working-directory is not clean (contains un-commited modifications). This is not allowed in production release. dev : added for a development mode release", "title": "Building a release"}, {"location": "cozy-stack/release/#sprint-release", "text": "At the end of a sprint, we release different versions of the stack: \u201cNaked\u201d stack, for GNU/Linux amd64/arm, FreeBSD amd64 Docker image for cozy-app-dev Production docker image for cozy-stack Debian/Ubuntu self-hosting packages The release process is as follow: Create a tag x.y.z and push it The release is created by GitHub Actions with .github/workflows/release.yml GitHub Actions build all artifacts and publish them as release artifacts and docker images on Docker Hub: The binaries are generated by GitHub Actions by the script ./scripts/build.sh cozy-stack production docker image is built by the script ./scripts/docker/production/release.sh cozy-app-dev docker image is built by the script ./scripts/docker/cozy-app-dev/release.sh The deb packages are generated with the scripts in ./scripts/packaging", "title": "Sprint release"}, {"location": "cozy-stack/remote/", "text": "Table of contents Proxy for remote data/API \u00b6 The client side applications in Cozy are constrained and cannot speak with external websites to avoid leaking personal data. Technically, it is made with the Content Security Policy. These rules are very strict and it would be a pity to not allow a client side app to load public informations from a source like Wikipedia. Our proposal is to make client side apps able to query external websites of their choices, but these requests will be made via the cozy-stack (as a proxy) and will be logged to check later that no personal data was leaked unintentionally. We can see the data loaded from the external website as a document with a doctype: it\u2019s just not a doctype local to our cozy, but a remote one. A client side app can request data from external websites by doing these three steps: Declaring a remote doctype and its requests Declaring permissions on these doctypes in the manifest Calling the /remote API of cozy-stack Declaring a remote doctype \u00b6 Doctypes are formalized in this repository: github.com/cozy/cozy-doctypes . Each doctype has its own directory inside the repository. For a remote doctype, it will include a file called request that will describe how the cozy-stack will request the external website. Let\u2019s take an example: $ tree cozy-doctypes cozy-doctypes \u251c\u2500\u2500 [ ... ] \u251c\u2500\u2500 org.wikidata.entity \u2502 \u2514\u2500\u2500 request \u2514\u2500\u2500 org.wikidata.search \u2514\u2500\u2500 request $ cat cozy-doctypes/org.wikidata.entity/request GET https://www.wikidata.org/wiki/Special:EntityData/ {{ entity }} .json Accept: application/json $ cat cozy-doctypes/org.wikidata.search/request GET https://www.wikidata.org/w/api.php?action = wbsearchentities & search ={{ q }} & language = en & format = json Here, we have two remote doctypes. Each one has a request defined for it. The format for the request file is: the verb and the URL on the first line then some lines that describe the HTTP headers then a blank line and the body if the request is a POST The URL can only use the default port. But, for development and testing in local, this rule can be disabled with the --remote-allow-custom-port flag of the cozy-stack serve command. For the path, the query-string, the headers, and the body, it\u2019s possible to have some dynamic part by using {{ , a variable name, and }} . Some templating helpers are available to escape specific variables using {{ function name - space - variable name }} . These helpers are only available for the body part of the template. Available helpers: json : for json parts ( { \"key\": \"{{json val}}\" } ) html : for html parts (

    {{html val}}

    ) query : for query parameter of a url ( http://foobar.com?q={{query q}} ) path : for path component of a url ( http://foobar.com/{{path p}} ) Values injected in the URL are automatically URI-escaped based on the part they are included in: namely as a query parameter or as a path component. Note : by default, the User-Agent is set to a default value (\u201ccozy-stack\u201d and a version number). It can be overriden in the request description. Example: GET https://foobar.com/ {{ path }} ?q= {{ query }} Content-Type: {{ contentType }} { \"key\": \" {{ json value }} \", \"url\": \"http://anotherurl.com/ {{ path anotherPath }} ?q= {{ query anotherQuery }} \", } Declaring permissions \u00b6 Nothing special here. The client side app must declare that it will use these doctypes in its manifest, like for other doctypes: { \"...\" : \"...\" , \"permissions\" : { \"search\" : { \"description\" : \"Required for searching on wikidata\" , \"type\" : \"org.wikidata.search\" }, \"entity\" : { \"description\" : \"Required for getting more informations about an entity on wikidata\" , \"type\" : \"org.wikidata.entity\" } } } Calling the remote API \u00b6 GET/POST /remote/:doctype \u00b6 The client side app must use the same verb as the defined request ( GET in our two previous examples). It can use the query-string for GET, and a JSON body for POST, to give values for the variables. Example: GET /remote/org.wikidata.search?q=Douglas+Adams HTTP / 1.1 Host : alice.cozy.localhost It is possible to send some extra informations, to make it easier to understand the request. If no variable in the request matches it, it won\u2019t be send to the remote website. Example: POST /remote/org.example HTTP / 1.1 Host : alice.cozy.localhost Content-Type : application/json { \"query\" : \"Qbhtynf Nqnzf\" , \"comment\" : \"query is rot13 for Douglas Adams\" } Note : currently, only the response with a content-type that is an image, JSON or XML are accepted. Other content-types are blocked the time to evaluate if they are useful and their security implication (javascript is probably not something we want to allow). GET /remote/_all_doctypes \u00b6 This endpoint lists all the known remote doctypes. A permission on io.cozy.doctypes for GET is needed to query this endoint. Example: GET /remote/_all_doctypes HTTP / 1.1 HTTP / 1.1 200 OK Content-Type : application/json [ \"cc.cozycloud.dacc\" , \"cc.cozycloud.errors\" , \"org.wikidata.entity\" , \"org.wikidata.search\" ] GET /remote/assets/:asset-name \u00b6 The client application can fetch a list of predefined assets via this route. The resources available are defined in the configuration file. Example: GET /remote/assets/bank HTTP / 1.1 Host : alice.cozy.localhost Logs \u00b6 The requests are logged as the io.cozy.remote.requests doctype, with the doctype asked, the parameter (even those that have not been used, like comment in the previous example), and the application that has made the request. Secrets \u00b6 It is possible to make the stack inject a secret in a request. For example, if we want to make the stack inject a token for the request, then: 1- We need to store the secret in CouchDB, in the secrets/io-cozy-remote-secrets database. The document must have the remote doctype as an id, and the secret in another field, like this: { \"_id\" : \"cc.cozycloud.foobar\" , \"token\" : \"1c7f3ba03bd801391a91543d7eb8149c\" } 2- Use this secret in the remote doctype declaration: GET https://foobar.com/baz/ HTTP / 1.1 Authorization : Bearer {{secret_token}} You can see that we store token in the io-cozy-remote-secret but we use secret_token in the remote doctype declaration, this is a convention to follow. Like that, we quickly know what come from secrets and what come from the caller. If you use secret and you get a 400 Bad Request error a variable is used in the template, but no value was given check if you follow this convention. For developers \u00b6 If you are a developer and you want to use a new remote doctype, it can be difficult to first make it available in the github.com/cozy/cozy-doctypes repository and only then test it. So, the cozy-stack serve command has a --doctypes option to gives a local directory with the doctypes. You can fork the repository, clone it, work on a new doctype inside, test it locally, and when OK, make a pull request for it.", "title": "/remote - Proxy for remote data/API"}, {"location": "cozy-stack/remote/#proxy-for-remote-dataapi", "text": "The client side applications in Cozy are constrained and cannot speak with external websites to avoid leaking personal data. Technically, it is made with the Content Security Policy. These rules are very strict and it would be a pity to not allow a client side app to load public informations from a source like Wikipedia. Our proposal is to make client side apps able to query external websites of their choices, but these requests will be made via the cozy-stack (as a proxy) and will be logged to check later that no personal data was leaked unintentionally. We can see the data loaded from the external website as a document with a doctype: it\u2019s just not a doctype local to our cozy, but a remote one. A client side app can request data from external websites by doing these three steps: Declaring a remote doctype and its requests Declaring permissions on these doctypes in the manifest Calling the /remote API of cozy-stack", "title": "Proxy for remote data/API"}, {"location": "cozy-stack/remote/#declaring-a-remote-doctype", "text": "Doctypes are formalized in this repository: github.com/cozy/cozy-doctypes . Each doctype has its own directory inside the repository. For a remote doctype, it will include a file called request that will describe how the cozy-stack will request the external website. Let\u2019s take an example: $ tree cozy-doctypes cozy-doctypes \u251c\u2500\u2500 [ ... ] \u251c\u2500\u2500 org.wikidata.entity \u2502 \u2514\u2500\u2500 request \u2514\u2500\u2500 org.wikidata.search \u2514\u2500\u2500 request $ cat cozy-doctypes/org.wikidata.entity/request GET https://www.wikidata.org/wiki/Special:EntityData/ {{ entity }} .json Accept: application/json $ cat cozy-doctypes/org.wikidata.search/request GET https://www.wikidata.org/w/api.php?action = wbsearchentities & search ={{ q }} & language = en & format = json Here, we have two remote doctypes. Each one has a request defined for it. The format for the request file is: the verb and the URL on the first line then some lines that describe the HTTP headers then a blank line and the body if the request is a POST The URL can only use the default port. But, for development and testing in local, this rule can be disabled with the --remote-allow-custom-port flag of the cozy-stack serve command. For the path, the query-string, the headers, and the body, it\u2019s possible to have some dynamic part by using {{ , a variable name, and }} . Some templating helpers are available to escape specific variables using {{ function name - space - variable name }} . These helpers are only available for the body part of the template. Available helpers: json : for json parts ( { \"key\": \"{{json val}}\" } ) html : for html parts (

    {{html val}}

    ) query : for query parameter of a url ( http://foobar.com?q={{query q}} ) path : for path component of a url ( http://foobar.com/{{path p}} ) Values injected in the URL are automatically URI-escaped based on the part they are included in: namely as a query parameter or as a path component. Note : by default, the User-Agent is set to a default value (\u201ccozy-stack\u201d and a version number). It can be overriden in the request description. Example: GET https://foobar.com/ {{ path }} ?q= {{ query }} Content-Type: {{ contentType }} { \"key\": \" {{ json value }} \", \"url\": \"http://anotherurl.com/ {{ path anotherPath }} ?q= {{ query anotherQuery }} \", }", "title": "Declaring a remote doctype"}, {"location": "cozy-stack/remote/#declaring-permissions", "text": "Nothing special here. The client side app must declare that it will use these doctypes in its manifest, like for other doctypes: { \"...\" : \"...\" , \"permissions\" : { \"search\" : { \"description\" : \"Required for searching on wikidata\" , \"type\" : \"org.wikidata.search\" }, \"entity\" : { \"description\" : \"Required for getting more informations about an entity on wikidata\" , \"type\" : \"org.wikidata.entity\" } } }", "title": "Declaring permissions"}, {"location": "cozy-stack/remote/#calling-the-remote-api", "text": "", "title": "Calling the remote API"}, {"location": "cozy-stack/remote/#getpost-remotedoctype", "text": "The client side app must use the same verb as the defined request ( GET in our two previous examples). It can use the query-string for GET, and a JSON body for POST, to give values for the variables. Example: GET /remote/org.wikidata.search?q=Douglas+Adams HTTP / 1.1 Host : alice.cozy.localhost It is possible to send some extra informations, to make it easier to understand the request. If no variable in the request matches it, it won\u2019t be send to the remote website. Example: POST /remote/org.example HTTP / 1.1 Host : alice.cozy.localhost Content-Type : application/json { \"query\" : \"Qbhtynf Nqnzf\" , \"comment\" : \"query is rot13 for Douglas Adams\" } Note : currently, only the response with a content-type that is an image, JSON or XML are accepted. Other content-types are blocked the time to evaluate if they are useful and their security implication (javascript is probably not something we want to allow).", "title": "GET/POST /remote/:doctype"}, {"location": "cozy-stack/remote/#get-remote_all_doctypes", "text": "This endpoint lists all the known remote doctypes. A permission on io.cozy.doctypes for GET is needed to query this endoint. Example: GET /remote/_all_doctypes HTTP / 1.1 HTTP / 1.1 200 OK Content-Type : application/json [ \"cc.cozycloud.dacc\" , \"cc.cozycloud.errors\" , \"org.wikidata.entity\" , \"org.wikidata.search\" ]", "title": "GET /remote/_all_doctypes"}, {"location": "cozy-stack/remote/#get-remoteassetsasset-name", "text": "The client application can fetch a list of predefined assets via this route. The resources available are defined in the configuration file. Example: GET /remote/assets/bank HTTP / 1.1 Host : alice.cozy.localhost", "title": "GET /remote/assets/:asset-name"}, {"location": "cozy-stack/remote/#logs", "text": "The requests are logged as the io.cozy.remote.requests doctype, with the doctype asked, the parameter (even those that have not been used, like comment in the previous example), and the application that has made the request.", "title": "Logs"}, {"location": "cozy-stack/remote/#secrets", "text": "It is possible to make the stack inject a secret in a request. For example, if we want to make the stack inject a token for the request, then: 1- We need to store the secret in CouchDB, in the secrets/io-cozy-remote-secrets database. The document must have the remote doctype as an id, and the secret in another field, like this: { \"_id\" : \"cc.cozycloud.foobar\" , \"token\" : \"1c7f3ba03bd801391a91543d7eb8149c\" } 2- Use this secret in the remote doctype declaration: GET https://foobar.com/baz/ HTTP / 1.1 Authorization : Bearer {{secret_token}} You can see that we store token in the io-cozy-remote-secret but we use secret_token in the remote doctype declaration, this is a convention to follow. Like that, we quickly know what come from secrets and what come from the caller. If you use secret and you get a 400 Bad Request error a variable is used in the template, but no value was given check if you follow this convention.", "title": "Secrets"}, {"location": "cozy-stack/remote/#for-developers", "text": "If you are a developer and you want to use a new remote doctype, it can be difficult to first make it available in the github.com/cozy/cozy-doctypes repository and only then test it. So, the cozy-stack serve command has a --doctypes option to gives a local directory with the doctypes. You can fork the repository, clone it, work on a new doctype inside, test it locally, and when OK, make a pull request for it.", "title": "For developers"}, {"location": "cozy-stack/security/", "text": "Table of contents Security \u00b6 Checklist \u00b6 Strong security is centered on the user Defense in depth is still worthy Have a strict control of all the accesses to the Cozy Protect client-side apps by default Don\u2019t trust inputs, always sanitize them Encryption is not the solution to all the problems, but it helps Use standards (https, OAuth2) Have a reliable way to deploy, with sane defaults No one is perfect, code must be reviewed Be open to external contributors Rationale \u00b6 Strong security is centered on the user \u00b6 For systems well designed, the user is often the weakest link in the security chain. Engineers have a tendancy to overestimate the technical risks and underestimate the human interactions. It doesn\u2019t mean that we can avoid technical measures. But it\u2019s very important to take in account the possible behaviour of the user. That means that adding a text to explain him/her the consequences of a click on a button can increase the security a lot much than forcing him/her to do things. For example, forcing users to change regulary their password makes them choose passwords that are a lot weaker (but easier for them to remember). Defense in depth is still worthy \u00b6 Also known as layered defense, defense in depth is a security principle where single points of complete compromise are eliminated or mitigated by the incorporation of a series or multiple layers of security safeguards and risk-mitigation countermeasures. Have diverse defensive strategies, so that if one layer of defense turns out to be inadequate, another layer of defense will hopefully prevent a full breach. Have a strict control of all the accesses to the Cozy \u00b6 All the requests to the cozy stack have a strict access control. It is based on several informations: Is the user connected? What is the application that makes this request? What are the permissions for this application? Which grant is used, in particular for applications with public pages? What are the permissions for this grant? More informations here . Protect client-side apps by default \u00b6 This is mostly applying the state of the art: Using HTTPS, with HSTS. Using secure, httpOnly, sameSite cookies to avoid cookies theft or misuse. Using a Content Security Policy (CSP). Using X-frame-options http header to protect against click-jacking. But we will use a CSP very restrictive by default (no access to other web domains for example). Don\u2019t trust inputs, always sanitize them \u00b6 If we take the OWASP top 10 vulnerabilities , we can see that a lot of them are related to trusting inputs. It starts with the first one, injections, but it goes also to XSS and unvalidated forwards (in OAuth2 notably). Always sanitizing inputs is a good pratice that improves security, but has also some nice effects like helping developers discover hidden bugs. Encryption is not the solution to all the problems, but it helps \u00b6 Some data are encrypted before being saved in CouchDB (passwords for the accounts for example). Encrypting everything has some downsides: It\u2019s not possible to index encryped documents or do computations on the encrypted fields in reasonable time ( homomorphic encryption is still an open subject). Having more encrypted data can globally weaken the encryption, if it\u2019s not handled properly. If the encryption key is lost or a bug happen, the data is lost with no way to recover them. So, we are more confortable to encrypt only some fields. And later, when we will have more experience and feedbacks from the user, extend the encryption to more fields. We are also working with SMIS , a research lab, to find a way to securely store and backup the encryption keys. Use standards (https, OAuth2) \u00b6 Standards like https and OAuth2 had a lot of eyes to look at them, and are therefore more robust. Reinventing the wheel can be valuable for some things. But for security, the cost is very high and only some very particular constraints can justify such an high cost. Cozy don\u2019t have these constraints, so we will stick to the standards. Have a reliable way to deploy, with sane defaults \u00b6 It\u2019s important that deploying a cozy is well documented, doesn\u2019t require too many steps and can be automatized. An error on the installation can have dramatic effects, like the database being leaked on internet. So, we need to really take care of the devops experience. In particular, having sane defaults for the configuration will help to minimize the number of things he/she has to do, and such the number of places where he/she can make faux pas. No one is perfect, code must be reviewed \u00b6 No code is directly pushed to the master branch in git. It has to be reviewed by at least one member of the core team (ideally the whole team), and this person can\u2019t be the author of the change. Even the best developers can make mistakes, and we don\u2019t pretend to be them. Our force is to work as team. Be open to external contributors \u00b6 Our code is Open Source, external contributors can review it. If they (you?) find a weakness, please contact us by sending an email to security AT cozycloud.cc. This is a mailing-list specially setup for responsible disclosure of security weaknesses in Cozy. We will respond in less than 72 hours. When a security flaw is found, the process is the following: Make a pull-request to fix (on our private git instance) and test it. Deploy the fix on cozycloud.cc Publish a new version, announce it on the forum as a security update and on the mailing-lists. 15 days later, add the details on the forum.", "title": "Security"}, {"location": "cozy-stack/security/#security", "text": "", "title": "Security"}, {"location": "cozy-stack/security/#checklist", "text": "Strong security is centered on the user Defense in depth is still worthy Have a strict control of all the accesses to the Cozy Protect client-side apps by default Don\u2019t trust inputs, always sanitize them Encryption is not the solution to all the problems, but it helps Use standards (https, OAuth2) Have a reliable way to deploy, with sane defaults No one is perfect, code must be reviewed Be open to external contributors", "title": "Checklist"}, {"location": "cozy-stack/security/#rationale", "text": "", "title": "Rationale"}, {"location": "cozy-stack/security/#strong-security-is-centered-on-the-user", "text": "For systems well designed, the user is often the weakest link in the security chain. Engineers have a tendancy to overestimate the technical risks and underestimate the human interactions. It doesn\u2019t mean that we can avoid technical measures. But it\u2019s very important to take in account the possible behaviour of the user. That means that adding a text to explain him/her the consequences of a click on a button can increase the security a lot much than forcing him/her to do things. For example, forcing users to change regulary their password makes them choose passwords that are a lot weaker (but easier for them to remember).", "title": "Strong security is centered on the user"}, {"location": "cozy-stack/security/#defense-in-depth-is-still-worthy", "text": "Also known as layered defense, defense in depth is a security principle where single points of complete compromise are eliminated or mitigated by the incorporation of a series or multiple layers of security safeguards and risk-mitigation countermeasures. Have diverse defensive strategies, so that if one layer of defense turns out to be inadequate, another layer of defense will hopefully prevent a full breach.", "title": "Defense in depth is still worthy"}, {"location": "cozy-stack/security/#have-a-strict-control-of-all-the-accesses-to-the-cozy", "text": "All the requests to the cozy stack have a strict access control. It is based on several informations: Is the user connected? What is the application that makes this request? What are the permissions for this application? Which grant is used, in particular for applications with public pages? What are the permissions for this grant? More informations here .", "title": "Have a strict control of all the accesses to the Cozy"}, {"location": "cozy-stack/security/#protect-client-side-apps-by-default", "text": "This is mostly applying the state of the art: Using HTTPS, with HSTS. Using secure, httpOnly, sameSite cookies to avoid cookies theft or misuse. Using a Content Security Policy (CSP). Using X-frame-options http header to protect against click-jacking. But we will use a CSP very restrictive by default (no access to other web domains for example).", "title": "Protect client-side apps by default"}, {"location": "cozy-stack/security/#dont-trust-inputs-always-sanitize-them", "text": "If we take the OWASP top 10 vulnerabilities , we can see that a lot of them are related to trusting inputs. It starts with the first one, injections, but it goes also to XSS and unvalidated forwards (in OAuth2 notably). Always sanitizing inputs is a good pratice that improves security, but has also some nice effects like helping developers discover hidden bugs.", "title": "Don't trust inputs, always sanitize them"}, {"location": "cozy-stack/security/#encryption-is-not-the-solution-to-all-the-problems-but-it-helps", "text": "Some data are encrypted before being saved in CouchDB (passwords for the accounts for example). Encrypting everything has some downsides: It\u2019s not possible to index encryped documents or do computations on the encrypted fields in reasonable time ( homomorphic encryption is still an open subject). Having more encrypted data can globally weaken the encryption, if it\u2019s not handled properly. If the encryption key is lost or a bug happen, the data is lost with no way to recover them. So, we are more confortable to encrypt only some fields. And later, when we will have more experience and feedbacks from the user, extend the encryption to more fields. We are also working with SMIS , a research lab, to find a way to securely store and backup the encryption keys.", "title": "Encryption is not the solution to all the problems, but it helps"}, {"location": "cozy-stack/security/#use-standards-https-oauth2", "text": "Standards like https and OAuth2 had a lot of eyes to look at them, and are therefore more robust. Reinventing the wheel can be valuable for some things. But for security, the cost is very high and only some very particular constraints can justify such an high cost. Cozy don\u2019t have these constraints, so we will stick to the standards.", "title": "Use standards (https, OAuth2)"}, {"location": "cozy-stack/security/#have-a-reliable-way-to-deploy-with-sane-defaults", "text": "It\u2019s important that deploying a cozy is well documented, doesn\u2019t require too many steps and can be automatized. An error on the installation can have dramatic effects, like the database being leaked on internet. So, we need to really take care of the devops experience. In particular, having sane defaults for the configuration will help to minimize the number of things he/she has to do, and such the number of places where he/she can make faux pas.", "title": "Have a reliable way to deploy, with sane defaults"}, {"location": "cozy-stack/security/#no-one-is-perfect-code-must-be-reviewed", "text": "No code is directly pushed to the master branch in git. It has to be reviewed by at least one member of the core team (ideally the whole team), and this person can\u2019t be the author of the change. Even the best developers can make mistakes, and we don\u2019t pretend to be them. Our force is to work as team.", "title": "No one is perfect, code must be reviewed"}, {"location": "cozy-stack/security/#be-open-to-external-contributors", "text": "Our code is Open Source, external contributors can review it. If they (you?) find a weakness, please contact us by sending an email to security AT cozycloud.cc. This is a mailing-list specially setup for responsible disclosure of security weaknesses in Cozy. We will respond in less than 72 hours. When a security flaw is found, the process is the following: Make a pull-request to fix (on our private git instance) and test it. Deploy the fix on cozycloud.cc Publish a new version, announce it on the forum as a security update and on the mailing-lists. 15 days later, add the details on the forum.", "title": "Be open to external contributors"}, {"location": "cozy-stack/settings/", "text": "Table of contents Settings \u00b6 Disk usage \u00b6 GET /settings/disk-usage \u00b6 Says how many bytes are available and used to store files. When not limited the quota field is omitted. Also says how many bytes are used by last version of files and how many bytes are taken by older versions. If the include=trash parameter is added to the query string, it will also compute the size of the files in the trash. Request \u00b6 GET /settings/disk-usage?include=trash HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Authorization : Bearer ... Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.disk-usage\" , \"attributes\" : { \"quota\" : \"123456789\" , \"used\" : \"12345678\" , \"files\" : \"10305070\" , \"trash\" : \"456789\" , \"versions\" : \"2040608\" } } } OAuth clients usage \u00b6 GET /settings/clients-usage \u00b6 This endpoint returns the number of user-connected OAuth clients, the limit set on the Cozy and if this limit has been reached or even exceeded. If there is no limit, the limit attribute won\u2019t be present in the response. Request \u00b6 GET /settings/clients-usage HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Authorization : Bearer ... Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.clients-usage\" , \"attributes\" : { \"limit\" : 3 , \"count\" : 3 , \"limitReached\" : true , \"limitExceeded\" : false } } } Email update \u00b6 POST /settings/email \u00b6 The email adress update process starts with this call. The password is required in order to make a strong authentication. This endpoint will send a confirmation email to the new address with a link. Once clicked, this link will redirect the user to the second endpoint. Request \u00b6 POST /settings/email HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ... { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"email\" : \"alice@example.com\" } Response \u00b6 HTTP / 1.1 204 No Content POST /settings/email/resend \u00b6 Once the email process is started, it\u2019s possible to resend an email in order to ensure the link delivery. Request \u00b6 POST /settings/email HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ... Response \u00b6 HTTP / 1.1 204 No Content GET /settings/email/confirm \u00b6 This is the second part of the email update process. The user have received a confirmation email with a link on its new email adress. When he click on the link he ends up on this endpoint. The url contains a token used to authenticate the user and the action. Request \u00b6 GET /settings/email/confirm?token=XXXXXXX HTTP / 1.1 Host : alice.example.com Response \u00b6 In case of success the user will be redirected to its setting page. In case of error an HTML error page will appears. HTTP / 1.1 307 Temporary Redirect Location : http://alice-settings.cozy.localhost:8080 DELETE /settings/email \u00b6 This endpoints allows to cancel the ongoing email adress update process. Request \u00b6 DELETE /settings/email HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ... Response \u00b6 HTTP / 1.1 204 No Content Passphrase \u00b6 The master password, known by the cozy owner, is used for two things: to allow the user to login and to do encryption on the client side. To do so, two keys are derivated from the master password, one for each usage. In this section, we are talking about the derivated key used for login on a cozy instance. GET /settings/passphrase \u00b6 The server will send the parameters for hashing the master password on the client side to derive a key used for login. Note: a permission on GET io.cozy.settings is required for this endpoint. Request \u00b6 GET /settings/passphrase HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Authorization : Bearer ... Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.passphrase\" , \"attributes\" : { \"salt\" : \"me@alice.example.com\" , \"kdf\" : 0 , \"iterations\" : 10000 } } } Note: only kdf: 0 is currently supported. It means PBKDF2 with SHA256. POST /settings/passphrase (form) \u00b6 The user can send its new hashed passphrase (base64 encoded) to finish the onboarding. The registration token can only be used once. The key is the encryption key for bitwarden, encrypted with the master key. The public_key and private_key are the key pair for sharing data with a bitwarden organization, and they are optional. Request \u00b6 POST /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/x-www-form-urlencoded register_token=37cddf40d7724988860fa0e03efd30fe& passphrase=4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791& key=0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=& public_key=MIIBIjANBgkqhkiG9w...AQAB& private_key=2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=& iterations=100000 Response \u00b6 HTTP / 1.1 303 See Other Set-Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure Location : https://alice-home.example.com/ POST /settings/passphrase (json) \u00b6 The onboarding application can send a request to this endpoint to register the passphrase of the user. Request \u00b6 POST /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"register_token\" : \"37cddf40d7724988860fa0e03efd30fe\" , \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"hint\" : \"a hint to help me remember my passphrase\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"public_key\" : \"MIIBIjANBgkqhkiG9w...AQAB\" , \"private_key\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"iterations\" : 100000 } Response \u00b6 HTTP / 1.1 204 No Content Set-Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure POST /settings/passphrase/flagship \u00b6 This endpoint is similar to POST /settings/passphrase , but it allows the flagship app to also obtain OAuth access and register tokens without having to make the OAuth dance (which can be awkward for the user). Request \u00b6 POST /settings/passphrase/flagship HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"register_token\" : \"37cddf40d7724988860fa0e03efd30fe\" , \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"hint\" : \"a hint to help me remember my passphrase\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"public_key\" : \"MIIBIjANBgkqhkiG9w...AQAB\" , \"private_key\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"iterations\" : 100000 , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg\" , \"scope\" : \"*\" } Note: if the OAuth client has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app. PUT /settings/passphrase (without two-factor authentication) \u00b6 The user can change its passphrase with this route. For users with two-factor authentication activated, a second step on the same route is necessary to actually update the passphrase. See below. A \"force\": true parameter can be added in the JSON to force a passphrase on a Cozy where authentication by password is disabled and the vault is empty. It allows to use Cozy Pass when the authentication on the Cozy is delegated via OIDC. When forcing a password reset, you need to regenerate the public and private keys encryption key of the vault and pass them via key , publicKey and privateKey . See those password-helpers for example on how to regenerate those keys. Request \u00b6 PUT /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"current_passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"new_passphrase\" : \"2e7e1e04300356adc8fabf5d304b58c564399746cc7a21464fd6593edd925720\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"iterations\" : 10000 } Response \u00b6 HTTP / 1.1 204 No Content Set-Cookie : cozysessid=AAAAShoo3uo1Maic4VibuGohlik2eKUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure PUT /settings/passphrase (with two-factor authentication) \u00b6 The user can change its passphrase with this route, with two-factor authentication to verify the user with more than its passphrase. Request (first step) \u00b6 PUT /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"current_passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" } Response (first step) \u00b6 HTTP / 1.1 200 OK Set-Cookie : cozysessid=AAAAShoo3uo1Maic4VibuGohlik2eKUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure { \"two_factor_token\" : \"YxOSUjxd0SNmuwEEDRHXfw==\" } At this point, the current passphrase has been exchanged against a token, and a passcode should have been sent to the user to authenticate on the second step. The token/passcode pair can be used on the second step to update the passphrase. Request (second step) \u00b6 PUT /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"new_passphrase\" : \"2e7e1e04300356adc8fabf5d304b58c564399746cc7a21464fd6593edd925720\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"iterations\" : 10000 , \"two_factor_token\" : \"YxOSUjxd0SNmuwEEDRHXfw==\" , \"two_factor_passcode\" : \"4947178\" } Response (second step) \u00b6 HTTP / 1.1 204 No Content Set-Cookie : cozysessid=AAAAShoo3uo1Maic4VibuGohlik2eKUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure Response \u00b6 HTTP / 1.1 204 No Content POST /settings/passphrase/check \u00b6 This route can be used to check the passphrase of the user before making important changes like asking for the Cozy deletion. Request \u00b6 POST /settings/passphrase/check HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authentication : Bearer xxx { \"passphrase\" : \"2e7e1e04300356adc8fabf5d304b58c564399746cc7a21464fd6593edd925720\" } Response \u00b6 It will be 204 No Content if the passphrase is correct, or a 403 Forbidden if the passphrase is incorrect. GET /settings/hint \u00b6 This route can be used to know if a hint has been chosen (but the hint won\u2019t be revealed). If there is a hint, the response will be a 204 No Content . And, if not, it will be a 404 No Content . Request \u00b6 GET /settings/hint HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 204 No Content PUT /settings/hint \u00b6 The user can change the hint for its passphrase. Request \u00b6 PUT /settings/hint HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"hint\" : \"My passphrase is very complicated\" } Response \u00b6 HTTP / 1.1 204 No Content POST /settings/vault \u00b6 This route can be used to ensure the vault is initialized. If it is not the case, it will migrate the accounts from the konnectors accounts to the vault and will set the extension_installed flag. Request \u00b6 POST /settings/vault HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 204 No Content Instance \u00b6 GET /settings/capabilities \u00b6 List the activated capabilities for this instance. An unadvertised capability should be considered false and, for backward compatibility, if you can\u2019t get a valid response from this endpoint (in particular in case of a 404 Not found error), all capabilities should be considered false . The current capabilities are: file_versioning is true when the VFS can create old versions of a file flat_subdomains is true when the stack is configured to use flat subdomains (not nested) can_auth_with_password is true when authentication with a Cozy password is possible can_auth_with_magic_links is true when authentication with a link sent by email is possible can_auth_with_oidc is true when delegated authentication with OIDC is possible for this instance. Note: both can_auth_with_password and can_auth_with_oidc can be true for an instance where the choice is given to the user of how they want to authenticate. Request \u00b6 GET /settings/capabilities HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.capabilities\" , \"attributes\" : { \"file_versioning\" : true , \"flat_subdomains\" : false , \"can_auth_with_password\" : true , \"can_auth_with_magic_links\" : false , \"can_auth_with_oidc\" : false }, \"links\" : { \"self\" : \"/settings/capabilities\" } } } Permissions \u00b6 No permissions are required to access this route, but the request needs to be authenticated (webapp token, OAuth token, etc.). GET /settings/external-ties \u00b6 List ties between the instance and external services such as a subscription vendor (e.g. mobile app stores). The current possible ties are: has_blocking_subscription is true when the instance is linked to a premium subscription paid via a third-party vendor that does not let us cancel the subscription ourselves and requires it to be cancelled by the customer themselves. Request \u00b6 GET /settings/external-ties HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.external-ties\" , \"attributes\" : { \"has_blocking_subscription\" : false }, \"links\" : { \"self\" : \"/settings/external-ties\" } } } Permissions \u00b6 No permissions are required to access this route, but the request needs to be made from an authenticated Web session or Webapp. GET /settings/instance \u00b6 If the user is logged in, display all instance settings. Request \u00b6 GET /settings/instance HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxx Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.instance\" , \"meta\" : { \"rev\" : \"3-56521545485448482\" }, \"attributes\" : { \"locale\" : \"fr\" , \"password_defined\" : true , \"auto_update\" : true , \"email\" : \"alice@example.com\" , \"public_name\" : \"Alice Martin\" , \"auth_mode\" : \"basic\" , \"default_redirection\" : \"drive/#/folder\" , \"context\" : \"dev\" , \"sponsorships\" : [ \"springfield\" ] } } } Note about password_defined \u00b6 There are a few fields that are persisted on the instance its-self, not on its settings document. When they are updated, it won\u2019t be reflected in the realtime when listening on the io.cozy.settings.instance document. For password_defined , it is possible to be notified when the password is defined by watching a synthetic document with the doctype io.cozy.settings , and the id io.cozy.settings.passphrase . POST /settings/instance/deletion \u00b6 The settings application can use this route if the user wants to delete their Cozy instance. Request \u00b6 POST /settings/instance/deletion HTTP / 1.1 Host : alice.example.com Response \u00b6 HTTP / 1.1 204 No Content DELETE /settings/instance/moved_from \u00b6 When there is an attribute moved_from in the instance settings, it means that the Cozy has been moved from the given address. The Home application uses this information to display a modal to alert the user. And when they dismiss the modal, a request is made to this route to remove this information (and avoid showing this modal again the next time they will open the Home again). Request \u00b6 DELETE /settings/instance/moved_from HTTP / 1.1 Host : target.cozy.localhost Cookie : sessionid=xxxxx Response \u00b6 HTTP / 1.1 204 No Content Permissions \u00b6 No permission is required to use this route, only that the user is logged-in. PUT /settings/instance \u00b6 If the user is logged in, allow to set the instance fields Request \u00b6 POST /settings/instance HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Content-Type : application/vnd.api+json Cookie : sessionid=xxxxx Authorization : Bearer settings-token { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.instance\" , \"meta\" : { \"rev\" : \"3-56521545485448482\" }, \"attributes\" : { \"locale\" : \"fr\" , \"email\" : \"alice@example.com\" , \"public_name\" : \"Alice Martin\" , \"timezone\" : \"Europe/Berlin\" , \"auth_mode\" : \"two_factor_mail\" , \"default_redirection\" : \"drive/#/folder\" } } } Note: the format for default_redirection is the application slug, followed by a slash, and then the route for the app (path + fragment). Response \u00b6 HTTP/1.1 200 OK Content-Type: application/json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.instance\" , \"meta\" : { \"rev\" : \"4-5a3e315e\" }, \"attributes\" : { \"locale\" : \"fr\" , \"email\" : \"alice@example.com\" , \"public_name\" : \"Alice Martin\" , \"timezone\" : \"Europe/Berlin\" , \"auth_mode\" : \"two_factor_mail\" , \"default_redirection\" : \"drive/#/folder\" } } } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.settings for the verb PUT . PUT /settings/instance/auth_mode \u00b6 With this route, the user can ask for the activation of different authentication modes, like two-factor authentication. Available authentication modes: basic : basic authentication only with passphrase two_factor_mail : authentication with passphrase and validation with a code sent via email to the user. When asking for activation of the two-factor authentication, a side-effect can be triggered to send the user its code (via email for instance), and the activation not being effective. This side-effect should provide the user with a code that can be used to finalize the activation of the two-factor authentication. Hence, this route has two behaviors: the code is not provided: the route is a side effect to ask for the activation of 2FA, and a code is sent the code is provided, and valid: the two-factor authentication is actually activated. Status codes: 204 No Content : when the mail has been confirmed and two-factor authentication is activated 422 Unprocessable Entity : when the given confirmation code is not good. Request \u00b6 PUT /settings/instance/auth_mode HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"auth_mode\" : \"two_factor_mail\" , \"two_factor_activation_code\" : \"12345678\" } PUT /settings/instance/sign_tos \u00b6 With this route, an OAuth client can sign the new TOS version. Status codes: 204 No Content : when the mail has been confirmed and two-factor authentication is activated Request \u00b6 PUT /settings/instance/sign_tos HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ... Sessions \u00b6 GET /settings/sessions \u00b6 This route allows to get all the currently active sessions. GET /settings/sessions HTTP / 1.1 Host : cozy.example.org Cookie : ... Authorization : Bearer ... HTTP / 1.1 200 OK Content-Type : application/json { \"data\" : [ { \"id\" : \"...\" , \"attributes\" : { \"last_seen\" : \"\" }, \"meta\" : { \"rev\" : \"...\" } } ] } Permissions \u00b6 This route requires the application to have permissions on the io.cozy.sessions doctype with the GET verb. OAuth 2 clients \u00b6 GET /settings/clients \u00b6 Get the list of the registered clients Request \u00b6 GET /settings/clients HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxxx Authorization : Bearer oauth2-clients-token Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"30e84c10-e6cf-11e6-9bfd-a7106972de51\" , \"attributes\" : { \"redirect_uris\" : [ \"http://localhost:4000/oauth/callback\" ], \"client_name\" : \"Cozy-Desktop on my-new-laptop\" , \"client_kind\" : \"desktop\" , \"client_uri\" : \"https://docs.cozy.io/en/mobile/desktop.html\" , \"logo_uri\" : \"https://docs.cozy.io/assets/images/cozy-logo-docs.svg\" , \"policy_uri\" : \"https://cozy.io/policy\" , \"software_id\" : \"/github.com/cozy-labs/cozy-desktop\" , \"software_version\" : \"0.16.0\" , \"client_os\" : \"Windows\" , \"last_refreshed_at\" : \"2017-09-04T08:14:47Z\" , \"synchronized_at\" : \"2017-09-05T16:23:04Z\" }, \"links\" : { \"self\" : \"/settings/clients/30e84c10-e6cf-11e6-9bfd-a7106972de51\" } } ] } Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.oauth.clients for the verb GET (only client-side apps). DELETE /settings/clients/:client-id \u00b6 Request \u00b6 DELETE /settings/clients/30e84c10-e6cf-11e6-9bfd-a7106972de51 HTTP / 1.1 Host : alice.example.com Authorization : Bearer oauth2-clients-token Response \u00b6 HTTP / 1.1 204 No Content Permissions \u00b6 To use this endpoint, an application needs a permission on the type io.cozy.oauth.clients for the verb DELETE (only client-side apps). GET /settings/clients/limit-exceeded \u00b6 Get an OAuth clients limit exceeded page if the instance has more connected OAuth clients than its limit allows or redirect the request to the redirect parameter\u2019s value. The redirect parameter is optional. By default, its value is the instance\u2019s default redirection. The page will auto-refresh every 20 seconds or when an OAuth client deletion is detected. Query-String \u00b6 Parameter Description redirect URL where to redirect when the limit is not exceeded Request \u00b6 GET /settings/clients/limit-exceeded?redirect=https%3A%2F%2Falice-home.example.com%2F HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxx POST /settings/synchronized \u00b6 Any OAuth2 client can make a request to this endpoint with its token, no permission is needed. It will update the date of last synchronization for this device. Request \u00b6 POST /settings/synchronized HTTP / 1.1 Host : alice.example.com Authorization : Bearer oauth2-access-token Response \u00b6 HTTP / 1.1 204 No Content Context \u00b6 GET /settings/onboarded \u00b6 It redirects the user to an application after the onboarding. The application is selected according to the context of the instance and the configuration of the stack. GET /settings/install_flagship_app \u00b6 At the end of an onboarding, just after the password has been chosen, if the user is in a mobile browser, the stack will show a page to push them to install the flagship app. GET /settings/context \u00b6 It gives the keys/values from the config for the context of the instance. Request \u00b6 GET /settings/context HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxx Response \u00b6 { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.context\" , \"attributes\" : { \"default_redirection\" : \"drive/#/folder\" , \"help_link\" : \"https://forum.cozy.io/\" , \"onboarded_redirection\" : \"home/#/discovery/?intro\" }, \"links\" : { \"self\" : \"/settings/context\" } } } Permissions \u00b6 To use this endpoint, an application needs a valid token, but no explicit permission is required. Feature flags \u00b6 A feature flag is a name and an associated value (boolean, number, string or a JSON) that can be interpreted by the apps. It can be used for giving access to paid features, or to enable a feature progressively on all the cozy instances of a context. The stack computes the feature flags from several sources (in order of decreasing priority): the flags set on the instance by the command cozy-stack feature flags the response of the manager for GET /api/v1/flags?sets=s1,s2&context=ctx (where s1,s2 has been set via cozy-stack feature sets ) the flags coming from the context configuration ( context..features ) the flags set on the context by the command cozy-stack feature ratio the default value ( cozy-stack feature default ). For a given flag, the stack takes the value from the source with the highest priority, and does not look at the other sources (no merge). GET /settings/flags \u00b6 This endpoint returns the computed list of feature flags for the given instance. It accepts an include parameter in the query string to see the details of how the flags were computed. Request \u00b6 GET /settings/flags HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags\" , \"attributes\" : { \"has_feature1\" : true , \"has_feature2\" : false , \"number_of_foos\" : 10 , \"bar_config\" : { \"qux\" : \"quux\" } }, \"links\" : { \"self\" : \"/settings/flags\" } } } Request \u00b6 GET /settings/flags?include=source HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags\" , \"attributes\" : { \"has_feature1\" : true , \"has_feature2\" : false , \"number_of_foos\" : 10 , \"bar_config\" : { \"qux\" : \"quux\" } }, \"links\" : { \"self\" : \"/settings/flags\" } }, \"included\" : [ { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.instance\" , \"attributes\" : { \"number_of_foos\" : 10 } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.manager\" , \"attributes\" : { \"sets\" : [ \"s1\" , \"s2\" ], \"has_feature1\" : true , \"number_of_foos\" : 5 } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.config\" , \"attributes\" : { \"number_of_foos\" : 2 } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.context\" , \"attributes\" : { \"has_feature2\" : [{ \"ratio\" : 0.1 , \"value\" : true }], \"bar_config\" : [ { \"ratio\" : 0.2 , \"value\" : { \"qux\" : \"quux\" } }, { \"ratio\" : 0.8 , \"value\" : { \"qux\" : \"baz\" } } ] } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.default\" , \"attributes\" : { \"bar_config\" : { \"qux\" : \"courge\" }, \"number_of_foos\" : 2 } } ] } Permissions \u00b6 To use this endpoint, an application needs a valid token, but no explicit permission is required.", "title": "/settings - Settings"}, {"location": "cozy-stack/settings/#settings", "text": "", "title": "Settings"}, {"location": "cozy-stack/settings/#disk-usage", "text": "", "title": "Disk usage"}, {"location": "cozy-stack/settings/#get-settingsdisk-usage", "text": "Says how many bytes are available and used to store files. When not limited the quota field is omitted. Also says how many bytes are used by last version of files and how many bytes are taken by older versions. If the include=trash parameter is added to the query string, it will also compute the size of the files in the trash.", "title": "GET /settings/disk-usage"}, {"location": "cozy-stack/settings/#request", "text": "GET /settings/disk-usage?include=trash HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/settings/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.disk-usage\" , \"attributes\" : { \"quota\" : \"123456789\" , \"used\" : \"12345678\" , \"files\" : \"10305070\" , \"trash\" : \"456789\" , \"versions\" : \"2040608\" } } }", "title": "Response"}, {"location": "cozy-stack/settings/#oauth-clients-usage", "text": "", "title": "OAuth clients usage"}, {"location": "cozy-stack/settings/#get-settingsclients-usage", "text": "This endpoint returns the number of user-connected OAuth clients, the limit set on the Cozy and if this limit has been reached or even exceeded. If there is no limit, the limit attribute won\u2019t be present in the response.", "title": "GET /settings/clients-usage"}, {"location": "cozy-stack/settings/#request_1", "text": "GET /settings/clients-usage HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/settings/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.clients-usage\" , \"attributes\" : { \"limit\" : 3 , \"count\" : 3 , \"limitReached\" : true , \"limitExceeded\" : false } } }", "title": "Response"}, {"location": "cozy-stack/settings/#email-update", "text": "", "title": "Email update"}, {"location": "cozy-stack/settings/#post-settingsemail", "text": "The email adress update process starts with this call. The password is required in order to make a strong authentication. This endpoint will send a confirmation email to the new address with a link. Once clicked, this link will redirect the user to the second endpoint.", "title": "POST /settings/email"}, {"location": "cozy-stack/settings/#request_2", "text": "POST /settings/email HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ... { \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"email\" : \"alice@example.com\" }", "title": "Request"}, {"location": "cozy-stack/settings/#response_2", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#post-settingsemailresend", "text": "Once the email process is started, it\u2019s possible to resend an email in order to ensure the link delivery.", "title": "POST /settings/email/resend"}, {"location": "cozy-stack/settings/#request_3", "text": "POST /settings/email HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/settings/#response_3", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#get-settingsemailconfirm", "text": "This is the second part of the email update process. The user have received a confirmation email with a link on its new email adress. When he click on the link he ends up on this endpoint. The url contains a token used to authenticate the user and the action.", "title": "GET /settings/email/confirm"}, {"location": "cozy-stack/settings/#request_4", "text": "GET /settings/email/confirm?token=XXXXXXX HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/settings/#response_4", "text": "In case of success the user will be redirected to its setting page. In case of error an HTML error page will appears. HTTP / 1.1 307 Temporary Redirect Location : http://alice-settings.cozy.localhost:8080", "title": "Response"}, {"location": "cozy-stack/settings/#delete-settingsemail", "text": "This endpoints allows to cancel the ongoing email adress update process.", "title": "DELETE /settings/email"}, {"location": "cozy-stack/settings/#request_5", "text": "DELETE /settings/email HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/settings/#response_5", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#passphrase", "text": "The master password, known by the cozy owner, is used for two things: to allow the user to login and to do encryption on the client side. To do so, two keys are derivated from the master password, one for each usage. In this section, we are talking about the derivated key used for login on a cozy instance.", "title": "Passphrase"}, {"location": "cozy-stack/settings/#get-settingspassphrase", "text": "The server will send the parameters for hashing the master password on the client side to derive a key used for login. Note: a permission on GET io.cozy.settings is required for this endpoint.", "title": "GET /settings/passphrase"}, {"location": "cozy-stack/settings/#request_6", "text": "GET /settings/passphrase HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/settings/#response_6", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.passphrase\" , \"attributes\" : { \"salt\" : \"me@alice.example.com\" , \"kdf\" : 0 , \"iterations\" : 10000 } } } Note: only kdf: 0 is currently supported. It means PBKDF2 with SHA256.", "title": "Response"}, {"location": "cozy-stack/settings/#post-settingspassphrase-form", "text": "The user can send its new hashed passphrase (base64 encoded) to finish the onboarding. The registration token can only be used once. The key is the encryption key for bitwarden, encrypted with the master key. The public_key and private_key are the key pair for sharing data with a bitwarden organization, and they are optional.", "title": "POST /settings/passphrase (form)"}, {"location": "cozy-stack/settings/#request_7", "text": "POST /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/x-www-form-urlencoded register_token=37cddf40d7724988860fa0e03efd30fe& passphrase=4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791& key=0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=& public_key=MIIBIjANBgkqhkiG9w...AQAB& private_key=2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=& iterations=100000", "title": "Request"}, {"location": "cozy-stack/settings/#response_7", "text": "HTTP / 1.1 303 See Other Set-Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure Location : https://alice-home.example.com/", "title": "Response"}, {"location": "cozy-stack/settings/#post-settingspassphrase-json", "text": "The onboarding application can send a request to this endpoint to register the passphrase of the user.", "title": "POST /settings/passphrase (json)"}, {"location": "cozy-stack/settings/#request_8", "text": "POST /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"register_token\" : \"37cddf40d7724988860fa0e03efd30fe\" , \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"hint\" : \"a hint to help me remember my passphrase\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"public_key\" : \"MIIBIjANBgkqhkiG9w...AQAB\" , \"private_key\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"iterations\" : 100000 }", "title": "Request"}, {"location": "cozy-stack/settings/#response_8", "text": "HTTP / 1.1 204 No Content Set-Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure", "title": "Response"}, {"location": "cozy-stack/settings/#post-settingspassphraseflagship", "text": "This endpoint is similar to POST /settings/passphrase , but it allows the flagship app to also obtain OAuth access and register tokens without having to make the OAuth dance (which can be awkward for the user).", "title": "POST /settings/passphrase/flagship"}, {"location": "cozy-stack/settings/#request_9", "text": "POST /settings/passphrase/flagship HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"register_token\" : \"37cddf40d7724988860fa0e03efd30fe\" , \"passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"hint\" : \"a hint to help me remember my passphrase\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"public_key\" : \"MIIBIjANBgkqhkiG9w...AQAB\" , \"private_key\" : \"2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=\" , \"iterations\" : 100000 , \"client_id\" : \"64ce5cb0-bd4c-11e6-880e-b3b7dfda89d3\" , \"client_secret\" : \"eyJpc3Mi[...omitted for brevity...]\" }", "title": "Request"}, {"location": "cozy-stack/settings/#response_9", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"access_token\" : \"OWY0MjNjMGEtOTNmNi0xMWVjLWIyZGItN2I5YjgwNmRjYzBiCg\" , \"token_type\" : \"bearer\" , \"refresh_token\" : \"YTUwMjcyYjgtOTNmNi0xMWVjLWE4YTQtZWJhMzlmMTAwMWJiCg\" , \"scope\" : \"*\" } Note: if the OAuth client has not been certified as the flagship app, this request will return: HTTP / 1.1 202 Accepted Content-Type : application/json { \"session_code\" : \"ZmY4ODI3NGMtOTY1Yy0xMWVjLThkMDgtMmI5M2\" } The session_code can be put in the query string while opening the OAuth authorize page. It will be used to open the session, and let the user type the 6-digits code they have received by mail to confirm that they want to use this app as the flagship app.", "title": "Response"}, {"location": "cozy-stack/settings/#put-settingspassphrase-without-two-factor-authentication", "text": "The user can change its passphrase with this route. For users with two-factor authentication activated, a second step on the same route is necessary to actually update the passphrase. See below. A \"force\": true parameter can be added in the JSON to force a passphrase on a Cozy where authentication by password is disabled and the vault is empty. It allows to use Cozy Pass when the authentication on the Cozy is delegated via OIDC. When forcing a password reset, you need to regenerate the public and private keys encryption key of the vault and pass them via key , publicKey and privateKey . See those password-helpers for example on how to regenerate those keys.", "title": "PUT /settings/passphrase (without two-factor authentication)"}, {"location": "cozy-stack/settings/#request_10", "text": "PUT /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"current_passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" , \"new_passphrase\" : \"2e7e1e04300356adc8fabf5d304b58c564399746cc7a21464fd6593edd925720\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"iterations\" : 10000 }", "title": "Request"}, {"location": "cozy-stack/settings/#response_10", "text": "HTTP / 1.1 204 No Content Set-Cookie : cozysessid=AAAAShoo3uo1Maic4VibuGohlik2eKUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure", "title": "Response"}, {"location": "cozy-stack/settings/#put-settingspassphrase-with-two-factor-authentication", "text": "The user can change its passphrase with this route, with two-factor authentication to verify the user with more than its passphrase.", "title": "PUT /settings/passphrase (with two-factor authentication)"}, {"location": "cozy-stack/settings/#request-first-step", "text": "PUT /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"current_passphrase\" : \"4f58133ea0f415424d0a856e0d3d2e0cd28e4358fce7e333cb524729796b2791\" }", "title": "Request (first step)"}, {"location": "cozy-stack/settings/#response-first-step", "text": "HTTP / 1.1 200 OK Set-Cookie : cozysessid=AAAAShoo3uo1Maic4VibuGohlik2eKUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure { \"two_factor_token\" : \"YxOSUjxd0SNmuwEEDRHXfw==\" } At this point, the current passphrase has been exchanged against a token, and a passcode should have been sent to the user to authenticate on the second step. The token/passcode pair can be used on the second step to update the passphrase.", "title": "Response (first step)"}, {"location": "cozy-stack/settings/#request-second-step", "text": "PUT /settings/passphrase HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"new_passphrase\" : \"2e7e1e04300356adc8fabf5d304b58c564399746cc7a21464fd6593edd925720\" , \"key\" : \"0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=\" , \"iterations\" : 10000 , \"two_factor_token\" : \"YxOSUjxd0SNmuwEEDRHXfw==\" , \"two_factor_passcode\" : \"4947178\" }", "title": "Request (second step)"}, {"location": "cozy-stack/settings/#response-second-step", "text": "HTTP / 1.1 204 No Content Set-Cookie : cozysessid=AAAAShoo3uo1Maic4VibuGohlik2eKUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa; Path=/; Domain=alice.example.com; Max-Age=604800; HttpOnly; Secure", "title": "Response (second step)"}, {"location": "cozy-stack/settings/#response_11", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#post-settingspassphrasecheck", "text": "This route can be used to check the passphrase of the user before making important changes like asking for the Cozy deletion.", "title": "POST /settings/passphrase/check"}, {"location": "cozy-stack/settings/#request_11", "text": "POST /settings/passphrase/check HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authentication : Bearer xxx { \"passphrase\" : \"2e7e1e04300356adc8fabf5d304b58c564399746cc7a21464fd6593edd925720\" }", "title": "Request"}, {"location": "cozy-stack/settings/#response_12", "text": "It will be 204 No Content if the passphrase is correct, or a 403 Forbidden if the passphrase is incorrect.", "title": "Response"}, {"location": "cozy-stack/settings/#get-settingshint", "text": "This route can be used to know if a hint has been chosen (but the hint won\u2019t be revealed). If there is a hint, the response will be a 204 No Content . And, if not, it will be a 404 No Content .", "title": "GET /settings/hint"}, {"location": "cozy-stack/settings/#request_12", "text": "GET /settings/hint HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/settings/#response_13", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#put-settingshint", "text": "The user can change the hint for its passphrase.", "title": "PUT /settings/hint"}, {"location": "cozy-stack/settings/#request_13", "text": "PUT /settings/hint HTTP / 1.1 Host : alice.example.com Content-Type : application/json { \"hint\" : \"My passphrase is very complicated\" }", "title": "Request"}, {"location": "cozy-stack/settings/#response_14", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#post-settingsvault", "text": "This route can be used to ensure the vault is initialized. If it is not the case, it will migrate the accounts from the konnectors accounts to the vault and will set the extension_installed flag.", "title": "POST /settings/vault"}, {"location": "cozy-stack/settings/#request_14", "text": "POST /settings/vault HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/settings/#response_15", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#instance", "text": "", "title": "Instance"}, {"location": "cozy-stack/settings/#get-settingscapabilities", "text": "List the activated capabilities for this instance. An unadvertised capability should be considered false and, for backward compatibility, if you can\u2019t get a valid response from this endpoint (in particular in case of a 404 Not found error), all capabilities should be considered false . The current capabilities are: file_versioning is true when the VFS can create old versions of a file flat_subdomains is true when the stack is configured to use flat subdomains (not nested) can_auth_with_password is true when authentication with a Cozy password is possible can_auth_with_magic_links is true when authentication with a link sent by email is possible can_auth_with_oidc is true when delegated authentication with OIDC is possible for this instance. Note: both can_auth_with_password and can_auth_with_oidc can be true for an instance where the choice is given to the user of how they want to authenticate.", "title": "GET /settings/capabilities"}, {"location": "cozy-stack/settings/#request_15", "text": "GET /settings/capabilities HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/settings/#response_16", "text": "{ \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.capabilities\" , \"attributes\" : { \"file_versioning\" : true , \"flat_subdomains\" : false , \"can_auth_with_password\" : true , \"can_auth_with_magic_links\" : false , \"can_auth_with_oidc\" : false }, \"links\" : { \"self\" : \"/settings/capabilities\" } } }", "title": "Response"}, {"location": "cozy-stack/settings/#permissions", "text": "No permissions are required to access this route, but the request needs to be authenticated (webapp token, OAuth token, etc.).", "title": "Permissions"}, {"location": "cozy-stack/settings/#get-settingsexternal-ties", "text": "List ties between the instance and external services such as a subscription vendor (e.g. mobile app stores). The current possible ties are: has_blocking_subscription is true when the instance is linked to a premium subscription paid via a third-party vendor that does not let us cancel the subscription ourselves and requires it to be cancelled by the customer themselves.", "title": "GET /settings/external-ties"}, {"location": "cozy-stack/settings/#request_16", "text": "GET /settings/external-ties HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/settings/#response_17", "text": "{ \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.external-ties\" , \"attributes\" : { \"has_blocking_subscription\" : false }, \"links\" : { \"self\" : \"/settings/external-ties\" } } }", "title": "Response"}, {"location": "cozy-stack/settings/#permissions_1", "text": "No permissions are required to access this route, but the request needs to be made from an authenticated Web session or Webapp.", "title": "Permissions"}, {"location": "cozy-stack/settings/#get-settingsinstance", "text": "If the user is logged in, display all instance settings.", "title": "GET /settings/instance"}, {"location": "cozy-stack/settings/#request_17", "text": "GET /settings/instance HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxx", "title": "Request"}, {"location": "cozy-stack/settings/#response_18", "text": "{ \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.instance\" , \"meta\" : { \"rev\" : \"3-56521545485448482\" }, \"attributes\" : { \"locale\" : \"fr\" , \"password_defined\" : true , \"auto_update\" : true , \"email\" : \"alice@example.com\" , \"public_name\" : \"Alice Martin\" , \"auth_mode\" : \"basic\" , \"default_redirection\" : \"drive/#/folder\" , \"context\" : \"dev\" , \"sponsorships\" : [ \"springfield\" ] } } }", "title": "Response"}, {"location": "cozy-stack/settings/#note-about-password_defined", "text": "There are a few fields that are persisted on the instance its-self, not on its settings document. When they are updated, it won\u2019t be reflected in the realtime when listening on the io.cozy.settings.instance document. For password_defined , it is possible to be notified when the password is defined by watching a synthetic document with the doctype io.cozy.settings , and the id io.cozy.settings.passphrase .", "title": "Note about password_defined"}, {"location": "cozy-stack/settings/#post-settingsinstancedeletion", "text": "The settings application can use this route if the user wants to delete their Cozy instance.", "title": "POST /settings/instance/deletion"}, {"location": "cozy-stack/settings/#request_18", "text": "POST /settings/instance/deletion HTTP / 1.1 Host : alice.example.com", "title": "Request"}, {"location": "cozy-stack/settings/#response_19", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#delete-settingsinstancemoved_from", "text": "When there is an attribute moved_from in the instance settings, it means that the Cozy has been moved from the given address. The Home application uses this information to display a modal to alert the user. And when they dismiss the modal, a request is made to this route to remove this information (and avoid showing this modal again the next time they will open the Home again).", "title": "DELETE /settings/instance/moved_from"}, {"location": "cozy-stack/settings/#request_19", "text": "DELETE /settings/instance/moved_from HTTP / 1.1 Host : target.cozy.localhost Cookie : sessionid=xxxxx", "title": "Request"}, {"location": "cozy-stack/settings/#response_20", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#permissions_2", "text": "No permission is required to use this route, only that the user is logged-in.", "title": "Permissions"}, {"location": "cozy-stack/settings/#put-settingsinstance", "text": "If the user is logged in, allow to set the instance fields", "title": "PUT /settings/instance"}, {"location": "cozy-stack/settings/#request_20", "text": "POST /settings/instance HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Content-Type : application/vnd.api+json Cookie : sessionid=xxxxx Authorization : Bearer settings-token { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.instance\" , \"meta\" : { \"rev\" : \"3-56521545485448482\" }, \"attributes\" : { \"locale\" : \"fr\" , \"email\" : \"alice@example.com\" , \"public_name\" : \"Alice Martin\" , \"timezone\" : \"Europe/Berlin\" , \"auth_mode\" : \"two_factor_mail\" , \"default_redirection\" : \"drive/#/folder\" } } } Note: the format for default_redirection is the application slug, followed by a slash, and then the route for the app (path + fragment).", "title": "Request"}, {"location": "cozy-stack/settings/#response_21", "text": "HTTP/1.1 200 OK Content-Type: application/json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.instance\" , \"meta\" : { \"rev\" : \"4-5a3e315e\" }, \"attributes\" : { \"locale\" : \"fr\" , \"email\" : \"alice@example.com\" , \"public_name\" : \"Alice Martin\" , \"timezone\" : \"Europe/Berlin\" , \"auth_mode\" : \"two_factor_mail\" , \"default_redirection\" : \"drive/#/folder\" } } }", "title": "Response"}, {"location": "cozy-stack/settings/#permissions_3", "text": "To use this endpoint, an application needs a permission on the type io.cozy.settings for the verb PUT .", "title": "Permissions"}, {"location": "cozy-stack/settings/#put-settingsinstanceauth_mode", "text": "With this route, the user can ask for the activation of different authentication modes, like two-factor authentication. Available authentication modes: basic : basic authentication only with passphrase two_factor_mail : authentication with passphrase and validation with a code sent via email to the user. When asking for activation of the two-factor authentication, a side-effect can be triggered to send the user its code (via email for instance), and the activation not being effective. This side-effect should provide the user with a code that can be used to finalize the activation of the two-factor authentication. Hence, this route has two behaviors: the code is not provided: the route is a side effect to ask for the activation of 2FA, and a code is sent the code is provided, and valid: the two-factor authentication is actually activated. Status codes: 204 No Content : when the mail has been confirmed and two-factor authentication is activated 422 Unprocessable Entity : when the given confirmation code is not good.", "title": "PUT /settings/instance/auth_mode"}, {"location": "cozy-stack/settings/#request_21", "text": "PUT /settings/instance/auth_mode HTTP / 1.1 Host : alice.example.com Content-Type : application/json Cookie : cozysessid=AAAAAFhSXT81MWU0ZTBiMzllMmI1OGUyMmZiN2Q0YTYzNDAxN2Y5NjCmp2Ja56hPgHwufpJCBBGJC2mLeJ5LCRrFFkHwaVVa { \"auth_mode\" : \"two_factor_mail\" , \"two_factor_activation_code\" : \"12345678\" }", "title": "Request"}, {"location": "cozy-stack/settings/#put-settingsinstancesign_tos", "text": "With this route, an OAuth client can sign the new TOS version. Status codes: 204 No Content : when the mail has been confirmed and two-factor authentication is activated", "title": "PUT /settings/instance/sign_tos"}, {"location": "cozy-stack/settings/#request_22", "text": "PUT /settings/instance/sign_tos HTTP / 1.1 Host : alice.example.com Content-Type : application/json Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/settings/#sessions", "text": "", "title": "Sessions"}, {"location": "cozy-stack/settings/#get-settingssessions", "text": "This route allows to get all the currently active sessions. GET /settings/sessions HTTP / 1.1 Host : cozy.example.org Cookie : ... Authorization : Bearer ... HTTP / 1.1 200 OK Content-Type : application/json { \"data\" : [ { \"id\" : \"...\" , \"attributes\" : { \"last_seen\" : \"\" }, \"meta\" : { \"rev\" : \"...\" } } ] }", "title": "GET /settings/sessions"}, {"location": "cozy-stack/settings/#permissions_4", "text": "This route requires the application to have permissions on the io.cozy.sessions doctype with the GET verb.", "title": "Permissions"}, {"location": "cozy-stack/settings/#oauth-2-clients", "text": "", "title": "OAuth 2 clients"}, {"location": "cozy-stack/settings/#get-settingsclients", "text": "Get the list of the registered clients", "title": "GET /settings/clients"}, {"location": "cozy-stack/settings/#request_23", "text": "GET /settings/clients HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxxx Authorization : Bearer oauth2-clients-token", "title": "Request"}, {"location": "cozy-stack/settings/#response_22", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.oauth.clients\" , \"id\" : \"30e84c10-e6cf-11e6-9bfd-a7106972de51\" , \"attributes\" : { \"redirect_uris\" : [ \"http://localhost:4000/oauth/callback\" ], \"client_name\" : \"Cozy-Desktop on my-new-laptop\" , \"client_kind\" : \"desktop\" , \"client_uri\" : \"https://docs.cozy.io/en/mobile/desktop.html\" , \"logo_uri\" : \"https://docs.cozy.io/assets/images/cozy-logo-docs.svg\" , \"policy_uri\" : \"https://cozy.io/policy\" , \"software_id\" : \"/github.com/cozy-labs/cozy-desktop\" , \"software_version\" : \"0.16.0\" , \"client_os\" : \"Windows\" , \"last_refreshed_at\" : \"2017-09-04T08:14:47Z\" , \"synchronized_at\" : \"2017-09-05T16:23:04Z\" }, \"links\" : { \"self\" : \"/settings/clients/30e84c10-e6cf-11e6-9bfd-a7106972de51\" } } ] }", "title": "Response"}, {"location": "cozy-stack/settings/#permissions_5", "text": "To use this endpoint, an application needs a permission on the type io.cozy.oauth.clients for the verb GET (only client-side apps).", "title": "Permissions"}, {"location": "cozy-stack/settings/#delete-settingsclientsclient-id", "text": "", "title": "DELETE /settings/clients/:client-id"}, {"location": "cozy-stack/settings/#request_24", "text": "DELETE /settings/clients/30e84c10-e6cf-11e6-9bfd-a7106972de51 HTTP / 1.1 Host : alice.example.com Authorization : Bearer oauth2-clients-token", "title": "Request"}, {"location": "cozy-stack/settings/#response_23", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#permissions_6", "text": "To use this endpoint, an application needs a permission on the type io.cozy.oauth.clients for the verb DELETE (only client-side apps).", "title": "Permissions"}, {"location": "cozy-stack/settings/#get-settingsclientslimit-exceeded", "text": "Get an OAuth clients limit exceeded page if the instance has more connected OAuth clients than its limit allows or redirect the request to the redirect parameter\u2019s value. The redirect parameter is optional. By default, its value is the instance\u2019s default redirection. The page will auto-refresh every 20 seconds or when an OAuth client deletion is detected.", "title": "GET /settings/clients/limit-exceeded"}, {"location": "cozy-stack/settings/#query-string", "text": "Parameter Description redirect URL where to redirect when the limit is not exceeded", "title": "Query-String"}, {"location": "cozy-stack/settings/#request_25", "text": "GET /settings/clients/limit-exceeded?redirect=https%3A%2F%2Falice-home.example.com%2F HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxx", "title": "Request"}, {"location": "cozy-stack/settings/#post-settingssynchronized", "text": "Any OAuth2 client can make a request to this endpoint with its token, no permission is needed. It will update the date of last synchronization for this device.", "title": "POST /settings/synchronized"}, {"location": "cozy-stack/settings/#request_26", "text": "POST /settings/synchronized HTTP / 1.1 Host : alice.example.com Authorization : Bearer oauth2-access-token", "title": "Request"}, {"location": "cozy-stack/settings/#response_24", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/settings/#context", "text": "", "title": "Context"}, {"location": "cozy-stack/settings/#get-settingsonboarded", "text": "It redirects the user to an application after the onboarding. The application is selected according to the context of the instance and the configuration of the stack.", "title": "GET /settings/onboarded"}, {"location": "cozy-stack/settings/#get-settingsinstall_flagship_app", "text": "At the end of an onboarding, just after the password has been chosen, if the user is in a mobile browser, the stack will show a page to push them to install the flagship app.", "title": "GET /settings/install_flagship_app"}, {"location": "cozy-stack/settings/#get-settingscontext", "text": "It gives the keys/values from the config for the context of the instance.", "title": "GET /settings/context"}, {"location": "cozy-stack/settings/#request_27", "text": "GET /settings/context HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json Cookie : sessionid=xxxx", "title": "Request"}, {"location": "cozy-stack/settings/#response_25", "text": "{ \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.context\" , \"attributes\" : { \"default_redirection\" : \"drive/#/folder\" , \"help_link\" : \"https://forum.cozy.io/\" , \"onboarded_redirection\" : \"home/#/discovery/?intro\" }, \"links\" : { \"self\" : \"/settings/context\" } } }", "title": "Response"}, {"location": "cozy-stack/settings/#permissions_7", "text": "To use this endpoint, an application needs a valid token, but no explicit permission is required.", "title": "Permissions"}, {"location": "cozy-stack/settings/#feature-flags", "text": "A feature flag is a name and an associated value (boolean, number, string or a JSON) that can be interpreted by the apps. It can be used for giving access to paid features, or to enable a feature progressively on all the cozy instances of a context. The stack computes the feature flags from several sources (in order of decreasing priority): the flags set on the instance by the command cozy-stack feature flags the response of the manager for GET /api/v1/flags?sets=s1,s2&context=ctx (where s1,s2 has been set via cozy-stack feature sets ) the flags coming from the context configuration ( context..features ) the flags set on the context by the command cozy-stack feature ratio the default value ( cozy-stack feature default ). For a given flag, the stack takes the value from the source with the highest priority, and does not look at the other sources (no merge).", "title": "Feature flags"}, {"location": "cozy-stack/settings/#get-settingsflags", "text": "This endpoint returns the computed list of feature flags for the given instance. It accepts an include parameter in the query string to see the details of how the flags were computed.", "title": "GET /settings/flags"}, {"location": "cozy-stack/settings/#request_28", "text": "GET /settings/flags HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/settings/#response_26", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags\" , \"attributes\" : { \"has_feature1\" : true , \"has_feature2\" : false , \"number_of_foos\" : 10 , \"bar_config\" : { \"qux\" : \"quux\" } }, \"links\" : { \"self\" : \"/settings/flags\" } } }", "title": "Response"}, {"location": "cozy-stack/settings/#request_29", "text": "GET /settings/flags?include=source HTTP / 1.1 Host : alice.example.com Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/settings/#response_27", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags\" , \"attributes\" : { \"has_feature1\" : true , \"has_feature2\" : false , \"number_of_foos\" : 10 , \"bar_config\" : { \"qux\" : \"quux\" } }, \"links\" : { \"self\" : \"/settings/flags\" } }, \"included\" : [ { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.instance\" , \"attributes\" : { \"number_of_foos\" : 10 } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.manager\" , \"attributes\" : { \"sets\" : [ \"s1\" , \"s2\" ], \"has_feature1\" : true , \"number_of_foos\" : 5 } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.config\" , \"attributes\" : { \"number_of_foos\" : 2 } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.context\" , \"attributes\" : { \"has_feature2\" : [{ \"ratio\" : 0.1 , \"value\" : true }], \"bar_config\" : [ { \"ratio\" : 0.2 , \"value\" : { \"qux\" : \"quux\" } }, { \"ratio\" : 0.8 , \"value\" : { \"qux\" : \"baz\" } } ] } }, { \"type\" : \"io.cozy.settings\" , \"id\" : \"io.cozy.settings.flags.default\" , \"attributes\" : { \"bar_config\" : { \"qux\" : \"courge\" }, \"number_of_foos\" : 2 } } ] }", "title": "Response"}, {"location": "cozy-stack/settings/#permissions_8", "text": "To use this endpoint, an application needs a valid token, but no explicit permission is required.", "title": "Permissions"}, {"location": "cozy-stack/sharing-design/", "text": "Table of contents Sharing design \u00b6 Baseline \u00b6 Here we detail the baseline of the Cozy sharing design and provide some core statements. Data sync \u00b6 The shared data is duplicated among members: it is both on the sharer\u2019s cozy (the owner), and on the recipients\u2019 cozy. This is a core difference compared to a federated sharing such as the one in NextCloud . The CouchDB replication protocol is used to synchronize the documents. It means that the documents will be same on the owner side and on the recipients side (\u201csymmetric sharing\u201d). The applications say what is shared, the cozy stack synchronizes that. The stack does the low-level work and gives primitives to the applications. The applications must use them in a responsible manner, and in particular, to avoid transitivity issues. The applications should know how to deal with documents\u2019 conflicts, e.g. what to do with a document updated by several members at the same time with different content. At least, the default CouchDB behaviour to handle conflicts and select winning revisions should be acceptable if the applications don\u2019t do anything to detect and resolve conflicts. Contacts discovery \u00b6 A sharer may not know the addresses of the recipients\u2019 cozy instances, but he/she has a way to send them an URL on his/her cozy to start the process. Recipient preview \u00b6 A recipient can preview a sharing before accepting it if the application supports this option. Else, he/she will have only the description and rules to make his/her mind about accepting or refusing the sharing. Specific data type support \u00b6 For files and folders, the documents replication process (the replicator) is customized to handle the specificities of the io.cozy.files doctype. The applications must be able to work with broken relationships between documents, which can happen if one shares a document without its relationships. Safety principles \u00b6 First safety principle : when a user B accepts a sharing from user A, the documents that were on the user B\u2019s cozy before the sharing are not sent to user A without an explicit action of user B (like moving a file to a shared directory). Second safety principle : when two users, A and B, are sharing documents, a change of a document on the user A\u2019s cozy can\u2019t make an exiting document of user B enter in the sharing. Setup of a sharing \u00b6 Step 1: the owner creates the sharing \u00b6 One person decides to share something with other people from an application on her cozy. In our example, Alice wants to share a todo list with her friends, Bob and Charlie, and it is done from the Todo application. The application calls the stack with the rules for this sharing, including the documents to target and the rights granted to the recipients, to add/update/delete todos. It also specifies the contacts with whom to share by providing their identifiers. See the sharing schema for a complete description of the expected fields. The stack persists an io.cozy.sharings document and sends an email to the recipients (Bob an Charlie). Step 2: a recipient accepts the sharing \u00b6 A recipient, let\u2019s say Bob, receives the email and clicks on the link. His browser shows him the Todo application on Alice\u2019s Cozy so that he can preview the todo list, and a modal asks him if he wants to continue the sharing acceptation workflow. If he does, a form will ask him what is the address of his Cozy (the form can be pre-filled if he has already accepted another sharing in the past). After he has filled the form and submitted it, he is redirected on his Cozy. If he is not logged in, he has to login first. Then, a page describes him how the sharing will work and what technical permissions it implies. It also asks him to confirm the sharing. If he accepts, his instance will send to Alice\u2019s instance the answer. Step 3: the initial replication starts \u00b6 Alice\u2019s Cozy instance creates some tokens and sends them with other informations such as the response of the answer request from Bob\u2019s instance. At this moment, both instances are ready to start to replicate data to the other instances. So, let\u2019s do the initial replication. Alice\u2019s instance starts to fill the io.cozy.shared database with all the documents that match a rule of the sharing (except the rules with local: true ), and create triggers for the future documents to be also added in this database (the exact triggers depend of the parameters of the rules). And, when done, it creates a job for the replicator, and setups a trigger for future changes in the io.cozy.shared to start a replicator job. This mechanism is further explained in the data sync section. Bob\u2019s instance also checks if any document matches a sharing rule. In most cases, it won\u2019t. But in some very special cases (e.g. a previous revoked sharing on the same documents), there are some documents that match a rule. They are added to the io.cozy.shared database, but with a conflict flag. They won\u2019t be replicated unless Bob accepts to in his Todo application. Triggers are also added on Bob\u2019s instance for filling the io.cozy.shared database, and to call the replicator after that. Note: there is a lock around the initial filling of the io.cozy.shared database to avoid concurrency issues if two recipients accept the sharing at the same time. Data sync \u00b6 As stated in the baseline, the shared data is copied among the databases of all the members for a sharing. Therefore, contrarily to centralized or federated sharing, where the same data is accessed by all members, extra work must be done to replicate changes between all members. The replication mode is specified in a sharing rule for each document action: add, update or delete. It can be: none : the changes won\u2019t be replicated between members. push : only the changes made by the owner will be propaged to the recipients. sync : the changes made by any member are propagated to the other members. See the sharing schema for more details and examples. The data synchronization is based on the document\u2019s revisions. Each time a document is updated in database, a new revision is created with the following format: 1-abc , where 1 is a number incremented at each new change and abc a hash of the document. The revisions history of each shared document is saved in a io.cozy.shared document. This history is used to compare revisions between sharing members and propagate updates. Hence, not only the shared documents are synced, but also their whole revisions history through the io.cozy.shared database. See the revisions syncing section for a complete example. General workflow \u00b6 In the following, we assume the a sync sharing for all actions between Alice, Bob and Charlie. Step 1: a todo item is added on Bob\u2019s Cozy, a trigger is fired and it adds the new document to the io.cozy.shared database Step 2: a debounced trigger on the io.cozy.shared database is used to start a replicator Step 3: the replicator does the following steps it queries a local document of the io.cozy.shared database to get the last sequence number of a successful replication with this sequence number, it requests the changes feed of io.cozy.shared with a filter on the sharing id the results is a list of document doctype + id + rev that is sent to Alice\u2019s Cozy Alice\u2019s Cozy checks which revisions are known, and send a response with the list of those that are not for each not known revision, Bob\u2019s Cozy send the document to Alice\u2019s Cozy (in bulk) and, if it\u2019s all good, it persists the new sequence number in the local document, as a start point for the next replication Step 4: the changes are put in the io.cozy.shared database on Alice\u2019s Cozy Step 5: it starts a replicator on Alice\u2019s Cozy Step 6: the replicator send the changes to Charlie\u2019s Cozy, all the cozy instances are synchronized again! Note: when a todo item is moved fron a shared todo list to a not shared todo list, the document in io.cozy.shared for the todo item is kept, and the sharing id is associated to the keyword removed inside it. The remove behavior of the sharing rule is then applied. Revisions syncing \u00b6 Here, we detail the internals of the revisions-based syncing mechanism through an example: Alice, Bob and Charlie share a Todo with the id \u201ctodo1\u201d. Note that in reality this id would be an UUID, but we give it a simple name for the sake of clarity. This Todo had only one update (its creation), made by Alice that generated the revision 1-a . After the initial replication, all the members have a io.cozy.shared document, with this sole revision as history. This history is actually a tree: when a CouchDB conflict occurs, a new branch is created, containing the losing revision, so we can keep track of it and avoid losing any data. Note the document id is in the form / to easily reference the shared document. Here, it is io.cozy.todos/todo1 . In the sequence diagram below, we illustrate the steps occuring when Alice generates updates. We also illustrate how a CouchDB can occur and how it is handled, by making Charlie updating the same document than Alice at the same time. This update leads to a conflict between the revisions 2-a , generated by Alice, and 2-c , generated by Charlie: a winning revision is then elected by CouchDB, 2-a , but 2-c is saved in another branch of the revision tree. Thanks to it, the conflict is propagated to other members that will be able to resolve it through the Todo application (by manually erasing or merging the conflicted revision for instance). Eventually, all members converge to the same state with the same docs and the same revisions histories. CouchDB conflicts \u00b6 A CouchDB conflict is when a document has conflicting revisions, i.e. it has at least two revisions branches in its revision history. Hence, these conflicts are made on the database level. By design , CouchDB can produce conflicts in its replication protocol, as the revision history is replicated and forced among nodes. We detail here how a CouchDB conflict can be made. In the particular case of files and folders, we implemented specific strategies to avoid having to deal with conflicts at the application level: the stack is able to prevent CouchDB conflicts for io.cozy.files documents and enforce reconciliation when possible. We also detail what is done when no reconciliation can be made. Id transformations \u00b6 Initially, we were using the CouchDB protocol revision as described above, but we have introduced a transformation of the identifiers for io.cozy.files, and later, we have generalized this transformation for all doctypes. It means that Alice and Bob have the same shared documents, but not with the same identifiers. The identifiers are transformed with a XOR, using a key exchanged when the recipient accepts the sharing. In practice, it is useful when someone is revoked from a sharing, and accepts later the sharing again. It allows to avoid reusing the same identifiers for documents exchanged on the first sharing and on the second sharing, which can create some weird situations. For example, a cipher is shared between Alice and Bob when its revision is 3-aaa. Later, when the sharing is revoked, the document will be deleted on Bob\u2019s instance (the ciphers are deleted on recipients when a sharing is revoked), which creates a revision 4-bbb. If Alice invites Bob again, and Bob accepts, the replication will sent the document from Alice\u2019s instance to Bob\u2019s instance with revision 3-aaa. CouchDB will say OK, but the revision 4-bbb will still be seen as a successor of 3-aaa, and for CouchDB, the document will still be deleted. Using different IDs for the first and second sharing fixes this issue. Files and folders \u00b6 Why are they special? \u00b6 Files are special for several reasons. First and foremost, they have a binary attached to them that can be quite heavy. The stack also enforces some rules on them (e.g. a file can\u2019t be added to a deleted folder) and has some specific code for the tree nature of files and folders (e.g. a permission on a folder is inherited on all the files and folders inside it, even if they are several levels below). Thus, the workflow explained just before is not compatible with the files. As we need to introduce some code specific to the files, we have also wanted to improve the sharing of files. First, we don\u2019t want to force the recipients to put the shared folder at exactly the same place as the owner. In fact, we think that putting the shared folder in a folder called Shared with me is more friendly. We also think that a file that has been shared in the past but is no longer (the sharing has been revoked) can evolve on both the owner\u2019s cozy and on the recipients\u2019 cozy in different ways, and in such a case, it\u2019s more logical to consider them as different files. These two reasons implies, on a technical level, that the identifiers for files and folders are not the same on the owner and the recipients of a sharing. The replicator will translate the identifiers from one system to another during the replications. Of course, it will also translate the id in the sharing rules, and the dir_id to preserve the relationship between a file and its parent folder. The path attribute will be seen as a cache, and recomputed when a cozy instance receives a folder document from a sharing replication. We will continue to have a replication as close to the CouchDB replication as possible. It means we synchronize a state, and not looking for the history of operations like cozy-desktop does. It is less accurate and can lead more often to conflicts. The cozy instances are expected to be online most of the time and have a short delay for replications: we think that the conflicts will happen only on rares occasions. This make acceptable to take this shortcut. And, in case of conflicts, we will preserve the content of the files (no data loss), even if it means duplicating the files. How a sharing involving files works? \u00b6 When a sharing involves a rule on the io.cozy.files doctype, a folder is created on the recipients cozy where the files will be put. It is created inside the Shared with me folder by default, but can be moved somewhere else after that. The folder won\u2019t be synchronized its-self later, and if the folder is trashed, the sharing is automatically revoked. As it is not a reversible action, a confirmation is asked before doing that. Note: we will forbid the sharing of the root of the virtual file system, of the trash and trashed files/folders, and of course the Shared with me folder. The step 3 described above, aka the replicator, will be more complicated for folders and files. First change, it will work on two phases: 1. what can be synchronized without transfering the binaries first, and 2. the synchronization of files with a binary attached. Second change, the replicator will acquire the Virtual File System lock on the cozy instance where it will write things to ensure the consistency of what it writes. Third change, before inserting a folder or file in the database, the replicator checks that its parent exists, and if it\u2019s not the case, it creates it. Last change, we will avoid CouchDB conflicts for files and folder by using a special conflict resolution process. Sequence diagram \u00b6 Conflict resolution \u00b6 In the case of io.cozy.files documents, we prevent CouchDB conflicts to happen by implementing specific strategies. Here, we detail the conflicts situations where a resolution is possible: When two cozy instances have modified the same file concurrently Same for a folder When two files or folders are renamed concurrently to the same name inside the same directory When a file or folder is created or updated on cozy instance while the parent directory is trashed concurrently on another cozy instance. For 1. and 2., we will reconciliate the changes except for a file with two versions having a distinct binary (we rely on size and checksum to detect that). In such a case, we create a copy of the file with one version, while keeping the other version in the original file (the higher revision wins). For 3., we say that the owner instance wins: the file with the name in conflict on the owner instance will keep its name, and the other file with the same name will be renamed. This rule helps to minimize the number of exchanges between the cozy instances, which is a factor of stability to avoid more conflicts. For 4., we restore the trashed parent, or recreate it if it the trash was emptied. Conflict with no reconciliation \u00b6 When a file is modified concurrently on two cozy instances, and at least one change involve the content, we can\u2019t reconciliate the modifications. To know which version of the file is the \u201cwinner\u201d and will keep the same identifier, and which version is the \u201closer\u201d and will have a new identifier, we compare the revisions and the higher wins. This conflict is particulary tricky to resolve, with a lot of subcases. In particular, we try to converge to the same revisions on all the instances for the \u201cwinner\u201d file (and for the \u201closer\u201d too). We have 3 sets of attributes for files: size and md5sum (they change when the content has changed) name and dir_id (they change when the file is moved or renamed) created_at , updated_at , tags , referenced_by , etc. For the first two sets, the operation on the Virtual File System will needs to reach the storage (Swift), not just CouchDB. For the third set, it\u2019s easy: we can do the change at the same time as another change, because these attributes are only used in CouchDB. But we can\u2019t do a change on the first two sets at the same time: the Virtual File System can\u2019t update the content and move/rename a file in the same operation. If we needs to do both, it will generate 2 revisions in CouchDB for the file. Note: you can see that using CouchDB-like replication protocol means that we have some replications that can look useless, just some echo to a writing. In fact, it is used to acknowledge the writing and is helpful for conflict resolutions. It may be conter-intuitive, but removing them will harm the stability of the system, even if they do nothing most of the time. Example 1 \u00b6 Here, Alice uploads a file on her Cozy. It creates two revisions for this file (it\u2019s what the Virtual File System does). Then, she shares the directory with this file to her friend Bob. When Bob accepts the sharing, the file is sent to his Cozy, with the same revision (2-2aa). Later, Bob renames the file. It creates a new revision (3-3aa). The change is replicated to Alice\u2019s Cozy. And we have a replication from Alice to Bob to ensure that every thing is fine. Even later, Alice and Bob both renames the file at the same time. It creates a conflict. We have a first replication (from Alice to Bob), but nothing happens on B because the local revision (4-4bb) is greater than the candidate revision (4-4aa) and the content is the same. Just after that, we have a revision on the opposite direction (from Bob to Alice). The candidate revision wins (4-4bb), but for files, we don\u2019t use CouchDB conflict, thus it\u2019s not possible to write a new revision at the same generation (4). The only option is to create a new revision (5-5bb). This revision is then sent to Bob: Bob\u2019s Cozy accepts the new revision even if it has no effect on the file (it was already the good name), just to resolve the conflict. Example 2 \u00b6 Like in the last example, Alice uploads a file and share a directory to Bob with this file, Bob acccepts. But then, several actions are made on the file in a short lapse of time and it generates a difficult conflict: Alice renames the file, and then uploads a new version with cozy-desktop Bob moves the file to a sub-directory. So, when the replication comes, we have two versions of the file with different name, parent directory, and content. The winner is the higher revision (4-4aa). The resolution takes 4 steps: A copy of the file is created from the revision 3-3bb, with the new identifier id2 = XorID(id, 3-3bb). The new content is written on Bob\u2019s Cozy: we can\u2019t use the revisions 3-3aa (same generation as 3-3bb) and 4-4aa (it will mean the conflict is fixed, but it\u2019s not the case, the filenames are still different), so a new revision is used (4-4cc). The file is moved and renamed on Bob\u2019s Cozy, with a next revision (5-5bb). The two files are sent to Alice\u2019s Cozy: 5-5bb is accepted just to resolve the conflict, and id2 is uploaded as a new file. Special case: out and in again \u00b6 Let\u2019s look at a special case. Alice shares a folder with Bob and Charlie. It contains a directory, with a few files inside it. This directory has been synchronized, and Bob decides to move it somewhere else on its cozy instance that is not inside the shared folder, let\u2019s say at the root. The sharing synchronization will move the directory to the trash for Alice and Charlie. Bob can continue to work on the files in this directory. If Charlie restores the directory from the trash, it will be put again in the sharing. And we can see that we have an issue: on Bob instance, we will have two copies on the files, at two different locations, but technically, they should have the same identifiers. It is not possible. To avoid that, we have to change the identifier, or more precisely, delete a file and recreate it with a new identifier. It means losing historical versions and some other things like sharing by links. It is an operation that takes a lot of resources. So, we need to be careful in how we do that. And, like usual for the sharing, we need to take care of the stability and convergence of the replication algorithm. With these constraints, the approache we have chosen is to put a copy of a file that was moved out of the sharing in the trash when this operation is replicated. For the member of the sharing that has made the operation, the file will be the same (no need to change how the VFS work), and it is only later, when this change is replicated to the other members that we will put a copy of the file in the trash and delete the file (this is managed by the sharing layer). Thus, the other members of the sharing will have a copy of the file, but not the original file (sharing by links won\u2019t work on the copy for example), and the old versions of the file will be lost. We think it is an acceptable tradeoff between complexity, reliability, and matching the user expectations. Still, it has an important limitation. If Alice and Bob moves a file from the shared directory to somewhere else at the same time, and later, one of them is moving again the file inside the shared directory, we will be in a bad situation, where the replication algorithm can\u2019t synchronize the file. For the moment, we prefer to advance with this limitation, but we will have to take care of it later. Schema \u00b6 Description of a sharing \u00b6 An identifier (the same for all members of the sharing) A list of members . The first one is the owner. For each member, we have: status , a status that can be: owner for the member that has created the sharing mail-not-sent for a member that has been added, but its invitation has not yet been sent (often, this status is used only for a few seconds) pending for a member with an invitation sent, but who has not clicked on the link seen for a member that has clicked on the invitation link, but has not setup the Cozy to Cozy replication for the sharing ready for a member where the Cozy to Cozy replication has been set up revoked for a member who is on longer in the sharing name , a contact name public_name , a public name email , the email address instance , the URL of the Cozy read_only , a flag to tell if the contact is restricted to read-only mode only_in_groups , a flag that will be false if the member has been added as a single contact groups , a list of indexes of the groups A list of groups , with for each one: id , the identifier of the io.cozy.contacts.groups name , the name of the group addedBy , the index of the member that has added the group read_only , a flag to tell if the group is restricted to read-only mode revoked , a flag set to true when the group is revoked from the sharing Some credentials to authorize the transfer of data between the owner and the recipients A description (one sentence that will help people understand what is shared and why) A flag active that says if the sharing is currently active for at least one member A flag owner , true for the document on the cozy of the sharer, and false on the other cozy instance A flag open_sharing : true if any member of the sharing except the read-only ones can add a new recipient false if only the owner can add a new recipient Some technical data ( created_at , updated_at , app_slug , preview_path , triggers , credentials ) A flag initial_sync present only when the initial replication is still running A number of files to synchronize for the initial sync, initial_number_of_files_to_sync (if there are no files to sync or the initial replication has finished, the field won\u2019t be here) A shortcut_id with the identifier of the shortcut file (when the recipient doesn\u2019t want to synchronize the documents on their Cozy instance) A list of sharing rules , each rule being composed of: a title , that will be displayed to the recipients before they accept the sharing a doctype (and a mime if the doctype is io.cozy.files ) a selector (by default, it\u2019s the id ) and values (one identifier, a list of identifiers, files and folders inside a folder, files that are referenced by the same document, documents bound to a previous sharing rule) local : by default false , but it can be true for documents that are useful for the preview page but doesn\u2019t need to be send to the recipients (e.g. a setting document of the application) add : a behavior when a new document matches this rule (the document is created, or it was a document that didn\u2019t match the rule and is modified and the new version matches the rule): none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member (except the read-only) are propagated to the other members update : a behavior when a document matched by this rule is modified. Can be: none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member (except the read-only) are propagated to the other members remove : a behavior when a document no longer matches this rule (the document is deleted, or it was a document that matched the rule, and is modified and the new version doesn\u2019t match the rule): none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member (except the read-only) are propagated to the other members revoke : the sharing is revoked. Example: I want to share a folder in read/write mode \u00b6 rule 1 title: folder doctype: io.cozy.files values: \"ca527016-0d83-11e8-a580-3b965c80c7f7\" add: sync update: sync remove: sync Example: I want to share a playlist where I\u2019m the only one that can add and remove items \u00b6 rule 1 title: playlist doctype: io.cozy.music.playlists values: \"99445b14-0d84-11e8-ae72-4b96fcbf0552\" update: none remove: revoke rule 2 title: items doctype: io.cozy.files selector: referenced_by values: \"io.cozy.files/ca527016-0d83-11e8-a580-3b965c80c7f7\" add: push update: none remove: push io.cozy.shared \u00b6 This doctype is an internal one for the stack. It is used to track what documents are shared, and to replicate changes from one Cozy to the others. _id : its identifier is the doctype and id of the referenced objet, separated by a / (e.g. io.cozy.contacts/c1f5dae4-0d87-11e8-b91b-1f41c005768b ) _rev : the CouchDB default revision for this document (not very meaningful, it\u2019s here to avoid concurrency issues) revisions : a tree with the last known _rev s of the referenced object infos , a map of sharing ids \u2192 {rule, removed, binary} rule says which rule from the sharing must be applied for this document removed will be true for a deleted document, a trashed file, or if the document does no longer match the sharing rule binary is a boolean flag that is true only for files (and not even folders) with removed: false dissociated is a boolean flag that can be true only for files and folders when they have been removed from the sharing but can be put again (only on the Cozy instance of the owner)", "title": "Sharing design"}, {"location": "cozy-stack/sharing-design/#sharing-design", "text": "", "title": "Sharing design"}, {"location": "cozy-stack/sharing-design/#baseline", "text": "Here we detail the baseline of the Cozy sharing design and provide some core statements.", "title": "Baseline"}, {"location": "cozy-stack/sharing-design/#data-sync", "text": "The shared data is duplicated among members: it is both on the sharer\u2019s cozy (the owner), and on the recipients\u2019 cozy. This is a core difference compared to a federated sharing such as the one in NextCloud . The CouchDB replication protocol is used to synchronize the documents. It means that the documents will be same on the owner side and on the recipients side (\u201csymmetric sharing\u201d). The applications say what is shared, the cozy stack synchronizes that. The stack does the low-level work and gives primitives to the applications. The applications must use them in a responsible manner, and in particular, to avoid transitivity issues. The applications should know how to deal with documents\u2019 conflicts, e.g. what to do with a document updated by several members at the same time with different content. At least, the default CouchDB behaviour to handle conflicts and select winning revisions should be acceptable if the applications don\u2019t do anything to detect and resolve conflicts.", "title": "Data sync"}, {"location": "cozy-stack/sharing-design/#contacts-discovery", "text": "A sharer may not know the addresses of the recipients\u2019 cozy instances, but he/she has a way to send them an URL on his/her cozy to start the process.", "title": "Contacts discovery"}, {"location": "cozy-stack/sharing-design/#recipient-preview", "text": "A recipient can preview a sharing before accepting it if the application supports this option. Else, he/she will have only the description and rules to make his/her mind about accepting or refusing the sharing.", "title": "Recipient preview"}, {"location": "cozy-stack/sharing-design/#specific-data-type-support", "text": "For files and folders, the documents replication process (the replicator) is customized to handle the specificities of the io.cozy.files doctype. The applications must be able to work with broken relationships between documents, which can happen if one shares a document without its relationships.", "title": "Specific data type support"}, {"location": "cozy-stack/sharing-design/#safety-principles", "text": "First safety principle : when a user B accepts a sharing from user A, the documents that were on the user B\u2019s cozy before the sharing are not sent to user A without an explicit action of user B (like moving a file to a shared directory). Second safety principle : when two users, A and B, are sharing documents, a change of a document on the user A\u2019s cozy can\u2019t make an exiting document of user B enter in the sharing.", "title": "Safety principles"}, {"location": "cozy-stack/sharing-design/#setup-of-a-sharing", "text": "", "title": "Setup of a sharing"}, {"location": "cozy-stack/sharing-design/#step-1-the-owner-creates-the-sharing", "text": "One person decides to share something with other people from an application on her cozy. In our example, Alice wants to share a todo list with her friends, Bob and Charlie, and it is done from the Todo application. The application calls the stack with the rules for this sharing, including the documents to target and the rights granted to the recipients, to add/update/delete todos. It also specifies the contacts with whom to share by providing their identifiers. See the sharing schema for a complete description of the expected fields. The stack persists an io.cozy.sharings document and sends an email to the recipients (Bob an Charlie).", "title": "Step 1: the owner creates the sharing"}, {"location": "cozy-stack/sharing-design/#step-2-a-recipient-accepts-the-sharing", "text": "A recipient, let\u2019s say Bob, receives the email and clicks on the link. His browser shows him the Todo application on Alice\u2019s Cozy so that he can preview the todo list, and a modal asks him if he wants to continue the sharing acceptation workflow. If he does, a form will ask him what is the address of his Cozy (the form can be pre-filled if he has already accepted another sharing in the past). After he has filled the form and submitted it, he is redirected on his Cozy. If he is not logged in, he has to login first. Then, a page describes him how the sharing will work and what technical permissions it implies. It also asks him to confirm the sharing. If he accepts, his instance will send to Alice\u2019s instance the answer.", "title": "Step 2: a recipient accepts the sharing"}, {"location": "cozy-stack/sharing-design/#step-3-the-initial-replication-starts", "text": "Alice\u2019s Cozy instance creates some tokens and sends them with other informations such as the response of the answer request from Bob\u2019s instance. At this moment, both instances are ready to start to replicate data to the other instances. So, let\u2019s do the initial replication. Alice\u2019s instance starts to fill the io.cozy.shared database with all the documents that match a rule of the sharing (except the rules with local: true ), and create triggers for the future documents to be also added in this database (the exact triggers depend of the parameters of the rules). And, when done, it creates a job for the replicator, and setups a trigger for future changes in the io.cozy.shared to start a replicator job. This mechanism is further explained in the data sync section. Bob\u2019s instance also checks if any document matches a sharing rule. In most cases, it won\u2019t. But in some very special cases (e.g. a previous revoked sharing on the same documents), there are some documents that match a rule. They are added to the io.cozy.shared database, but with a conflict flag. They won\u2019t be replicated unless Bob accepts to in his Todo application. Triggers are also added on Bob\u2019s instance for filling the io.cozy.shared database, and to call the replicator after that. Note: there is a lock around the initial filling of the io.cozy.shared database to avoid concurrency issues if two recipients accept the sharing at the same time.", "title": "Step 3: the initial replication starts"}, {"location": "cozy-stack/sharing-design/#data-sync_1", "text": "As stated in the baseline, the shared data is copied among the databases of all the members for a sharing. Therefore, contrarily to centralized or federated sharing, where the same data is accessed by all members, extra work must be done to replicate changes between all members. The replication mode is specified in a sharing rule for each document action: add, update or delete. It can be: none : the changes won\u2019t be replicated between members. push : only the changes made by the owner will be propaged to the recipients. sync : the changes made by any member are propagated to the other members. See the sharing schema for more details and examples. The data synchronization is based on the document\u2019s revisions. Each time a document is updated in database, a new revision is created with the following format: 1-abc , where 1 is a number incremented at each new change and abc a hash of the document. The revisions history of each shared document is saved in a io.cozy.shared document. This history is used to compare revisions between sharing members and propagate updates. Hence, not only the shared documents are synced, but also their whole revisions history through the io.cozy.shared database. See the revisions syncing section for a complete example.", "title": "Data sync"}, {"location": "cozy-stack/sharing-design/#general-workflow", "text": "In the following, we assume the a sync sharing for all actions between Alice, Bob and Charlie. Step 1: a todo item is added on Bob\u2019s Cozy, a trigger is fired and it adds the new document to the io.cozy.shared database Step 2: a debounced trigger on the io.cozy.shared database is used to start a replicator Step 3: the replicator does the following steps it queries a local document of the io.cozy.shared database to get the last sequence number of a successful replication with this sequence number, it requests the changes feed of io.cozy.shared with a filter on the sharing id the results is a list of document doctype + id + rev that is sent to Alice\u2019s Cozy Alice\u2019s Cozy checks which revisions are known, and send a response with the list of those that are not for each not known revision, Bob\u2019s Cozy send the document to Alice\u2019s Cozy (in bulk) and, if it\u2019s all good, it persists the new sequence number in the local document, as a start point for the next replication Step 4: the changes are put in the io.cozy.shared database on Alice\u2019s Cozy Step 5: it starts a replicator on Alice\u2019s Cozy Step 6: the replicator send the changes to Charlie\u2019s Cozy, all the cozy instances are synchronized again! Note: when a todo item is moved fron a shared todo list to a not shared todo list, the document in io.cozy.shared for the todo item is kept, and the sharing id is associated to the keyword removed inside it. The remove behavior of the sharing rule is then applied.", "title": "General workflow"}, {"location": "cozy-stack/sharing-design/#revisions-syncing", "text": "Here, we detail the internals of the revisions-based syncing mechanism through an example: Alice, Bob and Charlie share a Todo with the id \u201ctodo1\u201d. Note that in reality this id would be an UUID, but we give it a simple name for the sake of clarity. This Todo had only one update (its creation), made by Alice that generated the revision 1-a . After the initial replication, all the members have a io.cozy.shared document, with this sole revision as history. This history is actually a tree: when a CouchDB conflict occurs, a new branch is created, containing the losing revision, so we can keep track of it and avoid losing any data. Note the document id is in the form / to easily reference the shared document. Here, it is io.cozy.todos/todo1 . In the sequence diagram below, we illustrate the steps occuring when Alice generates updates. We also illustrate how a CouchDB can occur and how it is handled, by making Charlie updating the same document than Alice at the same time. This update leads to a conflict between the revisions 2-a , generated by Alice, and 2-c , generated by Charlie: a winning revision is then elected by CouchDB, 2-a , but 2-c is saved in another branch of the revision tree. Thanks to it, the conflict is propagated to other members that will be able to resolve it through the Todo application (by manually erasing or merging the conflicted revision for instance). Eventually, all members converge to the same state with the same docs and the same revisions histories.", "title": "Revisions syncing"}, {"location": "cozy-stack/sharing-design/#couchdb-conflicts", "text": "A CouchDB conflict is when a document has conflicting revisions, i.e. it has at least two revisions branches in its revision history. Hence, these conflicts are made on the database level. By design , CouchDB can produce conflicts in its replication protocol, as the revision history is replicated and forced among nodes. We detail here how a CouchDB conflict can be made. In the particular case of files and folders, we implemented specific strategies to avoid having to deal with conflicts at the application level: the stack is able to prevent CouchDB conflicts for io.cozy.files documents and enforce reconciliation when possible. We also detail what is done when no reconciliation can be made.", "title": "CouchDB conflicts"}, {"location": "cozy-stack/sharing-design/#id-transformations", "text": "Initially, we were using the CouchDB protocol revision as described above, but we have introduced a transformation of the identifiers for io.cozy.files, and later, we have generalized this transformation for all doctypes. It means that Alice and Bob have the same shared documents, but not with the same identifiers. The identifiers are transformed with a XOR, using a key exchanged when the recipient accepts the sharing. In practice, it is useful when someone is revoked from a sharing, and accepts later the sharing again. It allows to avoid reusing the same identifiers for documents exchanged on the first sharing and on the second sharing, which can create some weird situations. For example, a cipher is shared between Alice and Bob when its revision is 3-aaa. Later, when the sharing is revoked, the document will be deleted on Bob\u2019s instance (the ciphers are deleted on recipients when a sharing is revoked), which creates a revision 4-bbb. If Alice invites Bob again, and Bob accepts, the replication will sent the document from Alice\u2019s instance to Bob\u2019s instance with revision 3-aaa. CouchDB will say OK, but the revision 4-bbb will still be seen as a successor of 3-aaa, and for CouchDB, the document will still be deleted. Using different IDs for the first and second sharing fixes this issue.", "title": "Id transformations"}, {"location": "cozy-stack/sharing-design/#files-and-folders", "text": "", "title": "Files and folders"}, {"location": "cozy-stack/sharing-design/#why-are-they-special", "text": "Files are special for several reasons. First and foremost, they have a binary attached to them that can be quite heavy. The stack also enforces some rules on them (e.g. a file can\u2019t be added to a deleted folder) and has some specific code for the tree nature of files and folders (e.g. a permission on a folder is inherited on all the files and folders inside it, even if they are several levels below). Thus, the workflow explained just before is not compatible with the files. As we need to introduce some code specific to the files, we have also wanted to improve the sharing of files. First, we don\u2019t want to force the recipients to put the shared folder at exactly the same place as the owner. In fact, we think that putting the shared folder in a folder called Shared with me is more friendly. We also think that a file that has been shared in the past but is no longer (the sharing has been revoked) can evolve on both the owner\u2019s cozy and on the recipients\u2019 cozy in different ways, and in such a case, it\u2019s more logical to consider them as different files. These two reasons implies, on a technical level, that the identifiers for files and folders are not the same on the owner and the recipients of a sharing. The replicator will translate the identifiers from one system to another during the replications. Of course, it will also translate the id in the sharing rules, and the dir_id to preserve the relationship between a file and its parent folder. The path attribute will be seen as a cache, and recomputed when a cozy instance receives a folder document from a sharing replication. We will continue to have a replication as close to the CouchDB replication as possible. It means we synchronize a state, and not looking for the history of operations like cozy-desktop does. It is less accurate and can lead more often to conflicts. The cozy instances are expected to be online most of the time and have a short delay for replications: we think that the conflicts will happen only on rares occasions. This make acceptable to take this shortcut. And, in case of conflicts, we will preserve the content of the files (no data loss), even if it means duplicating the files.", "title": "Why are they special?"}, {"location": "cozy-stack/sharing-design/#how-a-sharing-involving-files-works", "text": "When a sharing involves a rule on the io.cozy.files doctype, a folder is created on the recipients cozy where the files will be put. It is created inside the Shared with me folder by default, but can be moved somewhere else after that. The folder won\u2019t be synchronized its-self later, and if the folder is trashed, the sharing is automatically revoked. As it is not a reversible action, a confirmation is asked before doing that. Note: we will forbid the sharing of the root of the virtual file system, of the trash and trashed files/folders, and of course the Shared with me folder. The step 3 described above, aka the replicator, will be more complicated for folders and files. First change, it will work on two phases: 1. what can be synchronized without transfering the binaries first, and 2. the synchronization of files with a binary attached. Second change, the replicator will acquire the Virtual File System lock on the cozy instance where it will write things to ensure the consistency of what it writes. Third change, before inserting a folder or file in the database, the replicator checks that its parent exists, and if it\u2019s not the case, it creates it. Last change, we will avoid CouchDB conflicts for files and folder by using a special conflict resolution process.", "title": "How a sharing involving files works?"}, {"location": "cozy-stack/sharing-design/#sequence-diagram", "text": "", "title": "Sequence diagram"}, {"location": "cozy-stack/sharing-design/#conflict-resolution", "text": "In the case of io.cozy.files documents, we prevent CouchDB conflicts to happen by implementing specific strategies. Here, we detail the conflicts situations where a resolution is possible: When two cozy instances have modified the same file concurrently Same for a folder When two files or folders are renamed concurrently to the same name inside the same directory When a file or folder is created or updated on cozy instance while the parent directory is trashed concurrently on another cozy instance. For 1. and 2., we will reconciliate the changes except for a file with two versions having a distinct binary (we rely on size and checksum to detect that). In such a case, we create a copy of the file with one version, while keeping the other version in the original file (the higher revision wins). For 3., we say that the owner instance wins: the file with the name in conflict on the owner instance will keep its name, and the other file with the same name will be renamed. This rule helps to minimize the number of exchanges between the cozy instances, which is a factor of stability to avoid more conflicts. For 4., we restore the trashed parent, or recreate it if it the trash was emptied.", "title": "Conflict resolution"}, {"location": "cozy-stack/sharing-design/#conflict-with-no-reconciliation", "text": "When a file is modified concurrently on two cozy instances, and at least one change involve the content, we can\u2019t reconciliate the modifications. To know which version of the file is the \u201cwinner\u201d and will keep the same identifier, and which version is the \u201closer\u201d and will have a new identifier, we compare the revisions and the higher wins. This conflict is particulary tricky to resolve, with a lot of subcases. In particular, we try to converge to the same revisions on all the instances for the \u201cwinner\u201d file (and for the \u201closer\u201d too). We have 3 sets of attributes for files: size and md5sum (they change when the content has changed) name and dir_id (they change when the file is moved or renamed) created_at , updated_at , tags , referenced_by , etc. For the first two sets, the operation on the Virtual File System will needs to reach the storage (Swift), not just CouchDB. For the third set, it\u2019s easy: we can do the change at the same time as another change, because these attributes are only used in CouchDB. But we can\u2019t do a change on the first two sets at the same time: the Virtual File System can\u2019t update the content and move/rename a file in the same operation. If we needs to do both, it will generate 2 revisions in CouchDB for the file. Note: you can see that using CouchDB-like replication protocol means that we have some replications that can look useless, just some echo to a writing. In fact, it is used to acknowledge the writing and is helpful for conflict resolutions. It may be conter-intuitive, but removing them will harm the stability of the system, even if they do nothing most of the time.", "title": "Conflict with no reconciliation"}, {"location": "cozy-stack/sharing-design/#example-1", "text": "Here, Alice uploads a file on her Cozy. It creates two revisions for this file (it\u2019s what the Virtual File System does). Then, she shares the directory with this file to her friend Bob. When Bob accepts the sharing, the file is sent to his Cozy, with the same revision (2-2aa). Later, Bob renames the file. It creates a new revision (3-3aa). The change is replicated to Alice\u2019s Cozy. And we have a replication from Alice to Bob to ensure that every thing is fine. Even later, Alice and Bob both renames the file at the same time. It creates a conflict. We have a first replication (from Alice to Bob), but nothing happens on B because the local revision (4-4bb) is greater than the candidate revision (4-4aa) and the content is the same. Just after that, we have a revision on the opposite direction (from Bob to Alice). The candidate revision wins (4-4bb), but for files, we don\u2019t use CouchDB conflict, thus it\u2019s not possible to write a new revision at the same generation (4). The only option is to create a new revision (5-5bb). This revision is then sent to Bob: Bob\u2019s Cozy accepts the new revision even if it has no effect on the file (it was already the good name), just to resolve the conflict.", "title": "Example 1"}, {"location": "cozy-stack/sharing-design/#example-2", "text": "Like in the last example, Alice uploads a file and share a directory to Bob with this file, Bob acccepts. But then, several actions are made on the file in a short lapse of time and it generates a difficult conflict: Alice renames the file, and then uploads a new version with cozy-desktop Bob moves the file to a sub-directory. So, when the replication comes, we have two versions of the file with different name, parent directory, and content. The winner is the higher revision (4-4aa). The resolution takes 4 steps: A copy of the file is created from the revision 3-3bb, with the new identifier id2 = XorID(id, 3-3bb). The new content is written on Bob\u2019s Cozy: we can\u2019t use the revisions 3-3aa (same generation as 3-3bb) and 4-4aa (it will mean the conflict is fixed, but it\u2019s not the case, the filenames are still different), so a new revision is used (4-4cc). The file is moved and renamed on Bob\u2019s Cozy, with a next revision (5-5bb). The two files are sent to Alice\u2019s Cozy: 5-5bb is accepted just to resolve the conflict, and id2 is uploaded as a new file.", "title": "Example 2"}, {"location": "cozy-stack/sharing-design/#special-case-out-and-in-again", "text": "Let\u2019s look at a special case. Alice shares a folder with Bob and Charlie. It contains a directory, with a few files inside it. This directory has been synchronized, and Bob decides to move it somewhere else on its cozy instance that is not inside the shared folder, let\u2019s say at the root. The sharing synchronization will move the directory to the trash for Alice and Charlie. Bob can continue to work on the files in this directory. If Charlie restores the directory from the trash, it will be put again in the sharing. And we can see that we have an issue: on Bob instance, we will have two copies on the files, at two different locations, but technically, they should have the same identifiers. It is not possible. To avoid that, we have to change the identifier, or more precisely, delete a file and recreate it with a new identifier. It means losing historical versions and some other things like sharing by links. It is an operation that takes a lot of resources. So, we need to be careful in how we do that. And, like usual for the sharing, we need to take care of the stability and convergence of the replication algorithm. With these constraints, the approache we have chosen is to put a copy of a file that was moved out of the sharing in the trash when this operation is replicated. For the member of the sharing that has made the operation, the file will be the same (no need to change how the VFS work), and it is only later, when this change is replicated to the other members that we will put a copy of the file in the trash and delete the file (this is managed by the sharing layer). Thus, the other members of the sharing will have a copy of the file, but not the original file (sharing by links won\u2019t work on the copy for example), and the old versions of the file will be lost. We think it is an acceptable tradeoff between complexity, reliability, and matching the user expectations. Still, it has an important limitation. If Alice and Bob moves a file from the shared directory to somewhere else at the same time, and later, one of them is moving again the file inside the shared directory, we will be in a bad situation, where the replication algorithm can\u2019t synchronize the file. For the moment, we prefer to advance with this limitation, but we will have to take care of it later.", "title": "Special case: out and in again"}, {"location": "cozy-stack/sharing-design/#schema", "text": "", "title": "Schema"}, {"location": "cozy-stack/sharing-design/#description-of-a-sharing", "text": "An identifier (the same for all members of the sharing) A list of members . The first one is the owner. For each member, we have: status , a status that can be: owner for the member that has created the sharing mail-not-sent for a member that has been added, but its invitation has not yet been sent (often, this status is used only for a few seconds) pending for a member with an invitation sent, but who has not clicked on the link seen for a member that has clicked on the invitation link, but has not setup the Cozy to Cozy replication for the sharing ready for a member where the Cozy to Cozy replication has been set up revoked for a member who is on longer in the sharing name , a contact name public_name , a public name email , the email address instance , the URL of the Cozy read_only , a flag to tell if the contact is restricted to read-only mode only_in_groups , a flag that will be false if the member has been added as a single contact groups , a list of indexes of the groups A list of groups , with for each one: id , the identifier of the io.cozy.contacts.groups name , the name of the group addedBy , the index of the member that has added the group read_only , a flag to tell if the group is restricted to read-only mode revoked , a flag set to true when the group is revoked from the sharing Some credentials to authorize the transfer of data between the owner and the recipients A description (one sentence that will help people understand what is shared and why) A flag active that says if the sharing is currently active for at least one member A flag owner , true for the document on the cozy of the sharer, and false on the other cozy instance A flag open_sharing : true if any member of the sharing except the read-only ones can add a new recipient false if only the owner can add a new recipient Some technical data ( created_at , updated_at , app_slug , preview_path , triggers , credentials ) A flag initial_sync present only when the initial replication is still running A number of files to synchronize for the initial sync, initial_number_of_files_to_sync (if there are no files to sync or the initial replication has finished, the field won\u2019t be here) A shortcut_id with the identifier of the shortcut file (when the recipient doesn\u2019t want to synchronize the documents on their Cozy instance) A list of sharing rules , each rule being composed of: a title , that will be displayed to the recipients before they accept the sharing a doctype (and a mime if the doctype is io.cozy.files ) a selector (by default, it\u2019s the id ) and values (one identifier, a list of identifiers, files and folders inside a folder, files that are referenced by the same document, documents bound to a previous sharing rule) local : by default false , but it can be true for documents that are useful for the preview page but doesn\u2019t need to be send to the recipients (e.g. a setting document of the application) add : a behavior when a new document matches this rule (the document is created, or it was a document that didn\u2019t match the rule and is modified and the new version matches the rule): none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member (except the read-only) are propagated to the other members update : a behavior when a document matched by this rule is modified. Can be: none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member (except the read-only) are propagated to the other members remove : a behavior when a document no longer matches this rule (the document is deleted, or it was a document that matched the rule, and is modified and the new version doesn\u2019t match the rule): none : the updates are never propagated (the default) push : the updates made on the owner are sent to the recipients sync : the updates on any member (except the read-only) are propagated to the other members revoke : the sharing is revoked.", "title": "Description of a sharing"}, {"location": "cozy-stack/sharing-design/#example-i-want-to-share-a-folder-in-readwrite-mode", "text": "rule 1 title: folder doctype: io.cozy.files values: \"ca527016-0d83-11e8-a580-3b965c80c7f7\" add: sync update: sync remove: sync", "title": "Example: I want to share a folder in read/write mode"}, {"location": "cozy-stack/sharing-design/#example-i-want-to-share-a-playlist-where-im-the-only-one-that-can-add-and-remove-items", "text": "rule 1 title: playlist doctype: io.cozy.music.playlists values: \"99445b14-0d84-11e8-ae72-4b96fcbf0552\" update: none remove: revoke rule 2 title: items doctype: io.cozy.files selector: referenced_by values: \"io.cozy.files/ca527016-0d83-11e8-a580-3b965c80c7f7\" add: push update: none remove: push", "title": "Example: I want to share a playlist where I\u2019m the only one that can add and remove items"}, {"location": "cozy-stack/sharing-design/#iocozyshared", "text": "This doctype is an internal one for the stack. It is used to track what documents are shared, and to replicate changes from one Cozy to the others. _id : its identifier is the doctype and id of the referenced objet, separated by a / (e.g. io.cozy.contacts/c1f5dae4-0d87-11e8-b91b-1f41c005768b ) _rev : the CouchDB default revision for this document (not very meaningful, it\u2019s here to avoid concurrency issues) revisions : a tree with the last known _rev s of the referenced object infos , a map of sharing ids \u2192 {rule, removed, binary} rule says which rule from the sharing must be applied for this document removed will be true for a deleted document, a trashed file, or if the document does no longer match the sharing rule binary is a boolean flag that is true only for files (and not even folders) with removed: false dissociated is a boolean flag that can be true only for files and folders when they have been removed from the sharing but can be put again (only on the Cozy instance of the owner)", "title": "io.cozy.shared"}, {"location": "cozy-stack/sharing/", "text": "Table of contents Sharing \u00b6 The owner of a cozy instance can share access to her documents to other users. Sharing by links \u00b6 A client-side application can propose sharing by links: The application must have a public route in its manifest. See Apps documentation for how to do that. The application can create a set of permissions for the shared documents, with codes. Another code called shortcode is also generated and associated with the code. This shortcode is much smaller (but secure), which is easier to be shared. See permissions documentation for the details. The application can then create a shareable link (e.g. https://calendar.cozy.example.net/public?sharecode=eiJ3iepoaihohz1Y ) by putting together the app sub-domain, the public route path, and a code for the permissions set. The app can then send this link by mail, via the jobs system , or just give it to the user, so he can transmit it to her friends via chat or other ways. When someone opens the shared link, the stack will load the public route, find the corresponding index.html file, and replace {{.Token}} inside it by a token with the same set of permissions that sharecode offers. This token can then be used as a Bearer token in the Authorization header for requests to the stack (or via cozy-client-js). NB: The shortcode can also be used as the Bearer . In this case, the corresponding sharecode will be matched on server-side If necessary, the application can list the permissions for the token by calling /permissions/self with this token. Cozy to cozy sharing \u00b6 The owner of a cozy instance can send and synchronize documents to others cozy users. Intents \u00b6 When a sharing is authorized, the user is redirected to their cozy on the application that was used for the sharing (when possible). It\u2019s possible to use a specific route to do so, via the intents. The application must declare an intent in its manifest for the action SHARING . The doctype of the intent must be the same as the doctype of the first rule of the sharing. In the redirect URL, the query string will have a sharing parameter with the sharing ID (but no intent parameter). Routes \u00b6 POST /sharings/ \u00b6 Create a new sharing. The sharing rules and recipients must be specified. The description , preview_path , and open_sharing fields are optional. The app_slug field is optional and is the slug of the web app by default. See the doc on io.cozy.sharings for in-depth explanation of all attributes . To create a sharing, no permissions on io.cozy.sharings are needed: an application can create a sharing on the documents for whose it has a permission. Request \u00b6 POST /sharings/ HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"relationships\" : { \"recipients\" : { \"data\" : [ { \"id\" : \"2a31ce0128b5f89e40fd90da3f014087\" , \"type\" : \"io.cozy.contacts\" }, { \"id\" : \"51bbc980acb0013cb5f618c04daba326\" , \"type\" : \"io.cozy.contacts.groups\" } ] } } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"mail-not-sent\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" }, { \"status\" : \"mail-not-sent\" , \"name\" : \"Gaby\" , \"email\" : \"gaby@example.net\" , \"only_in_groups\" : true , \"groups\" : [ 0 ] } ], \"groups\" : [ { \"id\" : \"51bbc980acb0013cb5f618c04daba326\" , \"name\" : \"G. people\" , \"addedBy\" : 0 } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } } GET /sharings/:sharing-id/discovery \u00b6 If no preview_path is set, it\u2019s an URL to this route that will be sent to the users to notify them that someone wants to share something with them. On this page, they can fill the URL of their Cozy (if the user has already filled its Cozy URL in a previous sharing, the form will be pre-filled and the user will just have to click OK). Query-String \u00b6 Parameter Description state a code that identify the recipient Example \u00b6 GET /sharings/ce8835a061d0ef68947afe69a0046722/discovery?state=eiJ3iepoaihohz1Y HTTP / 1.1 Host : alice.example.net POST /sharings/:sharing-id/discovery \u00b6 Give to the cozy of the sharer the URL of the Cozy of one recipient. The sharer will register its-self as an OAuth client on the recipient cozy, and then will ask the recipient to accept the permissions on its instance. This route exists in two versions, the version is selected by the HTTP header Accept Classical ( x-www-form-urlencoded ) \u00b6 Parameter Description state a code that identify the recipient url the URL of the Cozy for the recipient Example \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/discovery HTTP / 1.1 Host : alice.example.org Content-Type : application/x-www-form-urlencoded Accept : text/html state=eiJ3iepoaihohz1Y&url=https://bob.example.net/ HTTP / 1.1 302 Moved Temporarily Location : https://bob.example.net/auth/sharing?... JSON \u00b6 This version can be more convenient for applications that implement the preview page. To do that, an application must give a preview_path when creating the sharing. This path must be a public route of this application. The recipients will receive a link to the application subdomain, on this page, and with a sharecode in the query string (like for a share by link). To know the sharing-id , it\u2019s possible to ask GET /permissions/self , with the sharecode in the Authorization header (it\u2019s a JWT token). In the response, the source_id field will be io.cozy.sharings/ . Parameters \u00b6 Parameter Description sharecode a code that identify the recipient url the URL of the Cozy for the recipient Example \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/discovery HTTP / 1.1 Host : alice.example.org Content-Type : application/x-www-form-urlencoded Accept : application/json sharecode=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhcHAiLCJpYXQiOjE1MjAzNDM4NTc&url=https://bob.example.net/ HTTP / 1.1 200 OK Content-Type : application/json { \"redirect\" : \"https://bob.example.net/auth/sharing?...\" } POST /sharings/:sharing-id/preview-url \u00b6 This internal route can be used by the stack to get the URL where a member can preview the sharing. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/discovery-url HTTP / 1.1 Host : alice.example.net Content-Type : application/json { \"state\" : \"eiJ3iepoaihohz1Y\" } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"url\" : \"https://drive.alice.example.net/preview?sharecode=...\" } GET /sharings/:sharing-id \u00b6 Get the information about a sharing. This includes the content of the rules, the members, as well as the already shared documents for this sharing. For a member, we can have the following fields: a contact name ( name ), that is the name of this user as it appears in its contact document (if there is one such document) a public name ( public_name ), that is the name this user has put on his cozy as a public name (it is used for sending emails for example) an email addresse ( email ) an instance URL ( instance ) and a status ( status ). Notes: the first member is always the sharer to display the list of members to a user, the name should be use if available, and if it is not the case, you can use the public_name or the email on a recipient, the only member with an instance is the local user. Request \u00b6 GET /sharings/ce8835a061d0ef68947afe69a0046722 HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"initial_number_of_files_to_sync\" : 42 , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"612acf1c-1d72-11e8-b043-ef239d3074dd\" , \"type\" : \"io.cozy.files\" }, { \"id\" : \"a34528d2-13fb-9482-8d20-bf1972531225\" , \"type\" : \"io.cozy.files\" } ] } }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } } GET /sharings/news \u00b6 It returns the number of shortcuts to a sharing that have not been seen. Request \u00b6 GET /sharings/news HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"count\" : 5 } } GET /sharings/doctype/:doctype \u00b6 Get information about all the sharings that have a rule for the given doctype. This includes the content of the rules, the members, as well as the already shared documents for this sharing. Request \u00b6 GET /sharings/doctype/io.cozy.files HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"612acf1c-1d72-11e8-b043-ef239d3074dd\" , \"type\" : \"io.cozy.files\" }, { \"id\" : \"a34528d2-13fb-9482-8d20-bf1972531225\" , \"type\" : \"io.cozy.files\" } ] } } }, { \"type\" : \"io.cozy.sharings\" , \"id\" : \"b4e58d039c03d01742085de5e505284e\" , \"attributes\" : { \"description\" : \"another sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-02-04T12:35:08Z\" , \"updated_at\" : \"2018-02-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" } ], \"rules\" : [ { \"title\" : \"Singapore\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"e18e30e2-8eda-1bde-afce-edafc6b1a91b\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"meta\" : { \"rev\" : \"1-7ac5f1252a0c513186a5d35b1a6fd350\" }, \"links\" : { \"self\" : \"/sharings/b4e58d039c03d01742085de5e505284e\" }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"dcc52bee-1277-a6b3-b36f-369ffd81a4ee\" , \"type\" : \"io.cozy.files\" } ] } } } ], \"meta\" : { \"count\" : 3 } } PUT /sharings/:sharing-id \u00b6 The sharer\u2019s cozy sends a request to this route on the recipient\u2019s cozy to create a sharing request, with information about the sharing. This request can be used for two scenarios: This request will be displayed to the recipient just before its final acceptation of the sharing, to be sure they know what will be shared. This request will be used to create a shortcut (in that case, a query-string parameter shortcut=true&url=... will be added). Request \u00b6 PUT /sharings/ce8835a061d0ef68947afe69a0046722 HTTP / 1.1 Host : bob.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"mail-not-sent\" , \"email\" : \"bob@example.net\" , \"instance\" : \"bob.example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-f579a69a9fa5dd720010a1dbb82320be\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"mail-not-sent\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" , \"instance\" : \"bob.example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } } POST /sharings/:sharing-id/answer \u00b6 This route is used by the Cozy of a recipient to exchange credentials with the Cozy of the sharer, after the recipient has accepted a sharing. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/answer HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"public_name\" : \"Bob\" , \"state\" : \"eiJ3iepoaihohz1Y\" , \"client\" : { ... }, \"access_token\" : { ... } } } } When the sharing has a rule for bitwarden organization, the attributes also have a bitwarden object with user_id and public_key , to make it possible to share documents end to end encrypted. Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"client\" : { ... }, \"access_token\" : { ... } } } } POST /sharings/:sharing-id/public-key \u00b6 This route can be used by a sharing member to send their new public key after they have chosen their password for the first time (delegated authentication). Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/public-key HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json Authorization : Bearer ... { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"bitwarden\" : { \"user_id\" : \"0dc76ad9b1cf3a979b916b3155001830\" , \"public_key\" : \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wboB9QutvRKGswphAre6xi4boYxSw4IjXqXDTV297Cq/MB2cBklj+sMmRQNTkU266HFSTGp3jDVcegAsHMpVVlTKZnWW+gSP2+vSyGs9NUvG8JfLday1iuOntHJQkfYiZ7+BfBYFtx6iWRnbnegickyoS7PWibLP5lmEzZnFtrGcRT8urSfN61qlOVD1u+eqtif5tabdU6eyNWUMLCQYgtaGb1nNht/xDgbpBc3b2XbEF0tBJRFR5571EH1h//Ae7IT+pYuBZB9BoPAHj4fhQm3++oNjemUJbaVi0dM4KNfQ89z1lBBCh5lxAGPlpOjapN0qGPgSov8B9U+qXlmzQIDAQAB\" } } } } Response \u00b6 HTTP / 1.1 204 No Content POST /sharings/:sharing-id/recipients \u00b6 This route allows the sharer to add new recipients (and groups of recipients) to a sharing. It can also be used by a recipient when the sharing has open_sharing set to true if the recipient doesn\u2019t have the read_only flag. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"relationships\" : { \"recipients\" : { \"data\" : [ { \"id\" : \"ce7b1dfbd460039159f228298a29b2aa\" , \"type\" : \"io.cozy.contacts\" } ] }, \"read_only_recipients\" : { \"data\" : [ { \"id\" : \"e15384a1223ae2501cc1c4fa94008ea0\" , \"type\" : \"io.cozy.contacts\" } ] } } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"public_name\" : \"Bob\" , \"email\" : \"bob@example.net\" }, { \"status\" : \"pending\" , \"name\" : \"Charlie\" , \"email\" : \"charlie@example.net\" }, { \"status\" : \"pending\" , \"name\" : \"Dave\" , \"email\" : \"dave@example.net\" , \"read_only\" : true } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"612acf1c-1d72-11e8-b043-ef239d3074dd\" , \"type\" : \"io.cozy.files\" }, { \"id\" : \"a34528d2-13fb-9482-8d20-bf1972531225\" , \"type\" : \"io.cozy.files\" } ] } }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } } POST /sharings/:sharing-id/recipients/delegated \u00b6 This is an internal route for the stack. It is called by the recipient cozy on the owner cozy to add recipients and groups to the sharing ( open_sharing: true only). Data for direct recipients should contain an email address but if it is not known, an instance URL can also be provided. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/delegated HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"relationships\" : { \"recipients\" : { \"data\" : [ { \"email\" : \"dave@example.net\" } ] }, \"groups\" : { \"data\" : [ { \"id\" : \"b57cd790b2f4013c3ced18c04daba326\" , \"name\" : \"Dance\" , \"addedBy\" : 1 } ] } } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"dave@example.net\" : \"uS6wN7fTYaLZ-GdC_P6UWA\" } POST /sharings/:sharing-id/members/:index/invitation \u00b6 This is an internal route for the stack. It is called by the recipient cozy on the owner cozy to send an invitation. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/members/4/invitation HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.members\" , \"attributes\" : { \"email\" : \"diana@example.net\" } } } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"diana@example.net\" : \"uS6wN7fTYaLZ-GdC_P6UWA\" } DELETE /sharings/:sharing-id/groups/:group-index/:member-index \u00b6 This is an internal route for the stack. It is called by the recipient cozy on the owner cozy to remove a member of a sharing from a group. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/groups/0/1 HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 204 No Content PUT /sharings/:sharing-id/recipients \u00b6 This internal route is used to update the list of members (their states, emails and names) and the list of groups on the recipients cozy. The token used for this route can be the access token for a sharing where synchronization is active, or the sharecode for a member who has only a shortcut to the sharing on their Cozy instance. Request \u00b6 PUT /sharings/ce8835a061d0ef68947afe69a0046722/recipients HTTP / 1.1 Host : bob.example.net Content-Type : application/vnd.api+json { \"data\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"public_name\" : \"Bob\" , \"email\" : \"bob@example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Charlie\" , \"public_name\" : \"Charlie\" , \"email\" : \"charlie@example.net\" }, { \"status\" : \"pending\" , \"name\" : \"Dave\" , \"email\" : \"dave@example.net\" , \"read_only\" : true } ], \"included\" : [ { \"id\" : \"51bbc980acb0013cb5f618c04daba326\" , \"name\" : \"G. people\" , \"addedBy\" : 0 } ] } Response \u00b6 HTTP / 1.1 204 No Content GET /sharings/:sharing-id/recipients/:index/avatar \u00b6 This route can be used to get an image that shows the avatar of a member of this sharing. No permission is required to use this route, you just need to know the sharing-id to use it. If no image has been chosen, a fallback will be used, depending of the fallback parameter in the query-string: initials : a generated image with the initials of the owner\u2019s public name. This is the default behavior. 404 : just a 404 - Not found error. If the initials fallback is used and the member has not yet seen the sharing, the background of the image will be grey. Note : 0 for the index means the sharer. Request \u00b6 GET /sharings/ce8835a061d0ef68947afe69a0046722/recipients/2/avatar HTTP / 1.1 Host : bob.example.net Accept : image/* POST /sharings/:sharing-id/recipients/:index/readonly \u00b6 This route is used to add the read-only flag on a recipient of a sharing. Note : 0 is not accepted for index , as it is the sharer him-self. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/3/readonly HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 204 No Content POST /sharings/:sharing-id/recipients/self/readonly \u00b6 This is an internal route for the stack. It\u2019s used to inform the recipient\u2019s cozy that it is no longer in read-write mode. It also gives it an access token with a short validity (1 hour) to let it try to synchronize its last changes before going to read-only mode. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self/readonly HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"4dadbcae3f2d7a982e1b308eea000751\" , \"attributes\" : { \"client\" : { ... }, \"access_token\" : { ... } } } } Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/recipients/:index/readonly \u00b6 This route is used to remove the read-only flag on a recipient of a sharing. Note : 0 is not accepted for index , as it is the sharer him-self. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/3/readonly HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/recipients/self/readonly \u00b6 This is an internal route for the stack. It\u2019s used to inform the recipient\u2019s cozy that it is no longer in read-only mode, and to give it the credentials for sending its updates. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self/readonly HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"4dadbcae3f2d7a982e1b308eea000751\" , \"attributes\" : { \"client\" : { ... }, \"access_token\" : { ... } } } } Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/recipients \u00b6 This route is used by an application on the owner\u2019s cozy to revoke the sharing for all the members. After that, the sharing active flag will be false, the credentials for all members will be revoked, the members that have accepted the sharing will have their cozy informed that the sharing has been revoked, and pending members can no longer accept this sharing. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/recipients/:index \u00b6 This route can be only be called on the cozy instance of the sharer to revoke only one recipient of the sharing. The parameter is the index of this recipient in the members array of the sharing. The status for this member will be set to revoked , its cozy will be informed of the revokation, and the credentials for this cozy will be deleted. Note : 0 is not accepted for index , as it is the sharer him-self. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/1 HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/groups/:index \u00b6 This route can be only be called on the cozy instance of the sharer to revoke a group of the sharing. The parameter is the index of this recipient in the groups array of the sharing. The removed property for this group will be set to true , and it will revoke the members of this group unless they are still part of the sharing via another group or as direct recipients. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/groups/0 HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/recipients/self \u00b6 This route can be used by an application in the cozy of a recipient to remove it from the sharing. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self HTTP / 1.1 Host : bob.example.net Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id \u00b6 This is an internal route used by the cozy of the sharing\u2019s owner to inform a recipient\u2019s cozy that it was revoked. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722 HTTP / 1.1 Host : bob.example.net Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/answer \u00b6 This is an internal route used by a recipient\u2019s cozy to inform the owner\u2019s cozy that this recipient no longer wants to be part of the sharing. Request \u00b6 DELETE /sharings/ce8835a061d0ef68947afe69a0046722/answer HTTP / 1.1 Host : alice.example.net Response \u00b6 HTTP / 1.1 204 No Content POST /sharings/:sharing-id/recipients/self/moved \u00b6 This route can be used to inform that a Cozy has been moved to a new address. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self/moved HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.moved\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"new_instance\" : \"https://alice.newcozy.example\" , \"access_token\" : \"xxx\" , \"refresh_token\" : \"xxx\" } } } Response \u00b6 HTTP / 1.1 204 No Content POST /sharings/:sharing-id/_revs_diff \u00b6 This endpoint is used by the sharing replicator of the stack to know which documents must be sent to the other cozy. It is inspired by http://docs.couchdb.org/en/stable/api/database/misc.html#db-revs-diff. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/_revs_diff HTTP / 1.1 Host : bob.example.net Accept : application/json Content-Type : application/json Authorization : Bearer ... { \"io.cozy.files/29631902-2cec-11e8-860d-435b24c2cc58\" : [ \"2-4a7e4ae49c4366eaed8edeaea8f784ad\" ], \"io.cozy.files/44f5752a-2cec-11e8-b227-abfc3cfd4b6e\" : [ \"4-2ee767305024673cfb3f5af037cd2729\" , \"4-efc54218773c6acd910e2e97fea2a608\" ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"io.cozy.files/44f5752a-2cec-11e8-b227-abfc3cfd4b6e\" : { \"missing\" : [ \"4-2ee767305024673cfb3f5af037cd2729\" ], \"possible_ancestors\" : [ \"3-753875d51501a6b1883a9d62b4d33f91\" ] } } POST /sharings/:sharing-id/_bulk_docs \u00b6 This endpoint is used by the sharing replicator of the stack to send documents in a bulk to the other cozy. It is inspired by http://docs.couchdb.org/en/stable/api/database/bulk-api.html#db-bulk-docs. Note : we force new_edits to false . Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/_bulk_docs HTTP / 1.1 Host : bob.example.net Accept : application/json Content-Type : application/json Authorization : Bearer ... { \"io.cozy.files\" : [ { \"_id\" : \"44f5752a-2cec-11e8-b227-abfc3cfd4b6e\" , \"_rev\" : \"4-2ee767305024673cfb3f5af037cd2729\" , \"_revisions\" : { \"start\" : 4 , \"ids\" : [ \"2ee767305024673cfb3f5af037cd2729\" , \"753875d51501a6b1883a9d62b4d33f91\" ] } } ] } Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json [] GET /sharings/:sharing-id/io.cozy.files/:file-id \u00b6 This is an internal endpoint used by a stack to get information about a folder. It is used when a cozy sent to another cozy a file or folder inside a folder that was trashed (and trash was emptied): the recipient does no longer have information about the parent directory. To resolve the conflict, it recreates the missing parent directory by asking the other cozy informations about it. Request \u00b6 GET /sharings/ce8835a061d0ef68947afe69a0046722/io.cozy.files/6d245d072be5522bd3a6f273dd000c65 HTTP / 1.1 Host : alice.example.net Accept : application/json Authorization : Bearer ... Response \u00b6 HTTP / 1.1 200 OK Content-Type : application/json { \"_id\" : \"6d245d072be5522bd3a6f273dd000c65\" , \"_rev\" : \"1-de4ec176ffa9ddafe8bdcc739dc60fed\" , \"type\" : \"directory\" , \"name\" : \"phone\" , \"dir_id\" : \"6d245d072be5522bd3a6f273dd007396\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" ] } PUT /sharings/:sharing-id/io.cozy.files/:file-id/metadata \u00b6 This is an internal endpoint used by a stack to send the new metadata about a file that has changed. Request \u00b6 PUT /sharings/ce8835a061d0ef68947afe69a0046722/io.cozy.files/0c1116b028c6ae6f5cdafb949c088265/metadata HTTP / 1.1 Host : bob.example.net Accept : application/json Content-Type : application/json Authorization : Bearer ... { \"_id\" : \"4b24ab130b2538b7b444fc65430198ad\" , \"_rev\" : \"1-356bf77c03baa1da851a2be1f06aba81\" , \"_revisions\" : { \"start\" : 1 , \"ids\" : [ \"356bf77c03baa1da851a2be1f06aba81\" ] }, \"type\" : \"file\" , \"name\" : \"cloudy.jpg\" , \"dir_id\" : \"4b24ab130b2538b7b444fc65430188cd\" , \"created_at\" : \"2018-01-03T16:10:36.885807013+01:00\" , \"updated_at\" : \"2018-01-03T16:10:36.885807013+01:00\" , \"size\" : \"84980\" , \"md5sum\" : \"SuRJOiD/QPwDUpKpQujcVA==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2018-01-03T16:10:36.89118949+01:00\" , \"extractor_version\" : 2 , \"height\" : 1200 , \"width\" : 1600 } } Response \u00b6 If only the metadata has changed (not the content), the response will be a 204: HTTP / 1.1 204 No Content Else, the content will need to be uploaded: HTTP/1.1 200 OK Content-Type: application/json { \"key\" : \"dcd478c6-46cf-11e8-9c3f-535468cbce7b\" } PUT /sharings/:sharing-id/io.cozy.files/:key \u00b6 Upload the content of a file (new file or its content has changed since the last synchronization). Request \u00b6 PUT /sharings/ce8835a061d0ef68947afe69a0046722/io.cozy.files/dcd478c6-46cf-11e8-9c3f-535468cbce7b HTTP / 1.1 Host : bob.example.net Content-Type : image/jpeg Authorization : Bearer ... Response \u00b6 HTTP / 1.1 204 No Content POST /sharings/:sharing-id/reupload \u00b6 This is an internal route for the stack. It is called when the disk quota of an instance is increased to ask for the others instances on this sharing to try to reupload files without waiting for the normal retry period. Request \u00b6 POST /sharings/ce8835a061d0ef68947afe69a0046722/reupload HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Response \u00b6 HTTP / 1.1 204 No Content DELETE /sharings/:sharing-id/initial \u00b6 This internal route is used by the sharer to inform a recipient\u2019s cozy that the initial sync is finished. DELETE /sharings/ce8835a061d0ef68947afe69a0046722/initial HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Response \u00b6 HTTP / 1.1 204 No Content Real-time via websockets \u00b6 You can subscribe to the realtime API for the normal doctypes, but also for a special io.cozy.sharings.initial_sync doctype. For this doctype, you can give the id of a sharing and you will be notified when a file will be received during the initial synchronisation ( UPDATED ), and when the sync will be done ( DELETED ). Example \u00b6 client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.sharings.initial_sync\", \"id\": \"ce8835a061d0ef68947afe69a0046722\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"ce8835a061d0ef68947afe69a0046722\", \"type\": \"io.cozy.sharings.initial_sync\", \"doc\": {\"count\": 12}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"ce8835a061d0ef68947afe69a0046722\", \"type\": \"io.cozy.sharings.initial_sync\", \"doc\": {\"count\": 13}}} server > {\"event\": \"DELETED\", \"payload\": {\"id\": \"ce8835a061d0ef68947afe69a0046722\", \"type\": \"io.cozy.sharings.initial_sync\"}}", "title": "/sharings - Sharing"}, {"location": "cozy-stack/sharing/#sharing", "text": "The owner of a cozy instance can share access to her documents to other users.", "title": "Sharing"}, {"location": "cozy-stack/sharing/#sharing-by-links", "text": "A client-side application can propose sharing by links: The application must have a public route in its manifest. See Apps documentation for how to do that. The application can create a set of permissions for the shared documents, with codes. Another code called shortcode is also generated and associated with the code. This shortcode is much smaller (but secure), which is easier to be shared. See permissions documentation for the details. The application can then create a shareable link (e.g. https://calendar.cozy.example.net/public?sharecode=eiJ3iepoaihohz1Y ) by putting together the app sub-domain, the public route path, and a code for the permissions set. The app can then send this link by mail, via the jobs system , or just give it to the user, so he can transmit it to her friends via chat or other ways. When someone opens the shared link, the stack will load the public route, find the corresponding index.html file, and replace {{.Token}} inside it by a token with the same set of permissions that sharecode offers. This token can then be used as a Bearer token in the Authorization header for requests to the stack (or via cozy-client-js). NB: The shortcode can also be used as the Bearer . In this case, the corresponding sharecode will be matched on server-side If necessary, the application can list the permissions for the token by calling /permissions/self with this token.", "title": "Sharing by links"}, {"location": "cozy-stack/sharing/#cozy-to-cozy-sharing", "text": "The owner of a cozy instance can send and synchronize documents to others cozy users.", "title": "Cozy to cozy sharing"}, {"location": "cozy-stack/sharing/#intents", "text": "When a sharing is authorized, the user is redirected to their cozy on the application that was used for the sharing (when possible). It\u2019s possible to use a specific route to do so, via the intents. The application must declare an intent in its manifest for the action SHARING . The doctype of the intent must be the same as the doctype of the first rule of the sharing. In the redirect URL, the query string will have a sharing parameter with the sharing ID (but no intent parameter).", "title": "Intents"}, {"location": "cozy-stack/sharing/#routes", "text": "", "title": "Routes"}, {"location": "cozy-stack/sharing/#post-sharings", "text": "Create a new sharing. The sharing rules and recipients must be specified. The description , preview_path , and open_sharing fields are optional. The app_slug field is optional and is the slug of the web app by default. See the doc on io.cozy.sharings for in-depth explanation of all attributes . To create a sharing, no permissions on io.cozy.sharings are needed: an application can create a sharing on the documents for whose it has a permission.", "title": "POST /sharings/"}, {"location": "cozy-stack/sharing/#request", "text": "POST /sharings/ HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"relationships\" : { \"recipients\" : { \"data\" : [ { \"id\" : \"2a31ce0128b5f89e40fd90da3f014087\" , \"type\" : \"io.cozy.contacts\" }, { \"id\" : \"51bbc980acb0013cb5f618c04daba326\" , \"type\" : \"io.cozy.contacts.groups\" } ] } } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"mail-not-sent\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" }, { \"status\" : \"mail-not-sent\" , \"name\" : \"Gaby\" , \"email\" : \"gaby@example.net\" , \"only_in_groups\" : true , \"groups\" : [ 0 ] } ], \"groups\" : [ { \"id\" : \"51bbc980acb0013cb5f618c04daba326\" , \"name\" : \"G. people\" , \"addedBy\" : 0 } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } }", "title": "Response"}, {"location": "cozy-stack/sharing/#get-sharingssharing-iddiscovery", "text": "If no preview_path is set, it\u2019s an URL to this route that will be sent to the users to notify them that someone wants to share something with them. On this page, they can fill the URL of their Cozy (if the user has already filled its Cozy URL in a previous sharing, the form will be pre-filled and the user will just have to click OK).", "title": "GET /sharings/:sharing-id/discovery"}, {"location": "cozy-stack/sharing/#query-string", "text": "Parameter Description state a code that identify the recipient", "title": "Query-String"}, {"location": "cozy-stack/sharing/#example", "text": "GET /sharings/ce8835a061d0ef68947afe69a0046722/discovery?state=eiJ3iepoaihohz1Y HTTP / 1.1 Host : alice.example.net", "title": "Example"}, {"location": "cozy-stack/sharing/#post-sharingssharing-iddiscovery", "text": "Give to the cozy of the sharer the URL of the Cozy of one recipient. The sharer will register its-self as an OAuth client on the recipient cozy, and then will ask the recipient to accept the permissions on its instance. This route exists in two versions, the version is selected by the HTTP header Accept", "title": "POST /sharings/:sharing-id/discovery"}, {"location": "cozy-stack/sharing/#classical-x-www-form-urlencoded", "text": "Parameter Description state a code that identify the recipient url the URL of the Cozy for the recipient", "title": "Classical (x-www-form-urlencoded)"}, {"location": "cozy-stack/sharing/#example_1", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/discovery HTTP / 1.1 Host : alice.example.org Content-Type : application/x-www-form-urlencoded Accept : text/html state=eiJ3iepoaihohz1Y&url=https://bob.example.net/ HTTP / 1.1 302 Moved Temporarily Location : https://bob.example.net/auth/sharing?...", "title": "Example"}, {"location": "cozy-stack/sharing/#json", "text": "This version can be more convenient for applications that implement the preview page. To do that, an application must give a preview_path when creating the sharing. This path must be a public route of this application. The recipients will receive a link to the application subdomain, on this page, and with a sharecode in the query string (like for a share by link). To know the sharing-id , it\u2019s possible to ask GET /permissions/self , with the sharecode in the Authorization header (it\u2019s a JWT token). In the response, the source_id field will be io.cozy.sharings/ .", "title": "JSON"}, {"location": "cozy-stack/sharing/#parameters", "text": "Parameter Description sharecode a code that identify the recipient url the URL of the Cozy for the recipient", "title": "Parameters"}, {"location": "cozy-stack/sharing/#example_2", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/discovery HTTP / 1.1 Host : alice.example.org Content-Type : application/x-www-form-urlencoded Accept : application/json sharecode=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhcHAiLCJpYXQiOjE1MjAzNDM4NTc&url=https://bob.example.net/ HTTP / 1.1 200 OK Content-Type : application/json { \"redirect\" : \"https://bob.example.net/auth/sharing?...\" }", "title": "Example"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idpreview-url", "text": "This internal route can be used by the stack to get the URL where a member can preview the sharing.", "title": "POST /sharings/:sharing-id/preview-url"}, {"location": "cozy-stack/sharing/#request_1", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/discovery-url HTTP / 1.1 Host : alice.example.net Content-Type : application/json { \"state\" : \"eiJ3iepoaihohz1Y\" }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_1", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"url\" : \"https://drive.alice.example.net/preview?sharecode=...\" }", "title": "Response"}, {"location": "cozy-stack/sharing/#get-sharingssharing-id", "text": "Get the information about a sharing. This includes the content of the rules, the members, as well as the already shared documents for this sharing. For a member, we can have the following fields: a contact name ( name ), that is the name of this user as it appears in its contact document (if there is one such document) a public name ( public_name ), that is the name this user has put on his cozy as a public name (it is used for sending emails for example) an email addresse ( email ) an instance URL ( instance ) and a status ( status ). Notes: the first member is always the sharer to display the list of members to a user, the name should be use if available, and if it is not the case, you can use the public_name or the email on a recipient, the only member with an instance is the local user.", "title": "GET /sharings/:sharing-id"}, {"location": "cozy-stack/sharing/#request_2", "text": "GET /sharings/ce8835a061d0ef68947afe69a0046722 HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/sharing/#response_2", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"initial_number_of_files_to_sync\" : 42 , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"612acf1c-1d72-11e8-b043-ef239d3074dd\" , \"type\" : \"io.cozy.files\" }, { \"id\" : \"a34528d2-13fb-9482-8d20-bf1972531225\" , \"type\" : \"io.cozy.files\" } ] } }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } }", "title": "Response"}, {"location": "cozy-stack/sharing/#get-sharingsnews", "text": "It returns the number of shortcuts to a sharing that have not been seen.", "title": "GET /sharings/news"}, {"location": "cozy-stack/sharing/#request_3", "text": "GET /sharings/news HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/sharing/#response_3", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"meta\" : { \"count\" : 5 } }", "title": "Response"}, {"location": "cozy-stack/sharing/#get-sharingsdoctypedoctype", "text": "Get information about all the sharings that have a rule for the given doctype. This includes the content of the rules, the members, as well as the already shared documents for this sharing.", "title": "GET /sharings/doctype/:doctype"}, {"location": "cozy-stack/sharing/#request_4", "text": "GET /sharings/doctype/io.cozy.files HTTP / 1.1 Host : alice.example.net Accept : application/vnd.api+json", "title": "Request"}, {"location": "cozy-stack/sharing/#response_4", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : [ { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"612acf1c-1d72-11e8-b043-ef239d3074dd\" , \"type\" : \"io.cozy.files\" }, { \"id\" : \"a34528d2-13fb-9482-8d20-bf1972531225\" , \"type\" : \"io.cozy.files\" } ] } } }, { \"type\" : \"io.cozy.sharings\" , \"id\" : \"b4e58d039c03d01742085de5e505284e\" , \"attributes\" : { \"description\" : \"another sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-02-04T12:35:08Z\" , \"updated_at\" : \"2018-02-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" } ], \"rules\" : [ { \"title\" : \"Singapore\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"e18e30e2-8eda-1bde-afce-edafc6b1a91b\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"meta\" : { \"rev\" : \"1-7ac5f1252a0c513186a5d35b1a6fd350\" }, \"links\" : { \"self\" : \"/sharings/b4e58d039c03d01742085de5e505284e\" }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"dcc52bee-1277-a6b3-b36f-369ffd81a4ee\" , \"type\" : \"io.cozy.files\" } ] } } } ], \"meta\" : { \"count\" : 3 } }", "title": "Response"}, {"location": "cozy-stack/sharing/#put-sharingssharing-id", "text": "The sharer\u2019s cozy sends a request to this route on the recipient\u2019s cozy to create a sharing request, with information about the sharing. This request can be used for two scenarios: This request will be displayed to the recipient just before its final acceptation of the sharing, to be sure they know what will be shared. This request will be used to create a shortcut (in that case, a query-string parameter shortcut=true&url=... will be added).", "title": "PUT /sharings/:sharing-id"}, {"location": "cozy-stack/sharing/#request_5", "text": "PUT /sharings/ce8835a061d0ef68947afe69a0046722 HTTP / 1.1 Host : bob.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"mail-not-sent\" , \"email\" : \"bob@example.net\" , \"instance\" : \"bob.example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_5", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-f579a69a9fa5dd720010a1dbb82320be\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"mail-not-sent\" , \"name\" : \"Bob\" , \"email\" : \"bob@example.net\" , \"instance\" : \"bob.example.net\" } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } }", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idanswer", "text": "This route is used by the Cozy of a recipient to exchange credentials with the Cozy of the sharer, after the recipient has accepted a sharing.", "title": "POST /sharings/:sharing-id/answer"}, {"location": "cozy-stack/sharing/#request_6", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/answer HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"public_name\" : \"Bob\" , \"state\" : \"eiJ3iepoaihohz1Y\" , \"client\" : { ... }, \"access_token\" : { ... } } } } When the sharing has a rule for bitwarden organization, the attributes also have a bitwarden object with user_id and public_key , to make it possible to share documents end to end encrypted.", "title": "Request"}, {"location": "cozy-stack/sharing/#response_6", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"client\" : { ... }, \"access_token\" : { ... } } } }", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idpublic-key", "text": "This route can be used by a sharing member to send their new public key after they have chosen their password for the first time (delegated authentication).", "title": "POST /sharings/:sharing-id/public-key"}, {"location": "cozy-stack/sharing/#request_7", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/public-key HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json Authorization : Bearer ... { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"bitwarden\" : { \"user_id\" : \"0dc76ad9b1cf3a979b916b3155001830\" , \"public_key\" : \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wboB9QutvRKGswphAre6xi4boYxSw4IjXqXDTV297Cq/MB2cBklj+sMmRQNTkU266HFSTGp3jDVcegAsHMpVVlTKZnWW+gSP2+vSyGs9NUvG8JfLday1iuOntHJQkfYiZ7+BfBYFtx6iWRnbnegickyoS7PWibLP5lmEzZnFtrGcRT8urSfN61qlOVD1u+eqtif5tabdU6eyNWUMLCQYgtaGb1nNht/xDgbpBc3b2XbEF0tBJRFR5571EH1h//Ae7IT+pYuBZB9BoPAHj4fhQm3++oNjemUJbaVi0dM4KNfQ89z1lBBCh5lxAGPlpOjapN0qGPgSov8B9U+qXlmzQIDAQAB\" } } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_7", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idrecipients", "text": "This route allows the sharer to add new recipients (and groups of recipients) to a sharing. It can also be used by a recipient when the sharing has open_sharing set to true if the recipient doesn\u2019t have the read_only flag.", "title": "POST /sharings/:sharing-id/recipients"}, {"location": "cozy-stack/sharing/#request_8", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"relationships\" : { \"recipients\" : { \"data\" : [ { \"id\" : \"ce7b1dfbd460039159f228298a29b2aa\" , \"type\" : \"io.cozy.contacts\" } ] }, \"read_only_recipients\" : { \"data\" : [ { \"id\" : \"e15384a1223ae2501cc1c4fa94008ea0\" , \"type\" : \"io.cozy.contacts\" } ] } } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_8", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"meta\" : { \"rev\" : \"1-4859c6c755143adf0838d225c5e97882\" }, \"attributes\" : { \"description\" : \"sharing test\" , \"preview_path\" : \"/preview-sharing\" , \"app_slug\" : \"drive\" , \"owner\" : true , \"created_at\" : \"2018-01-04T12:35:08Z\" , \"updated_at\" : \"2018-01-04T13:45:43Z\" , \"members\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"public_name\" : \"Bob\" , \"email\" : \"bob@example.net\" }, { \"status\" : \"pending\" , \"name\" : \"Charlie\" , \"email\" : \"charlie@example.net\" }, { \"status\" : \"pending\" , \"name\" : \"Dave\" , \"email\" : \"dave@example.net\" , \"read_only\" : true } ], \"rules\" : [ { \"title\" : \"Hawaii\" , \"doctype\" : \"io.cozy.files\" , \"values\" : [ \"612acf1c-1d72-11e8-b043-ef239d3074dd\" ], \"add\" : \"sync\" , \"update\" : \"sync\" , \"remove\" : \"sync\" } ] }, \"relationships\" : { \"shared_docs\" : { \"data\" : [ { \"id\" : \"612acf1c-1d72-11e8-b043-ef239d3074dd\" , \"type\" : \"io.cozy.files\" }, { \"id\" : \"a34528d2-13fb-9482-8d20-bf1972531225\" , \"type\" : \"io.cozy.files\" } ] } }, \"links\" : { \"self\" : \"/sharings/ce8835a061d0ef68947afe69a0046722\" } } }", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idrecipientsdelegated", "text": "This is an internal route for the stack. It is called by the recipient cozy on the owner cozy to add recipients and groups to the sharing ( open_sharing: true only). Data for direct recipients should contain an email address but if it is not known, an instance URL can also be provided.", "title": "POST /sharings/:sharing-id/recipients/delegated"}, {"location": "cozy-stack/sharing/#request_9", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/delegated HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"relationships\" : { \"recipients\" : { \"data\" : [ { \"email\" : \"dave@example.net\" } ] }, \"groups\" : { \"data\" : [ { \"id\" : \"b57cd790b2f4013c3ced18c04daba326\" , \"name\" : \"Dance\" , \"addedBy\" : 1 } ] } } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_9", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"dave@example.net\" : \"uS6wN7fTYaLZ-GdC_P6UWA\" }", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idmembersindexinvitation", "text": "This is an internal route for the stack. It is called by the recipient cozy on the owner cozy to send an invitation.", "title": "POST /sharings/:sharing-id/members/:index/invitation"}, {"location": "cozy-stack/sharing/#request_10", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/members/4/invitation HTTP / 1.1 Host : alice.example.net Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.members\" , \"attributes\" : { \"email\" : \"diana@example.net\" } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_10", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"diana@example.net\" : \"uS6wN7fTYaLZ-GdC_P6UWA\" }", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idgroupsgroup-indexmember-index", "text": "This is an internal route for the stack. It is called by the recipient cozy on the owner cozy to remove a member of a sharing from a group.", "title": "DELETE /sharings/:sharing-id/groups/:group-index/:member-index"}, {"location": "cozy-stack/sharing/#request_11", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/groups/0/1 HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_11", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#put-sharingssharing-idrecipients", "text": "This internal route is used to update the list of members (their states, emails and names) and the list of groups on the recipients cozy. The token used for this route can be the access token for a sharing where synchronization is active, or the sharecode for a member who has only a shortcut to the sharing on their Cozy instance.", "title": "PUT /sharings/:sharing-id/recipients"}, {"location": "cozy-stack/sharing/#request_12", "text": "PUT /sharings/ce8835a061d0ef68947afe69a0046722/recipients HTTP / 1.1 Host : bob.example.net Content-Type : application/vnd.api+json { \"data\" : [ { \"status\" : \"owner\" , \"public_name\" : \"Alice\" , \"email\" : \"alice@example.net\" , \"instance\" : \"alice.example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Bob\" , \"public_name\" : \"Bob\" , \"email\" : \"bob@example.net\" }, { \"status\" : \"ready\" , \"name\" : \"Charlie\" , \"public_name\" : \"Charlie\" , \"email\" : \"charlie@example.net\" }, { \"status\" : \"pending\" , \"name\" : \"Dave\" , \"email\" : \"dave@example.net\" , \"read_only\" : true } ], \"included\" : [ { \"id\" : \"51bbc980acb0013cb5f618c04daba326\" , \"name\" : \"G. people\" , \"addedBy\" : 0 } ] }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_12", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#get-sharingssharing-idrecipientsindexavatar", "text": "This route can be used to get an image that shows the avatar of a member of this sharing. No permission is required to use this route, you just need to know the sharing-id to use it. If no image has been chosen, a fallback will be used, depending of the fallback parameter in the query-string: initials : a generated image with the initials of the owner\u2019s public name. This is the default behavior. 404 : just a 404 - Not found error. If the initials fallback is used and the member has not yet seen the sharing, the background of the image will be grey. Note : 0 for the index means the sharer.", "title": "GET /sharings/:sharing-id/recipients/:index/avatar"}, {"location": "cozy-stack/sharing/#request_13", "text": "GET /sharings/ce8835a061d0ef68947afe69a0046722/recipients/2/avatar HTTP / 1.1 Host : bob.example.net Accept : image/*", "title": "Request"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idrecipientsindexreadonly", "text": "This route is used to add the read-only flag on a recipient of a sharing. Note : 0 is not accepted for index , as it is the sharer him-self.", "title": "POST /sharings/:sharing-id/recipients/:index/readonly"}, {"location": "cozy-stack/sharing/#request_14", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/3/readonly HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_13", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idrecipientsselfreadonly", "text": "This is an internal route for the stack. It\u2019s used to inform the recipient\u2019s cozy that it is no longer in read-write mode. It also gives it an access token with a short validity (1 hour) to let it try to synchronize its last changes before going to read-only mode.", "title": "POST /sharings/:sharing-id/recipients/self/readonly"}, {"location": "cozy-stack/sharing/#request_15", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self/readonly HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"4dadbcae3f2d7a982e1b308eea000751\" , \"attributes\" : { \"client\" : { ... }, \"access_token\" : { ... } } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_14", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idrecipientsindexreadonly", "text": "This route is used to remove the read-only flag on a recipient of a sharing. Note : 0 is not accepted for index , as it is the sharer him-self.", "title": "DELETE /sharings/:sharing-id/recipients/:index/readonly"}, {"location": "cozy-stack/sharing/#request_16", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/3/readonly HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_15", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idrecipientsselfreadonly", "text": "This is an internal route for the stack. It\u2019s used to inform the recipient\u2019s cozy that it is no longer in read-only mode, and to give it the credentials for sending its updates.", "title": "DELETE /sharings/:sharing-id/recipients/self/readonly"}, {"location": "cozy-stack/sharing/#request_17", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self/readonly HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.answer\" , \"id\" : \"4dadbcae3f2d7a982e1b308eea000751\" , \"attributes\" : { \"client\" : { ... }, \"access_token\" : { ... } } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_16", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idrecipients", "text": "This route is used by an application on the owner\u2019s cozy to revoke the sharing for all the members. After that, the sharing active flag will be false, the credentials for all members will be revoked, the members that have accepted the sharing will have their cozy informed that the sharing has been revoked, and pending members can no longer accept this sharing.", "title": "DELETE /sharings/:sharing-id/recipients"}, {"location": "cozy-stack/sharing/#request_18", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_17", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idrecipientsindex", "text": "This route can be only be called on the cozy instance of the sharer to revoke only one recipient of the sharing. The parameter is the index of this recipient in the members array of the sharing. The status for this member will be set to revoked , its cozy will be informed of the revokation, and the credentials for this cozy will be deleted. Note : 0 is not accepted for index , as it is the sharer him-self.", "title": "DELETE /sharings/:sharing-id/recipients/:index"}, {"location": "cozy-stack/sharing/#request_19", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/1 HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_18", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idgroupsindex", "text": "This route can be only be called on the cozy instance of the sharer to revoke a group of the sharing. The parameter is the index of this recipient in the groups array of the sharing. The removed property for this group will be set to true , and it will revoke the members of this group unless they are still part of the sharing via another group or as direct recipients.", "title": "DELETE /sharings/:sharing-id/groups/:index"}, {"location": "cozy-stack/sharing/#request_20", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/groups/0 HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_19", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idrecipientsself", "text": "This route can be used by an application in the cozy of a recipient to remove it from the sharing.", "title": "DELETE /sharings/:sharing-id/recipients/self"}, {"location": "cozy-stack/sharing/#request_21", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self HTTP / 1.1 Host : bob.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_20", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-id", "text": "This is an internal route used by the cozy of the sharing\u2019s owner to inform a recipient\u2019s cozy that it was revoked.", "title": "DELETE /sharings/:sharing-id"}, {"location": "cozy-stack/sharing/#request_22", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722 HTTP / 1.1 Host : bob.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_21", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idanswer", "text": "This is an internal route used by a recipient\u2019s cozy to inform the owner\u2019s cozy that this recipient no longer wants to be part of the sharing.", "title": "DELETE /sharings/:sharing-id/answer"}, {"location": "cozy-stack/sharing/#request_23", "text": "DELETE /sharings/ce8835a061d0ef68947afe69a0046722/answer HTTP / 1.1 Host : alice.example.net", "title": "Request"}, {"location": "cozy-stack/sharing/#response_22", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idrecipientsselfmoved", "text": "This route can be used to inform that a Cozy has been moved to a new address.", "title": "POST /sharings/:sharing-id/recipients/self/moved"}, {"location": "cozy-stack/sharing/#request_24", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/recipients/self/moved HTTP / 1.1 Host : bob.example.net Authorization : Bearer ... Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.sharings.moved\" , \"id\" : \"ce8835a061d0ef68947afe69a0046722\" , \"attributes\" : { \"new_instance\" : \"https://alice.newcozy.example\" , \"access_token\" : \"xxx\" , \"refresh_token\" : \"xxx\" } } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_23", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-id_revs_diff", "text": "This endpoint is used by the sharing replicator of the stack to know which documents must be sent to the other cozy. It is inspired by http://docs.couchdb.org/en/stable/api/database/misc.html#db-revs-diff.", "title": "POST /sharings/:sharing-id/_revs_diff"}, {"location": "cozy-stack/sharing/#request_25", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/_revs_diff HTTP / 1.1 Host : bob.example.net Accept : application/json Content-Type : application/json Authorization : Bearer ... { \"io.cozy.files/29631902-2cec-11e8-860d-435b24c2cc58\" : [ \"2-4a7e4ae49c4366eaed8edeaea8f784ad\" ], \"io.cozy.files/44f5752a-2cec-11e8-b227-abfc3cfd4b6e\" : [ \"4-2ee767305024673cfb3f5af037cd2729\" , \"4-efc54218773c6acd910e2e97fea2a608\" ] }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_24", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"io.cozy.files/44f5752a-2cec-11e8-b227-abfc3cfd4b6e\" : { \"missing\" : [ \"4-2ee767305024673cfb3f5af037cd2729\" ], \"possible_ancestors\" : [ \"3-753875d51501a6b1883a9d62b4d33f91\" ] } }", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-id_bulk_docs", "text": "This endpoint is used by the sharing replicator of the stack to send documents in a bulk to the other cozy. It is inspired by http://docs.couchdb.org/en/stable/api/database/bulk-api.html#db-bulk-docs. Note : we force new_edits to false .", "title": "POST /sharings/:sharing-id/_bulk_docs"}, {"location": "cozy-stack/sharing/#request_26", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/_bulk_docs HTTP / 1.1 Host : bob.example.net Accept : application/json Content-Type : application/json Authorization : Bearer ... { \"io.cozy.files\" : [ { \"_id\" : \"44f5752a-2cec-11e8-b227-abfc3cfd4b6e\" , \"_rev\" : \"4-2ee767305024673cfb3f5af037cd2729\" , \"_revisions\" : { \"start\" : 4 , \"ids\" : [ \"2ee767305024673cfb3f5af037cd2729\" , \"753875d51501a6b1883a9d62b4d33f91\" ] } } ] }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_25", "text": "HTTP / 1.1 200 OK Content-Type : application/json []", "title": "Response"}, {"location": "cozy-stack/sharing/#get-sharingssharing-idiocozyfilesfile-id", "text": "This is an internal endpoint used by a stack to get information about a folder. It is used when a cozy sent to another cozy a file or folder inside a folder that was trashed (and trash was emptied): the recipient does no longer have information about the parent directory. To resolve the conflict, it recreates the missing parent directory by asking the other cozy informations about it.", "title": "GET /sharings/:sharing-id/io.cozy.files/:file-id"}, {"location": "cozy-stack/sharing/#request_27", "text": "GET /sharings/ce8835a061d0ef68947afe69a0046722/io.cozy.files/6d245d072be5522bd3a6f273dd000c65 HTTP / 1.1 Host : alice.example.net Accept : application/json Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/sharing/#response_26", "text": "HTTP / 1.1 200 OK Content-Type : application/json { \"_id\" : \"6d245d072be5522bd3a6f273dd000c65\" , \"_rev\" : \"1-de4ec176ffa9ddafe8bdcc739dc60fed\" , \"type\" : \"directory\" , \"name\" : \"phone\" , \"dir_id\" : \"6d245d072be5522bd3a6f273dd007396\" , \"created_at\" : \"2016-09-19T12:35:08Z\" , \"updated_at\" : \"2016-09-19T12:35:08Z\" , \"tags\" : [ \"bills\" ] }", "title": "Response"}, {"location": "cozy-stack/sharing/#put-sharingssharing-idiocozyfilesfile-idmetadata", "text": "This is an internal endpoint used by a stack to send the new metadata about a file that has changed.", "title": "PUT /sharings/:sharing-id/io.cozy.files/:file-id/metadata"}, {"location": "cozy-stack/sharing/#request_28", "text": "PUT /sharings/ce8835a061d0ef68947afe69a0046722/io.cozy.files/0c1116b028c6ae6f5cdafb949c088265/metadata HTTP / 1.1 Host : bob.example.net Accept : application/json Content-Type : application/json Authorization : Bearer ... { \"_id\" : \"4b24ab130b2538b7b444fc65430198ad\" , \"_rev\" : \"1-356bf77c03baa1da851a2be1f06aba81\" , \"_revisions\" : { \"start\" : 1 , \"ids\" : [ \"356bf77c03baa1da851a2be1f06aba81\" ] }, \"type\" : \"file\" , \"name\" : \"cloudy.jpg\" , \"dir_id\" : \"4b24ab130b2538b7b444fc65430188cd\" , \"created_at\" : \"2018-01-03T16:10:36.885807013+01:00\" , \"updated_at\" : \"2018-01-03T16:10:36.885807013+01:00\" , \"size\" : \"84980\" , \"md5sum\" : \"SuRJOiD/QPwDUpKpQujcVA==\" , \"mime\" : \"image/jpeg\" , \"class\" : \"image\" , \"executable\" : false , \"trashed\" : false , \"tags\" : [], \"metadata\" : { \"datetime\" : \"2018-01-03T16:10:36.89118949+01:00\" , \"extractor_version\" : 2 , \"height\" : 1200 , \"width\" : 1600 } }", "title": "Request"}, {"location": "cozy-stack/sharing/#response_27", "text": "If only the metadata has changed (not the content), the response will be a 204: HTTP / 1.1 204 No Content Else, the content will need to be uploaded: HTTP/1.1 200 OK Content-Type: application/json { \"key\" : \"dcd478c6-46cf-11e8-9c3f-535468cbce7b\" }", "title": "Response"}, {"location": "cozy-stack/sharing/#put-sharingssharing-idiocozyfileskey", "text": "Upload the content of a file (new file or its content has changed since the last synchronization).", "title": "PUT /sharings/:sharing-id/io.cozy.files/:key"}, {"location": "cozy-stack/sharing/#request_29", "text": "PUT /sharings/ce8835a061d0ef68947afe69a0046722/io.cozy.files/dcd478c6-46cf-11e8-9c3f-535468cbce7b HTTP / 1.1 Host : bob.example.net Content-Type : image/jpeg Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/sharing/#response_28", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#post-sharingssharing-idreupload", "text": "This is an internal route for the stack. It is called when the disk quota of an instance is increased to ask for the others instances on this sharing to try to reupload files without waiting for the normal retry period.", "title": "POST /sharings/:sharing-id/reupload"}, {"location": "cozy-stack/sharing/#request_30", "text": "POST /sharings/ce8835a061d0ef68947afe69a0046722/reupload HTTP / 1.1 Host : bob.example.net Authorization : Bearer ...", "title": "Request"}, {"location": "cozy-stack/sharing/#response_29", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#delete-sharingssharing-idinitial", "text": "This internal route is used by the sharer to inform a recipient\u2019s cozy that the initial sync is finished. DELETE /sharings/ce8835a061d0ef68947afe69a0046722/initial HTTP / 1.1 Host : bob.example.net Authorization : Bearer ...", "title": "DELETE /sharings/:sharing-id/initial"}, {"location": "cozy-stack/sharing/#response_30", "text": "HTTP / 1.1 204 No Content", "title": "Response"}, {"location": "cozy-stack/sharing/#real-time-via-websockets", "text": "You can subscribe to the realtime API for the normal doctypes, but also for a special io.cozy.sharings.initial_sync doctype. For this doctype, you can give the id of a sharing and you will be notified when a file will be received during the initial synchronisation ( UPDATED ), and when the sync will be done ( DELETED ).", "title": "Real-time via websockets"}, {"location": "cozy-stack/sharing/#example_3", "text": "client > {\"method\": \"AUTH\", \"payload\": \"xxAppOrAuthTokenxx=\"} client > {\"method\": \"SUBSCRIBE\", \"payload\": {\"type\": \"io.cozy.sharings.initial_sync\", \"id\": \"ce8835a061d0ef68947afe69a0046722\"}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"ce8835a061d0ef68947afe69a0046722\", \"type\": \"io.cozy.sharings.initial_sync\", \"doc\": {\"count\": 12}}} server > {\"event\": \"UPDATED\", \"payload\": {\"id\": \"ce8835a061d0ef68947afe69a0046722\", \"type\": \"io.cozy.sharings.initial_sync\", \"doc\": {\"count\": 13}}} server > {\"event\": \"DELETED\", \"payload\": {\"id\": \"ce8835a061d0ef68947afe69a0046722\", \"type\": \"io.cozy.sharings.initial_sync\"}}", "title": "Example"}, {"location": "cozy-stack/shortcuts/", "text": "Table of contents Shortcuts \u00b6 A shortcut is a file in the VFS with a .url extension. It is served with the application/internet-shortcut mime-type. The stack provides a few routes to help manipulate them. POST /shortcuts \u00b6 This route can be used to create a shortcut. You can create a shortcut using the POST /files/:dir-id route, but the content must respect the .url file format. This route offers an easier way to do that. Note: a permission to create a file is required to use this route. Request \u00b6 POST /shortcuts HTTP / 1.1 Host : alice.cozy.example Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.shortcuts\" , \"attributes\" : { \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"url\" : \"https://alice-photos.cozy.example/#/photos/629fb233be550a21174ac8e19f0043af\" , \"metadata\" : { \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"app\" : \"photos\" , \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" } } } } } Response \u00b6 HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"_id\" : \"629fb233be550a21174ac8e19f0043af\" , \"_rev\" : \"1-61c7804bdb4f9f8dae5a363cb9a30dd8\" , \"type\" : \"file\" , \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"trashed\" : false , \"md5sum\" : \"vfEMDpJShs8QeIlsDmw9VA==\" , \"created_at\" : \"2020-02-10T20:38:04Z\" , \"updated_at\" : \"2020-02-10T20:38:04Z\" , \"tags\" : [], \"metadata\" : { \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"app\" : \"photos\" , \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" } }, \"size\" : 62 , \"executable\" : false , \"class\" : \"shortcut\" , \"mime\" : \"application/shortcut\" , \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-02-10T20:38:04Z\" , \"createdOn\" : \"https://bob.cozy.example/\" , \"updatedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedOn\" : \"https://bob.cozy.example/\" } } GET /shortcuts/:id \u00b6 This route can be used to get information about a shortcut. A permission to read the file is required to use it. There are two variants, depending on the Accept header. Request (JSON variant) \u00b6 If the Accept header is application/vnd.api+json (or application/json ), the information are returned in JSON-API format. GET /shortcuts/629fb233be550a21174ac8e19f0043af HTTP / 1.1 Host : alice.cozy.example Accept : application/vnd.api+json Response (JSON variant) \u00b6 HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"629fb233be550a21174ac8e19f0043af\" , \"type\" : \"io.cozy.files.shortcuts\" , \"attributes\" : { \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"url\" : \"https://alice-photos.cozy.example/#/photos/629fb233be550a21174ac8e19f0043af\" , \"metadata\" : { \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"app\" : \"photos\" , \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" } } } } } Request (Redirection variant) \u00b6 GET /shortcuts/629fb233be550a21174ac8e19f0043af HTTP / 1.1 Host : alice.cozy.example Accept : text/html Response (Redirection variant) \u00b6 HTTP / 1.1 303 See Other Location : https://alice-photos.cozy.example/#/photos/629fb233be550a21174ac8e19f0043af", "title": "/shortcuts - Shortcuts"}, {"location": "cozy-stack/shortcuts/#shortcuts", "text": "A shortcut is a file in the VFS with a .url extension. It is served with the application/internet-shortcut mime-type. The stack provides a few routes to help manipulate them.", "title": "Shortcuts"}, {"location": "cozy-stack/shortcuts/#post-shortcuts", "text": "This route can be used to create a shortcut. You can create a shortcut using the POST /files/:dir-id route, but the content must respect the .url file format. This route offers an easier way to do that. Note: a permission to create a file is required to use this route.", "title": "POST /shortcuts"}, {"location": "cozy-stack/shortcuts/#request", "text": "POST /shortcuts HTTP / 1.1 Host : alice.cozy.example Content-Type : application/vnd.api+json { \"data\" : { \"type\" : \"io.cozy.files.shortcuts\" , \"attributes\" : { \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"url\" : \"https://alice-photos.cozy.example/#/photos/629fb233be550a21174ac8e19f0043af\" , \"metadata\" : { \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"app\" : \"photos\" , \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" } } } } }", "title": "Request"}, {"location": "cozy-stack/shortcuts/#response", "text": "HTTP / 1.1 201 Created Content-Type : application/vnd.api+json { \"_id\" : \"629fb233be550a21174ac8e19f0043af\" , \"_rev\" : \"1-61c7804bdb4f9f8dae5a363cb9a30dd8\" , \"type\" : \"file\" , \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"trashed\" : false , \"md5sum\" : \"vfEMDpJShs8QeIlsDmw9VA==\" , \"created_at\" : \"2020-02-10T20:38:04Z\" , \"updated_at\" : \"2020-02-10T20:38:04Z\" , \"tags\" : [], \"metadata\" : { \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"app\" : \"photos\" , \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" } }, \"size\" : 62 , \"executable\" : false , \"class\" : \"shortcut\" , \"mime\" : \"application/shortcut\" , \"cozyMetadata\" : { \"doctypeVersion\" : 1 , \"metadataVersion\" : 1 , \"createdAt\" : \"2020-02-10T20:38:04Z\" , \"createdOn\" : \"https://bob.cozy.example/\" , \"updatedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedAt\" : \"2020-02-10T20:38:04Z\" , \"uploadedOn\" : \"https://bob.cozy.example/\" } }", "title": "Response"}, {"location": "cozy-stack/shortcuts/#get-shortcutsid", "text": "This route can be used to get information about a shortcut. A permission to read the file is required to use it. There are two variants, depending on the Accept header.", "title": "GET /shortcuts/:id"}, {"location": "cozy-stack/shortcuts/#request-json-variant", "text": "If the Accept header is application/vnd.api+json (or application/json ), the information are returned in JSON-API format. GET /shortcuts/629fb233be550a21174ac8e19f0043af HTTP / 1.1 Host : alice.cozy.example Accept : application/vnd.api+json", "title": "Request (JSON variant)"}, {"location": "cozy-stack/shortcuts/#response-json-variant", "text": "HTTP / 1.1 200 OK Content-Type : application/vnd.api+json { \"data\" : { \"id\" : \"629fb233be550a21174ac8e19f0043af\" , \"type\" : \"io.cozy.files.shortcuts\" , \"attributes\" : { \"name\" : \"sunset.jpg.url\" , \"dir_id\" : \"629fb233be550a21174ac8e19f003e4a\" , \"url\" : \"https://alice-photos.cozy.example/#/photos/629fb233be550a21174ac8e19f0043af\" , \"metadata\" : { \"target\" : { \"cozyMetadata\" : { \"instance\" : \"https://alice.cozy.example/\" }, \"app\" : \"photos\" , \"_type\" : \"io.cozy.files\" , \"mime\" : \"image/jpg\" } } } } }", "title": "Response (JSON variant)"}, {"location": "cozy-stack/shortcuts/#request-redirection-variant", "text": "GET /shortcuts/629fb233be550a21174ac8e19f0043af HTTP / 1.1 Host : alice.cozy.example Accept : text/html", "title": "Request (Redirection variant)"}, {"location": "cozy-stack/shortcuts/#response-redirection-variant", "text": "HTTP / 1.1 303 See Other Location : https://alice-photos.cozy.example/#/photos/629fb233be550a21174ac8e19f0043af", "title": "Response (Redirection variant)"}, {"location": "cozy-stack/user-action-required/", "text": "Table of contents User action is required \u00b6 This document explains how the stack can alert applications that an user action is required to perform the expected services. For example, the stack can block most of its API until the user read and sign new terms of services. HTTP 402 Error \u00b6 In some cases the stack will return a 402 error to API requests. 402 will be used to denote error that require an user\u2019s action. For now, the only use cases are a Terms Of Services update. But some other use cases might appear in the future. The specific cause of this error will be provided within the body of the response (see examples below). HTTP / 1.1 402 Payment Required Content-Length : ... Content-Type : application/vnd.api+json { \"errors\" : [ { \"status\" : \"402\" , \"title\" : \"TOS Updated\" , \"code\" : \"tos-updated\" , \"detail\" : \"Terms of services have been updated\" , \"links\" : { \"self\" : \"https://manager.cozycloud.cc/cozy/tos?domain=...\" } } ] } If they receive such a code, the clients should block any further action on the stack, warn the user with the necessary message and provide a button allowing the user to perform the required action. If the client knows the specific error code, display a beautiful message. Otherwise, display the message provided by the stack and use the links.action on the button. Possible other codes in the future: payment_required for functions requiring a premium account, etc. HTTP 410 error \u00b6 The 410 HTTP error code will be used when an instance has been moved to a new address. { \"errors\" : [ { \"status\" : \"410\" , \"title\" : \"Cozy has been moved\" , \"code\" : \"moved\" , \"detail\" : \"The Cozy has been moved to a new address\" , \"links\" : { \"related\" : \"https://newcozy.example.org/\" } } ] } Anticipating these errors and warning the user \u00b6 An enpoints exists to get the list of warnings that the user can anticipate. For applications these warnings are included directly into the HTML of the index page, as follow: < meta name = \"user-action-required\" data-title = \"{{ .Title }}\" data-code = \"{{ .Code }}\" data-detail = \"{{ .Detail }}\" data-links = \"{{ .Links.Self }}\" } /> Request \u00b6 GET /settings/warnings HTTP / 1.1 Response \u00b6 HTTP / 1.1 402 Payment Required Content-Length : ... Content-Type : application/vnd.api+json { \"errors\" : [ { \"status\" : \"402\" , \"title\" : \"TOS Updated\" , \"code\" : \"tos-updated\" , \"detail\" : \"Terms of services have been updated\" , \"links\" : { \"self\" : \"https://manager.cozycloud.cc/cozy/tos?domain=...\" } } ] }", "title": " /settings - Terms of Services"}, {"location": "cozy-stack/user-action-required/#user-action-is-required", "text": "This document explains how the stack can alert applications that an user action is required to perform the expected services. For example, the stack can block most of its API until the user read and sign new terms of services.", "title": "User action is required"}, {"location": "cozy-stack/user-action-required/#http-402-error", "text": "In some cases the stack will return a 402 error to API requests. 402 will be used to denote error that require an user\u2019s action. For now, the only use cases are a Terms Of Services update. But some other use cases might appear in the future. The specific cause of this error will be provided within the body of the response (see examples below). HTTP / 1.1 402 Payment Required Content-Length : ... Content-Type : application/vnd.api+json { \"errors\" : [ { \"status\" : \"402\" , \"title\" : \"TOS Updated\" , \"code\" : \"tos-updated\" , \"detail\" : \"Terms of services have been updated\" , \"links\" : { \"self\" : \"https://manager.cozycloud.cc/cozy/tos?domain=...\" } } ] } If they receive such a code, the clients should block any further action on the stack, warn the user with the necessary message and provide a button allowing the user to perform the required action. If the client knows the specific error code, display a beautiful message. Otherwise, display the message provided by the stack and use the links.action on the button. Possible other codes in the future: payment_required for functions requiring a premium account, etc.", "title": "HTTP 402 Error"}, {"location": "cozy-stack/user-action-required/#http-410-error", "text": "The 410 HTTP error code will be used when an instance has been moved to a new address. { \"errors\" : [ { \"status\" : \"410\" , \"title\" : \"Cozy has been moved\" , \"code\" : \"moved\" , \"detail\" : \"The Cozy has been moved to a new address\" , \"links\" : { \"related\" : \"https://newcozy.example.org/\" } } ] }", "title": "HTTP 410 error"}, {"location": "cozy-stack/user-action-required/#anticipating-these-errors-and-warning-the-user", "text": "An enpoints exists to get the list of warnings that the user can anticipate. For applications these warnings are included directly into the HTML of the index page, as follow: < meta name = \"user-action-required\" data-title = \"{{ .Title }}\" data-code = \"{{ .Code }}\" data-detail = \"{{ .Detail }}\" data-links = \"{{ .Links.Self }}\" } />", "title": "Anticipating these errors and warning the user"}, {"location": "cozy-stack/user-action-required/#request", "text": "GET /settings/warnings HTTP / 1.1", "title": "Request"}, {"location": "cozy-stack/user-action-required/#response", "text": "HTTP / 1.1 402 Payment Required Content-Length : ... Content-Type : application/vnd.api+json { \"errors\" : [ { \"status\" : \"402\" , \"title\" : \"TOS Updated\" , \"code\" : \"tos-updated\" , \"detail\" : \"Terms of services have been updated\" , \"links\" : { \"self\" : \"https://manager.cozycloud.cc/cozy/tos?domain=...\" } } ] }", "title": "Response"}, {"location": "cozy-stack/wellknown/", "text": "Table of contents Well-known URIs \u00b6 Change-password \u00b6 This endpoint redirects to the settings page where the user can change their password. See https://w3c.github.io/webappsec-change-password-url/ Request \u00b6 GET /.well-known/change-password HTTP / 1.1 Host : alice.cozy.example.net Response \u00b6 HTTP / 1.1 302 Found Location : https://alice-settings.cozy.example.net/#/profile/password", "title": "/.well-known - Well-known"}, {"location": "cozy-stack/wellknown/#well-known-uris", "text": "", "title": "Well-known URIs"}, {"location": "cozy-stack/wellknown/#change-password", "text": "This endpoint redirects to the settings page where the user can change their password. See https://w3c.github.io/webappsec-change-password-url/", "title": "Change-password"}, {"location": "cozy-stack/wellknown/#request", "text": "GET /.well-known/change-password HTTP / 1.1 Host : alice.cozy.example.net", "title": "Request"}, {"location": "cozy-stack/wellknown/#response", "text": "HTTP / 1.1 302 Found Location : https://alice-settings.cozy.example.net/#/profile/password", "title": "Response"}, {"location": "cozy-stack/workers/", "text": "Table of contents Workers \u00b6 This page list all the currently available workers on the cozy-stack. It describes their input arguments object. See the jobs document to know more about the API context in which you can see how to use these arguments. log worker \u00b6 The log worker will just print in the log file the job sent to it. It can useful for debugging for example. thumbnail worker \u00b6 The thumbnail worker is used internally by the stack to generate thumbnails from the image files of a cozy instance. konnector worker \u00b6 The konnector worker is used to execute JS code that collects files and data from external providers, and put them in the Cozy. Its execution is detailed on the Konnector Worker specs . Job arguments \u00b6 To execute a konnector through a job, the expected arguments are the following: \"arguments\": { \"konnector\": , \"account\": } service worker \u00b6 The service worker is used to process background jobs, generally to compute non-realtime user data. \"arguments\": { \"slug\": , \"name\": , \"fields\": } Job arguments \u00b6 To execute a service through a job, the expected arguments are the following: \"arguments\": { \"name\": , \"slug\": } push worker \u00b6 The push worker can be used to send push-notifications to a user\u2019s device. The options are: client_id : the ID of the oauth client to push a notification to. title : the title of the notification message : the content of the notification data : key-value string map for additional metadata (optional) priority : the notification priority: high or normal (optional) topic : the topic identifier of the notification (optional) sound : a sound associated with the notification (optional) Example \u00b6 { \"client_id\" : \"abcdef123123123\" , \"title\" : \"My Notification\" , \"message\" : \"My notification content.\" , \"priority\" : \"high\" } Permissions \u00b6 To use this worker from a client-side application, you should use the notifications API . sms worker \u00b6 The sms worker can be used to send SMS notifications to a user, via the notifications API . The phone number used is the primary phone number registered in the contact that has the flag me: true (see contact doctype ) Note: If an error happens during the send of the sms (for instance no phone number on the cozy or SMS provider not available), the content will be send by email as fallback. To use the sms worker, you need to configure your SMS provider: - first enable sms worker in your stack configuration - configure the notification configuration by setting your provider\u2019s informations. unzip worker \u00b6 The unzip worker can take a zip archive from the VFS, and will unzip the files inside it to a directory of the VFS. The options are: zip : the ID of the zip file destination : the ID of the directory where the files will be unzipped. Example \u00b6 { \"zip\" : \"8737b5d6-51b6-11e7-9194-bf5b64b3bc9e\" , \"destination\" : \"88750a84-51b6-11e7-ba90-4f0b1cb62b7b\" } Permissions \u00b6 To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"unzip-to-a-directory\" : { \"description\" : \"Required to unzip a file inside the cozy\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"unzip\" ] } } } zip worker \u00b6 The zip worker does pretty much the opposite of the unzip worker: it creates a zip archive from files in the VFS. The options are: files : a map with the the files to zip (their path in the zip as key, their VFS identifier as value) dir_id : the directory identifier where the zip archive will be put filename : the name of the zip archive. Note: it is possible to include only a page for a PDF file, by using an object with id and page instead of just the file identifier. Example \u00b6 { \"files\" : { \"selection/one.pdf\" : \"36abc4c0-90fe-11e9-b05b-1fa43ca781ef\" , \"selection/two.pdf\" : \"36eb54c8-90fe-11e9-aeca-03ddc3acf91c\" , \"selection/three.pdf\" : \"37284586-90fe-11e9-be6d-179f72076e43\" , \"selection/four.pdf\" : \"37655462-90fe-11e9-9059-8739e3746720\" , \"selection/five.pdf\" : \"379fedfc-90fe-11e9-849f-0bbe172eba5f\" , \"selection/front.pdf\" : { \"id\" : \"49ca9e50-1074-013d-361a-18c04daba326\" , \"page\" : 1 }, \"selection/back.pdf\" : { \"id\" : \"49ca9e50-1074-013d-361a-18c04daba326\" , \"page\" : 2 } }, \"dir_id\" : \"3657ce9c-90fe-11e9-b40b-33baf841bcb8\" , \"filename\" : \"selection.zip\" } Permissions \u00b6 To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"create-a-zip-archive\" : { \"description\" : \"Required to create a zip archive inside the cozy\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"zip\" ] } } } sendmail worker \u00b6 The sendmail worker can be used to send mail from the stack. It implies that the stack has properly configured an access to an SMTP server. You can see an example of configuration in the cozy.example.yaml file at the root of this repository. sendmail options fields are the following: mode : string specifying the mode of the send: noreply to send a notification mail to the user pending to send a mail to the user to confirm their new email address from to send a mail from the user support to send both an email to the support and a confirmation to the user campaign to send a non transactional email to the user via an SMTP server using the following configurations, in order of priority: campaign_mail.contexts. if defined campaign_mail otherwise mail as the final fallback to : list of object {name, email} representing the addresses of the recipients. (should not be used in noreply mode) subject : string specifying the subject of the mail parts : list of part objects {type, body} listing representing the content parts of the type string of the content type: either text/html or text/plain body string of the actual body content of the part attachments : list of objects {filename, content} that represent the files attached to the email, where the content is base64-encoded Examples \u00b6 // from mode sending mail from the user to a list of recipients { \"mode\" : \"from\" , \"to\" : [ { \"name\" : \"John Doe 1\" , \"email\" : \"john1@doe\" }, { \"name\" : \"John Doe 2\" , \"email\" : \"john2@doe\" } ], \"subject\" : \"Hey !\" , \"parts\" : [ { \"type\" : \"text/html\" , \"body\" : \"

    Hey !

    \" }, { \"type\" : \"text/plain\" , \"body\" : \"Hey !\" } ] } // noreply mode, sending a notification mail to the user { \"mode\" : \"noreply\" , \"subject\" : \"You've got a new file !\" , \"parts\" : [ { \"type\" : \"text/html\" , \"body\" : \"

    Hey !

    \" }, { \"type\" : \"text/plain\" , \"body\" : \"Hey !\" } ] } Permissions \u00b6 To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to send mails from the user to his/her friends\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } } export \u00b6 The export worker can be used to generate allow the export of all data contained in the cozy. At the end of the export, a mail is sent to the user containing a link to access to its data. The progress of the export process can be followed with realtime events on the doctype io.cozy.exports . Its options are: parts_size : the size in bytes of the sizes index splitting done for multi-part download of files data max_age : the maximum age duration of the archive before it expires with_doctypes : the list of exported doctypes (exports all doctypes if empty) Example \u00b6 { \"parts_size\" : 52428800 , \"max_age\" : 60000000000 , // 1 minute \"with_doctypes\" : [ \"io.cozy.accounts\" , \"io.cozy.files\" ] // empty or null means all doctypes } import \u00b6 The import worker can be used to import the data from an export. The instance will be reset before importing data to avoid complex logic of reconciliation. The instance is blocked during the import, and a mail is sent at the end of the import, when the instance can be accessed again. Its options are: manifest_url : the URL of the manifest for the exported data. Example \u00b6 { \"manifest_url\" : \"http://cozy.localhost:8080/move/exports/QUFBQUFGLVg5b3c0WTJNNU9HRmpPR0V4WlRnd01XVTJZMlU0T0RjeE5UaGpNVEF3TWpKbVplblFfRWZWUVAtRGJXU0lnV2tIZ3NsVHN5dUR6V0ZIdVdSeERLb196X3A0\" } Permissions \u00b6 To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to create a export of the user's data\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"export\" ] } } } trash-files worker \u00b6 This worker is used only by the stack: when the user asks to clean the trash, the stack will delete the files from CouchDB and put a job for this worker. The deletion of files in Swift is slow, and can be done via this worker asynchronously. The behavior is not the same for all the VFS: afero: all the work is done during the HTTP request, no job is pushed Swift layout v1: all the work is done during the HTTP request, no job is pushed Swift layout v2: the files are deleted in CouchDB during the HTTP request, and they are deleted in Swift via the job Swift layout v3: the files are deleted in CouchDB during the HTTP request, the file versions are deleted in CouchDB via the job, and the files and their versions are deleted in Swift via the job. clean-old-trashed worker \u00b6 This worker is used to automatically delete files and directories that are in the trash for too long. The threshold for deletion is configurable per context in the config file, via the fs.auto_clean_trashed_after parameter. share workers \u00b6 The stack have 4 workers to power the sharings (internal usage only): share-group , to add/remove members to a sharing share-track , to update the io.cozy.shared database share-replicate , to start a replicator for most documents share-upload , to upload files Share-group \u00b6 When a contact is added to or removed from a group, the change should be reflected in the group\u2019s sharings\u2019 recipients. The message is composed of the contact ID, the list of groups added and the list of groups removed. Share-track \u00b6 The message is composed of 3 fields: the sharing ID, the rule index, and the doctype. The event is similar to a realtime event: a verb, a document, and optionaly the old version of this document. Share-replicate and share-upload \u00b6 The message is composed of a sharing ID and a count of the number of errors (i.e. the number of times this job was retried). notes-save \u00b6 This is another worker for the interal usage of the stack. It allows to write to the VFS a note in an asynchronous way. Writing to the VFS after each tiny change would kill the performance for realtime collaboration, so the stack writes the note to a cache, and has a trigger with debounce to persist the note to the VFS later. clean-clients \u00b6 This internal worker will delete unused OAuth clients. When an OAuth client is created, it has the pending flag set to true. When an access code is generated for a client, the flag is set to false. If 1 hour after the client has been created, the flag is still true, this worker will delete the client. It will help to clean unused clients which can be misleading for the user when the list of clients in settings is displayed. migrations \u00b6 The migrations worker can be used to migrate a cozy instance. Currently, it has a single option, type , with two supported values: remove-unwanted-folders : remove the administrative and/or photos folders for contexts where init_administrative_folder or init_photos_folder is set to false to-swift-v3 : migrate a cozy instance that has files in swift from a V1 or V2 layout to a V3 layout accounts-to-organization : create ciphers from accounts , re-encrypted with the organization key notes-mime-type : update the notes mime-type to text/vnd.cozy.note+markdown to allow them to be listed in the cozy-notes application. Example \u00b6 It can be launched from command-line with: $ cozy-stack jobs run migrations --domain example.mycozy.cloud --json '{\"type\": \"to-swift-v3\"}'", "title": " /jobs - Workers"}, {"location": "cozy-stack/workers/#workers", "text": "This page list all the currently available workers on the cozy-stack. It describes their input arguments object. See the jobs document to know more about the API context in which you can see how to use these arguments.", "title": "Workers"}, {"location": "cozy-stack/workers/#log-worker", "text": "The log worker will just print in the log file the job sent to it. It can useful for debugging for example.", "title": "log worker"}, {"location": "cozy-stack/workers/#thumbnail-worker", "text": "The thumbnail worker is used internally by the stack to generate thumbnails from the image files of a cozy instance.", "title": "thumbnail worker"}, {"location": "cozy-stack/workers/#konnector-worker", "text": "The konnector worker is used to execute JS code that collects files and data from external providers, and put them in the Cozy. Its execution is detailed on the Konnector Worker specs .", "title": "konnector worker"}, {"location": "cozy-stack/workers/#job-arguments", "text": "To execute a konnector through a job, the expected arguments are the following: \"arguments\": { \"konnector\": , \"account\": }", "title": "Job arguments"}, {"location": "cozy-stack/workers/#service-worker", "text": "The service worker is used to process background jobs, generally to compute non-realtime user data. \"arguments\": { \"slug\": , \"name\": , \"fields\": }", "title": "service worker"}, {"location": "cozy-stack/workers/#job-arguments_1", "text": "To execute a service through a job, the expected arguments are the following: \"arguments\": { \"name\": , \"slug\": }", "title": "Job arguments"}, {"location": "cozy-stack/workers/#push-worker", "text": "The push worker can be used to send push-notifications to a user\u2019s device. The options are: client_id : the ID of the oauth client to push a notification to. title : the title of the notification message : the content of the notification data : key-value string map for additional metadata (optional) priority : the notification priority: high or normal (optional) topic : the topic identifier of the notification (optional) sound : a sound associated with the notification (optional)", "title": "push worker"}, {"location": "cozy-stack/workers/#example", "text": "{ \"client_id\" : \"abcdef123123123\" , \"title\" : \"My Notification\" , \"message\" : \"My notification content.\" , \"priority\" : \"high\" }", "title": "Example"}, {"location": "cozy-stack/workers/#permissions", "text": "To use this worker from a client-side application, you should use the notifications API .", "title": "Permissions"}, {"location": "cozy-stack/workers/#sms-worker", "text": "The sms worker can be used to send SMS notifications to a user, via the notifications API . The phone number used is the primary phone number registered in the contact that has the flag me: true (see contact doctype ) Note: If an error happens during the send of the sms (for instance no phone number on the cozy or SMS provider not available), the content will be send by email as fallback. To use the sms worker, you need to configure your SMS provider: - first enable sms worker in your stack configuration - configure the notification configuration by setting your provider\u2019s informations.", "title": "sms worker"}, {"location": "cozy-stack/workers/#unzip-worker", "text": "The unzip worker can take a zip archive from the VFS, and will unzip the files inside it to a directory of the VFS. The options are: zip : the ID of the zip file destination : the ID of the directory where the files will be unzipped.", "title": "unzip worker"}, {"location": "cozy-stack/workers/#example_1", "text": "{ \"zip\" : \"8737b5d6-51b6-11e7-9194-bf5b64b3bc9e\" , \"destination\" : \"88750a84-51b6-11e7-ba90-4f0b1cb62b7b\" }", "title": "Example"}, {"location": "cozy-stack/workers/#permissions_1", "text": "To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"unzip-to-a-directory\" : { \"description\" : \"Required to unzip a file inside the cozy\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"unzip\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/workers/#zip-worker", "text": "The zip worker does pretty much the opposite of the unzip worker: it creates a zip archive from files in the VFS. The options are: files : a map with the the files to zip (their path in the zip as key, their VFS identifier as value) dir_id : the directory identifier where the zip archive will be put filename : the name of the zip archive. Note: it is possible to include only a page for a PDF file, by using an object with id and page instead of just the file identifier.", "title": "zip worker"}, {"location": "cozy-stack/workers/#example_2", "text": "{ \"files\" : { \"selection/one.pdf\" : \"36abc4c0-90fe-11e9-b05b-1fa43ca781ef\" , \"selection/two.pdf\" : \"36eb54c8-90fe-11e9-aeca-03ddc3acf91c\" , \"selection/three.pdf\" : \"37284586-90fe-11e9-be6d-179f72076e43\" , \"selection/four.pdf\" : \"37655462-90fe-11e9-9059-8739e3746720\" , \"selection/five.pdf\" : \"379fedfc-90fe-11e9-849f-0bbe172eba5f\" , \"selection/front.pdf\" : { \"id\" : \"49ca9e50-1074-013d-361a-18c04daba326\" , \"page\" : 1 }, \"selection/back.pdf\" : { \"id\" : \"49ca9e50-1074-013d-361a-18c04daba326\" , \"page\" : 2 } }, \"dir_id\" : \"3657ce9c-90fe-11e9-b40b-33baf841bcb8\" , \"filename\" : \"selection.zip\" }", "title": "Example"}, {"location": "cozy-stack/workers/#permissions_2", "text": "To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"create-a-zip-archive\" : { \"description\" : \"Required to create a zip archive inside the cozy\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"zip\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/workers/#sendmail-worker", "text": "The sendmail worker can be used to send mail from the stack. It implies that the stack has properly configured an access to an SMTP server. You can see an example of configuration in the cozy.example.yaml file at the root of this repository. sendmail options fields are the following: mode : string specifying the mode of the send: noreply to send a notification mail to the user pending to send a mail to the user to confirm their new email address from to send a mail from the user support to send both an email to the support and a confirmation to the user campaign to send a non transactional email to the user via an SMTP server using the following configurations, in order of priority: campaign_mail.contexts. if defined campaign_mail otherwise mail as the final fallback to : list of object {name, email} representing the addresses of the recipients. (should not be used in noreply mode) subject : string specifying the subject of the mail parts : list of part objects {type, body} listing representing the content parts of the type string of the content type: either text/html or text/plain body string of the actual body content of the part attachments : list of objects {filename, content} that represent the files attached to the email, where the content is base64-encoded", "title": "sendmail worker"}, {"location": "cozy-stack/workers/#examples", "text": "// from mode sending mail from the user to a list of recipients { \"mode\" : \"from\" , \"to\" : [ { \"name\" : \"John Doe 1\" , \"email\" : \"john1@doe\" }, { \"name\" : \"John Doe 2\" , \"email\" : \"john2@doe\" } ], \"subject\" : \"Hey !\" , \"parts\" : [ { \"type\" : \"text/html\" , \"body\" : \"

    Hey !

    \" }, { \"type\" : \"text/plain\" , \"body\" : \"Hey !\" } ] } // noreply mode, sending a notification mail to the user { \"mode\" : \"noreply\" , \"subject\" : \"You've got a new file !\" , \"parts\" : [ { \"type\" : \"text/html\" , \"body\" : \"

    Hey !

    \" }, { \"type\" : \"text/plain\" , \"body\" : \"Hey !\" } ] }", "title": "Examples"}, {"location": "cozy-stack/workers/#permissions_3", "text": "To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to send mails from the user to his/her friends\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"sendmail\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/workers/#export", "text": "The export worker can be used to generate allow the export of all data contained in the cozy. At the end of the export, a mail is sent to the user containing a link to access to its data. The progress of the export process can be followed with realtime events on the doctype io.cozy.exports . Its options are: parts_size : the size in bytes of the sizes index splitting done for multi-part download of files data max_age : the maximum age duration of the archive before it expires with_doctypes : the list of exported doctypes (exports all doctypes if empty)", "title": "export"}, {"location": "cozy-stack/workers/#example_3", "text": "{ \"parts_size\" : 52428800 , \"max_age\" : 60000000000 , // 1 minute \"with_doctypes\" : [ \"io.cozy.accounts\" , \"io.cozy.files\" ] // empty or null means all doctypes }", "title": "Example"}, {"location": "cozy-stack/workers/#import", "text": "The import worker can be used to import the data from an export. The instance will be reset before importing data to avoid complex logic of reconciliation. The instance is blocked during the import, and a mail is sent at the end of the import, when the instance can be accessed again. Its options are: manifest_url : the URL of the manifest for the exported data.", "title": "import"}, {"location": "cozy-stack/workers/#example_4", "text": "{ \"manifest_url\" : \"http://cozy.localhost:8080/move/exports/QUFBQUFGLVg5b3c0WTJNNU9HRmpPR0V4WlRnd01XVTJZMlU0T0RjeE5UaGpNVEF3TWpKbVplblFfRWZWUVAtRGJXU0lnV2tIZ3NsVHN5dUR6V0ZIdVdSeERLb196X3A0\" }", "title": "Example"}, {"location": "cozy-stack/workers/#permissions_4", "text": "To use this worker from a client-side application, you will need to ask the permission. It is done by adding this to the manifest: { \"permissions\" : { \"mail-from-the-user\" : { \"description\" : \"Required to create a export of the user's data\" , \"type\" : \"io.cozy.jobs\" , \"verbs\" : [ \"POST\" ], \"selector\" : \"worker\" , \"values\" : [ \"export\" ] } } }", "title": "Permissions"}, {"location": "cozy-stack/workers/#trash-files-worker", "text": "This worker is used only by the stack: when the user asks to clean the trash, the stack will delete the files from CouchDB and put a job for this worker. The deletion of files in Swift is slow, and can be done via this worker asynchronously. The behavior is not the same for all the VFS: afero: all the work is done during the HTTP request, no job is pushed Swift layout v1: all the work is done during the HTTP request, no job is pushed Swift layout v2: the files are deleted in CouchDB during the HTTP request, and they are deleted in Swift via the job Swift layout v3: the files are deleted in CouchDB during the HTTP request, the file versions are deleted in CouchDB via the job, and the files and their versions are deleted in Swift via the job.", "title": "trash-files worker"}, {"location": "cozy-stack/workers/#clean-old-trashed-worker", "text": "This worker is used to automatically delete files and directories that are in the trash for too long. The threshold for deletion is configurable per context in the config file, via the fs.auto_clean_trashed_after parameter.", "title": "clean-old-trashed worker"}, {"location": "cozy-stack/workers/#share-workers", "text": "The stack have 4 workers to power the sharings (internal usage only): share-group , to add/remove members to a sharing share-track , to update the io.cozy.shared database share-replicate , to start a replicator for most documents share-upload , to upload files", "title": "share workers"}, {"location": "cozy-stack/workers/#share-group", "text": "When a contact is added to or removed from a group, the change should be reflected in the group\u2019s sharings\u2019 recipients. The message is composed of the contact ID, the list of groups added and the list of groups removed.", "title": "Share-group"}, {"location": "cozy-stack/workers/#share-track", "text": "The message is composed of 3 fields: the sharing ID, the rule index, and the doctype. The event is similar to a realtime event: a verb, a document, and optionaly the old version of this document.", "title": "Share-track"}, {"location": "cozy-stack/workers/#share-replicate-and-share-upload", "text": "The message is composed of a sharing ID and a count of the number of errors (i.e. the number of times this job was retried).", "title": "Share-replicate and share-upload"}, {"location": "cozy-stack/workers/#notes-save", "text": "This is another worker for the interal usage of the stack. It allows to write to the VFS a note in an asynchronous way. Writing to the VFS after each tiny change would kill the performance for realtime collaboration, so the stack writes the note to a cache, and has a trigger with debounce to persist the note to the VFS later.", "title": "notes-save"}, {"location": "cozy-stack/workers/#clean-clients", "text": "This internal worker will delete unused OAuth clients. When an OAuth client is created, it has the pending flag set to true. When an access code is generated for a client, the flag is set to false. If 1 hour after the client has been created, the flag is still true, this worker will delete the client. It will help to clean unused clients which can be misleading for the user when the list of clients in settings is displayed.", "title": "clean-clients"}, {"location": "cozy-stack/workers/#migrations", "text": "The migrations worker can be used to migrate a cozy instance. Currently, it has a single option, type , with two supported values: remove-unwanted-folders : remove the administrative and/or photos folders for contexts where init_administrative_folder or init_photos_folder is set to false to-swift-v3 : migrate a cozy instance that has files in swift from a V1 or V2 layout to a V3 layout accounts-to-organization : create ciphers from accounts , re-encrypted with the organization key notes-mime-type : update the notes mime-type to text/vnd.cozy.note+markdown to allow them to be listed in the cozy-notes application.", "title": "migrations"}, {"location": "cozy-stack/workers/#example_5", "text": "It can be launched from command-line with: $ cozy-stack jobs run migrations --domain example.mycozy.cloud --json '{\"type\": \"to-swift-v3\"}'", "title": "Example"}, {"location": "cozy-stack/cli/cozy-stack/", "text": "cozy-stack \u00b6 cozy-stack is the main command Synopsis \u00b6 Cozy is a platform that brings all your web services in the same private space. With it, your web apps and your devices can share data easily, providing you with a new experience. You can install Cozy on your own hardware where no one profiles you. cozy-stack [flags] Options \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") -h, --help help for cozy-stack --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack apps - Interact with the applications cozy-stack assets - Show and manage dynamic assets cozy-stack check - A set of tools to check that instances are in the expected state. cozy-stack completion - Output shell completion code for the specified shell cozy-stack config - Show and manage configuration elements cozy-stack doc - Print the documentation cozy-stack features - Manage the feature flags cozy-stack files - Interact with the cozy filesystem cozy-stack fix - A set of tools to fix issues or migrate content. cozy-stack instances - Manage instances of a stack cozy-stack jobs - Launch and manage jobs and workers cozy-stack konnectors - Interact with the konnectors cozy-stack serve - Starts the stack and listens for HTTP calls cozy-stack settings - Display and update settings cozy-stack status - Check if the HTTP server is running cozy-stack swift - Interact directly with OpenStack Swift object storage cozy-stack tools - Regroup some tools for debugging and tests cozy-stack triggers - Interact with the triggers cozy-stack version - Print the version number", "title": "Manpages of the command-line tool"}, {"location": "cozy-stack/cli/cozy-stack/#cozy-stack", "text": "cozy-stack is the main command", "title": "cozy-stack"}, {"location": "cozy-stack/cli/cozy-stack/#synopsis", "text": "Cozy is a platform that brings all your web services in the same private space. With it, your web apps and your devices can share data easily, providing you with a new experience. You can install Cozy on your own hardware where no one profiles you. cozy-stack [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack/#options", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") -h, --help help for cozy-stack --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack/#see-also", "text": "cozy-stack apps - Interact with the applications cozy-stack assets - Show and manage dynamic assets cozy-stack check - A set of tools to check that instances are in the expected state. cozy-stack completion - Output shell completion code for the specified shell cozy-stack config - Show and manage configuration elements cozy-stack doc - Print the documentation cozy-stack features - Manage the feature flags cozy-stack files - Interact with the cozy filesystem cozy-stack fix - A set of tools to fix issues or migrate content. cozy-stack instances - Manage instances of a stack cozy-stack jobs - Launch and manage jobs and workers cozy-stack konnectors - Interact with the konnectors cozy-stack serve - Starts the stack and listens for HTTP calls cozy-stack settings - Display and update settings cozy-stack status - Check if the HTTP server is running cozy-stack swift - Interact directly with OpenStack Swift object storage cozy-stack tools - Regroup some tools for debugging and tests cozy-stack triggers - Interact with the triggers cozy-stack version - Print the version number", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_apps/", "text": "cozy-stack apps \u00b6 Interact with the applications Synopsis \u00b6 cozy-stack apps allows to interact with the cozy applications. It provides commands to install or update applications on a cozy. cozy-stack apps [flags] Options \u00b6 --all-domains work on all domains iteratively --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for apps Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack apps install - Install an application with the specified slug name from the given source URL. cozy-stack apps ls - List the installed applications. cozy-stack apps show - Show the application attributes cozy-stack apps uninstall - Uninstall the application with the specified slug name. cozy-stack apps update - Update the application with the specified slug name.", "title": "Cozy stack apps"}, {"location": "cozy-stack/cli/cozy-stack_apps/#cozy-stack-apps", "text": "Interact with the applications", "title": "cozy-stack apps"}, {"location": "cozy-stack/cli/cozy-stack_apps/#synopsis", "text": "cozy-stack apps allows to interact with the cozy applications. It provides commands to install or update applications on a cozy. cozy-stack apps [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_apps/#options", "text": "--all-domains work on all domains iteratively --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for apps", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_apps/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_apps/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack apps install - Install an application with the specified slug name from the given source URL. cozy-stack apps ls - List the installed applications. cozy-stack apps show - Show the application attributes cozy-stack apps uninstall - Uninstall the application with the specified slug name. cozy-stack apps update - Update the application with the specified slug name.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_apps_install/", "text": "cozy-stack apps install \u00b6 Install an application with the specified slug name from the given source URL. Synopsis \u00b6 Some schemes are allowed as [sourceurl] . cozy-stack apps install [sourceurl] [flags] Examples \u00b6 $ cozy-stack apps install --domain cozy.localhost:8080 drive registry://drive/stable $ cozy-stack apps install banks 'git://github.com/cozy/cozy-banks.git#build' $ cozy-stack apps install myapp 'git+ssh://git@gitlab.example.net/team/myapp.git#build' Options \u00b6 --ask-permissions specify that the application should not be activated after installation -h, --help help for install Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack apps - Interact with the applications", "title": "Cozy stack apps install"}, {"location": "cozy-stack/cli/cozy-stack_apps_install/#cozy-stack-apps-install", "text": "Install an application with the specified slug name from the given source URL.", "title": "cozy-stack apps install"}, {"location": "cozy-stack/cli/cozy-stack_apps_install/#synopsis", "text": "Some schemes are allowed as [sourceurl] . cozy-stack apps install [sourceurl] [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_apps_install/#examples", "text": "$ cozy-stack apps install --domain cozy.localhost:8080 drive registry://drive/stable $ cozy-stack apps install banks 'git://github.com/cozy/cozy-banks.git#build' $ cozy-stack apps install myapp 'git+ssh://git@gitlab.example.net/team/myapp.git#build'", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_apps_install/#options", "text": "--ask-permissions specify that the application should not be activated after installation -h, --help help for install", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_apps_install/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_apps_install/#see-also", "text": "cozy-stack apps - Interact with the applications", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_apps_ls/", "text": "cozy-stack apps ls \u00b6 List the installed applications. cozy-stack apps ls [flags] Options \u00b6 -h, --help help for ls Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack apps - Interact with the applications", "title": "Cozy stack apps ls"}, {"location": "cozy-stack/cli/cozy-stack_apps_ls/#cozy-stack-apps-ls", "text": "List the installed applications. cozy-stack apps ls [flags]", "title": "cozy-stack apps ls"}, {"location": "cozy-stack/cli/cozy-stack_apps_ls/#options", "text": "-h, --help help for ls", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_apps_ls/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_apps_ls/#see-also", "text": "cozy-stack apps - Interact with the applications", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_apps_show/", "text": "cozy-stack apps show \u00b6 Show the application attributes cozy-stack apps show [flags] Options \u00b6 -h, --help help for show Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack apps - Interact with the applications", "title": "Cozy stack apps show"}, {"location": "cozy-stack/cli/cozy-stack_apps_show/#cozy-stack-apps-show", "text": "Show the application attributes cozy-stack apps show [flags]", "title": "cozy-stack apps show"}, {"location": "cozy-stack/cli/cozy-stack_apps_show/#options", "text": "-h, --help help for show", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_apps_show/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_apps_show/#see-also", "text": "cozy-stack apps - Interact with the applications", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_apps_uninstall/", "text": "cozy-stack apps uninstall \u00b6 Uninstall the application with the specified slug name. cozy-stack apps uninstall [flags] Options \u00b6 -h, --help help for uninstall Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack apps - Interact with the applications", "title": "Cozy stack apps uninstall"}, {"location": "cozy-stack/cli/cozy-stack_apps_uninstall/#cozy-stack-apps-uninstall", "text": "Uninstall the application with the specified slug name. cozy-stack apps uninstall [flags]", "title": "cozy-stack apps uninstall"}, {"location": "cozy-stack/cli/cozy-stack_apps_uninstall/#options", "text": "-h, --help help for uninstall", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_apps_uninstall/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_apps_uninstall/#see-also", "text": "cozy-stack apps - Interact with the applications", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_apps_update/", "text": "cozy-stack apps update \u00b6 Update the application with the specified slug name. cozy-stack apps update [sourceurl] [flags] Options \u00b6 -h, --help help for update --safe do not upgrade if there are blocking changes Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack apps - Interact with the applications", "title": "Cozy stack apps update"}, {"location": "cozy-stack/cli/cozy-stack_apps_update/#cozy-stack-apps-update", "text": "Update the application with the specified slug name. cozy-stack apps update [sourceurl] [flags]", "title": "cozy-stack apps update"}, {"location": "cozy-stack/cli/cozy-stack_apps_update/#options", "text": "-h, --help help for update --safe do not upgrade if there are blocking changes", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_apps_update/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_apps_update/#see-also", "text": "cozy-stack apps - Interact with the applications", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_assets/", "text": "cozy-stack assets \u00b6 Show and manage dynamic assets Synopsis \u00b6 cozy-stack assets can be used to list, insert or remove dynamic assets Options \u00b6 -h, --help help for assets Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack assets add - Insert a dynamic asset cozy-stack assets ls - List assets cozy-stack assets rm - Removes an asset", "title": "Cozy stack assets"}, {"location": "cozy-stack/cli/cozy-stack_assets/#cozy-stack-assets", "text": "Show and manage dynamic assets", "title": "cozy-stack assets"}, {"location": "cozy-stack/cli/cozy-stack_assets/#synopsis", "text": "cozy-stack assets can be used to list, insert or remove dynamic assets", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_assets/#options", "text": "-h, --help help for assets", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_assets/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_assets/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack assets add - Insert a dynamic asset cozy-stack assets ls - List assets cozy-stack assets rm - Removes an asset", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_assets_add/", "text": "cozy-stack assets add \u00b6 Insert a dynamic asset Synopsis \u00b6 Insert an asset that will be available on https:// /assets/ For example, if a dynamic asset with the name \u2018/foo/bar/baz\u2019 is added for a context foocontext, and an instance example.mycozy.cloud is in the foocontext context, then this asset can be requested on https://example.mycozy.cloud/assets/foo/bar/baz.js (and not on \u2018example-app.mycozy.cloud\u2019). cozy-stack assets add --url --name --shasum --context [flags] Examples \u00b6 $ cozy-stack assets add --url file:///foo/bar/baz.js --name /foo/bar/baz.js --shasum 0763d6c2cebee0880eb3a9cc25d38cd23db39b5c3802f2dc379e408c877a2788 --context foocontext Options \u00b6 --context string The context of the asset -h, --help help for add --name string The name of the asset --shasum string The shasum of the asset --url string The URL of the asset Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack assets - Show and manage dynamic assets", "title": "Cozy stack assets add"}, {"location": "cozy-stack/cli/cozy-stack_assets_add/#cozy-stack-assets-add", "text": "Insert a dynamic asset", "title": "cozy-stack assets add"}, {"location": "cozy-stack/cli/cozy-stack_assets_add/#synopsis", "text": "Insert an asset that will be available on https:// /assets/ For example, if a dynamic asset with the name \u2018/foo/bar/baz\u2019 is added for a context foocontext, and an instance example.mycozy.cloud is in the foocontext context, then this asset can be requested on https://example.mycozy.cloud/assets/foo/bar/baz.js (and not on \u2018example-app.mycozy.cloud\u2019). cozy-stack assets add --url --name --shasum --context [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_assets_add/#examples", "text": "$ cozy-stack assets add --url file:///foo/bar/baz.js --name /foo/bar/baz.js --shasum 0763d6c2cebee0880eb3a9cc25d38cd23db39b5c3802f2dc379e408c877a2788 --context foocontext", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_assets_add/#options", "text": "--context string The context of the asset -h, --help help for add --name string The name of the asset --shasum string The shasum of the asset --url string The URL of the asset", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_assets_add/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_assets_add/#see-also", "text": "cozy-stack assets - Show and manage dynamic assets", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_assets_ls/", "text": "cozy-stack assets ls \u00b6 List assets Synopsis \u00b6 List assets currently served by the stack cozy-stack assets ls [flags] Examples \u00b6 $ cozy-stack assets ls Options \u00b6 -h, --help help for ls Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack assets - Show and manage dynamic assets", "title": "Cozy stack assets ls"}, {"location": "cozy-stack/cli/cozy-stack_assets_ls/#cozy-stack-assets-ls", "text": "List assets", "title": "cozy-stack assets ls"}, {"location": "cozy-stack/cli/cozy-stack_assets_ls/#synopsis", "text": "List assets currently served by the stack cozy-stack assets ls [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_assets_ls/#examples", "text": "$ cozy-stack assets ls", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_assets_ls/#options", "text": "-h, --help help for ls", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_assets_ls/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_assets_ls/#see-also", "text": "cozy-stack assets - Show and manage dynamic assets", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_assets_rm/", "text": "cozy-stack assets rm \u00b6 Removes an asset Synopsis \u00b6 Removes a custom asset in a specific context cozy-stack assets rm [context] [name] [flags] Examples \u00b6 $ cozy-stack assets rm foobar /foo/bar/baz.js Options \u00b6 -h, --help help for rm Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack assets - Show and manage dynamic assets", "title": "Cozy stack assets rm"}, {"location": "cozy-stack/cli/cozy-stack_assets_rm/#cozy-stack-assets-rm", "text": "Removes an asset", "title": "cozy-stack assets rm"}, {"location": "cozy-stack/cli/cozy-stack_assets_rm/#synopsis", "text": "Removes a custom asset in a specific context cozy-stack assets rm [context] [name] [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_assets_rm/#examples", "text": "$ cozy-stack assets rm foobar /foo/bar/baz.js", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_assets_rm/#options", "text": "-h, --help help for rm", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_assets_rm/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_assets_rm/#see-also", "text": "cozy-stack assets - Show and manage dynamic assets", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_check/", "text": "cozy-stack check \u00b6 A set of tools to check that instances are in the expected state. cozy-stack check [flags] Options \u00b6 -h, --help help for check Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack check fs - Check a vfs cozy-stack check shared - Check the io.cozy.shared documents cozy-stack check sharings - Check the io.cozy.sharings documents cozy-stack check triggers - Check the triggers", "title": "Cozy stack check"}, {"location": "cozy-stack/cli/cozy-stack_check/#cozy-stack-check", "text": "A set of tools to check that instances are in the expected state. cozy-stack check [flags]", "title": "cozy-stack check"}, {"location": "cozy-stack/cli/cozy-stack_check/#options", "text": "-h, --help help for check", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_check/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_check/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack check fs - Check a vfs cozy-stack check shared - Check the io.cozy.shared documents cozy-stack check sharings - Check the io.cozy.sharings documents cozy-stack check triggers - Check the triggers", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_check_fs/", "text": "cozy-stack check fs \u00b6 Check a vfs Synopsis \u00b6 This command checks that the files in the VFS are not desynchronized, ie a file present in CouchDB but not swift/localfs, or present in swift/localfs but not couchdb. There are 2 steps: index integrity checks that there are nothing wrong in the index (CouchDB), like a file present in a directory that has been deleted files consistency checks that the files are the same in the index (CouchDB) and the storage (Swift or localfs). By default, both operations are done, but you can choose one or the other via the flags. cozy-stack check fs [flags] Options \u00b6 --fail-fast Stop the FSCK on the first error --files-consistency Check the files consistency only (between CouchDB and Swift) -h, --help help for fs --index-integrity Check the index integrity only Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "Cozy stack check fs"}, {"location": "cozy-stack/cli/cozy-stack_check_fs/#cozy-stack-check-fs", "text": "Check a vfs", "title": "cozy-stack check fs"}, {"location": "cozy-stack/cli/cozy-stack_check_fs/#synopsis", "text": "This command checks that the files in the VFS are not desynchronized, ie a file present in CouchDB but not swift/localfs, or present in swift/localfs but not couchdb. There are 2 steps: index integrity checks that there are nothing wrong in the index (CouchDB), like a file present in a directory that has been deleted files consistency checks that the files are the same in the index (CouchDB) and the storage (Swift or localfs). By default, both operations are done, but you can choose one or the other via the flags. cozy-stack check fs [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_check_fs/#options", "text": "--fail-fast Stop the FSCK on the first error --files-consistency Check the files consistency only (between CouchDB and Swift) -h, --help help for fs --index-integrity Check the index integrity only", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_check_fs/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_check_fs/#see-also", "text": "cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_check_shared/", "text": "cozy-stack check shared \u00b6 Check the io.cozy.shared documents Synopsis \u00b6 The io.cozy.shared documents have a tree of revisions. This command will check that all revisions in this tree are either the root or their parent have a generation smaller than their generation. cozy-stack check shared [flags] Options \u00b6 -h, --help help for shared Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "Cozy stack check shared"}, {"location": "cozy-stack/cli/cozy-stack_check_shared/#cozy-stack-check-shared", "text": "Check the io.cozy.shared documents", "title": "cozy-stack check shared"}, {"location": "cozy-stack/cli/cozy-stack_check_shared/#synopsis", "text": "The io.cozy.shared documents have a tree of revisions. This command will check that all revisions in this tree are either the root or their parent have a generation smaller than their generation. cozy-stack check shared [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_check_shared/#options", "text": "-h, --help help for shared", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_check_shared/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_check_shared/#see-also", "text": "cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_check_sharings/", "text": "cozy-stack check sharings \u00b6 Check the io.cozy.sharings documents Synopsis \u00b6 This command checks that the io.cozy.sharings have no inconsistencies. It can be triggers that are missing on an active sharing, or missing credentials for an active member. There are 2 steps: setup integrity checks that there are nothing wrong in the configuration like a missing trigger files and folders consistency checks that the shared documents are the same for all members By default, both operations are done, but you can choose to skip the consistency check via the flags. cozy-stack check sharings [flags] Options \u00b6 --fast Skip the sharings FS consistency check -h, --help help for sharings Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "Cozy stack check sharings"}, {"location": "cozy-stack/cli/cozy-stack_check_sharings/#cozy-stack-check-sharings", "text": "Check the io.cozy.sharings documents", "title": "cozy-stack check sharings"}, {"location": "cozy-stack/cli/cozy-stack_check_sharings/#synopsis", "text": "This command checks that the io.cozy.sharings have no inconsistencies. It can be triggers that are missing on an active sharing, or missing credentials for an active member. There are 2 steps: setup integrity checks that there are nothing wrong in the configuration like a missing trigger files and folders consistency checks that the shared documents are the same for all members By default, both operations are done, but you can choose to skip the consistency check via the flags. cozy-stack check sharings [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_check_sharings/#options", "text": "--fast Skip the sharings FS consistency check -h, --help help for sharings", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_check_sharings/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_check_sharings/#see-also", "text": "cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_check_triggers/", "text": "cozy-stack check triggers \u00b6 Check the triggers Synopsis \u00b6 This command checks that the instance doesn\u2019t have duplicate triggers: several triggers of the same type, for the same worker, and with the same arguments. cozy-stack check triggers [flags] Options \u00b6 -h, --help help for triggers Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "Cozy stack check triggers"}, {"location": "cozy-stack/cli/cozy-stack_check_triggers/#cozy-stack-check-triggers", "text": "Check the triggers", "title": "cozy-stack check triggers"}, {"location": "cozy-stack/cli/cozy-stack_check_triggers/#synopsis", "text": "This command checks that the instance doesn\u2019t have duplicate triggers: several triggers of the same type, for the same worker, and with the same arguments. cozy-stack check triggers [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_check_triggers/#options", "text": "-h, --help help for triggers", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_check_triggers/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_check_triggers/#see-also", "text": "cozy-stack check - A set of tools to check that instances are in the expected state.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_completion/", "text": "cozy-stack completion \u00b6 Output shell completion code for the specified shell Synopsis \u00b6 Output shell completion code for the specified shell (bash, zsh, or fish). The shell code must be evalutated to provide interactive completion of cozy-stack commands. Bash: $ source <(cozy-stack completion bash) # To load completions for each session, execute once: # Linux: $ cozy-stack completion bash > /etc/bash_completion.d/cozy-stack # macOS: $ cozy-stack completion bash > $(brew \u2013prefix)/etc/bash_completion.d/cozy-stack Note: this requires the bash-completion framework, which is not installed by default on Mac. This can be installed by using homebrew: $ brew install bash-completion Once installed, bash_completion must be evaluated. This can be done by adding the following line to the .bash_profile $ source $( brew --prefix ) /etc/bash_completion Zsh: # If shell completion is not already enabled in your environment, # you will need to enable it. You can execute the following once: $ echo \u201cautoload -U compinit; compinit\u201d >> ~/.zshrc # To load completions for each session, execute once: $ cozy-stack completion zsh > \u201c${fpath[1]}/_cozy-stack\u201d # You will need to start a new shell for this setup to take effect. fish: $ cozy-stack completion fish | source # To load completions for each session, execute once: $ cozy-stack completion fish > /etc/fish/completions/cozy-stack.fish cozy-stack completion [flags] Options \u00b6 -h, --help help for completion Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command", "title": "Cozy stack completion"}, {"location": "cozy-stack/cli/cozy-stack_completion/#cozy-stack-completion", "text": "Output shell completion code for the specified shell", "title": "cozy-stack completion"}, {"location": "cozy-stack/cli/cozy-stack_completion/#synopsis", "text": "Output shell completion code for the specified shell (bash, zsh, or fish). The shell code must be evalutated to provide interactive completion of cozy-stack commands. Bash: $ source <(cozy-stack completion bash) # To load completions for each session, execute once: # Linux: $ cozy-stack completion bash > /etc/bash_completion.d/cozy-stack # macOS: $ cozy-stack completion bash > $(brew \u2013prefix)/etc/bash_completion.d/cozy-stack Note: this requires the bash-completion framework, which is not installed by default on Mac. This can be installed by using homebrew: $ brew install bash-completion Once installed, bash_completion must be evaluated. This can be done by adding the following line to the .bash_profile $ source $( brew --prefix ) /etc/bash_completion Zsh: # If shell completion is not already enabled in your environment, # you will need to enable it. You can execute the following once: $ echo \u201cautoload -U compinit; compinit\u201d >> ~/.zshrc # To load completions for each session, execute once: $ cozy-stack completion zsh > \u201c${fpath[1]}/_cozy-stack\u201d # You will need to start a new shell for this setup to take effect. fish: $ cozy-stack completion fish | source # To load completions for each session, execute once: $ cozy-stack completion fish > /etc/fish/completions/cozy-stack.fish cozy-stack completion [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_completion/#options", "text": "-h, --help help for completion", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_completion/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_completion/#see-also", "text": "cozy-stack - cozy-stack is the main command", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config/", "text": "cozy-stack config \u00b6 Show and manage configuration elements Synopsis \u00b6 cozy-stack config allows to print and generate some parts of the configuration Options \u00b6 -h, --help help for config Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack config decrypt-creds - Decrypt the given credentials cipher text with the specified decryption keyfile. cozy-stack config decrypt-data - Decrypt data with the specified decryption keyfile. cozy-stack config encrypt-creds - Encrypt the given credentials with the specified decryption keyfile. cozy-stack config encrypt-data - Encrypt data with the specified encryption keyfile. cozy-stack config gen-keys - Generate an key pair for encryption and decryption of credentials cozy-stack config insert-asset - Inserts an asset cozy-stack config ls-assets - List assets cozy-stack config ls-contexts - List contexts cozy-stack config passwd - Generate an admin passphrase cozy-stack config rm-asset - Removes an asset cozy-stack config show-context - Show a context", "title": "Cozy stack config"}, {"location": "cozy-stack/cli/cozy-stack_config/#cozy-stack-config", "text": "Show and manage configuration elements", "title": "cozy-stack config"}, {"location": "cozy-stack/cli/cozy-stack_config/#synopsis", "text": "cozy-stack config allows to print and generate some parts of the configuration", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config/#options", "text": "-h, --help help for config", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack config decrypt-creds - Decrypt the given credentials cipher text with the specified decryption keyfile. cozy-stack config decrypt-data - Decrypt data with the specified decryption keyfile. cozy-stack config encrypt-creds - Encrypt the given credentials with the specified decryption keyfile. cozy-stack config encrypt-data - Encrypt data with the specified encryption keyfile. cozy-stack config gen-keys - Generate an key pair for encryption and decryption of credentials cozy-stack config insert-asset - Inserts an asset cozy-stack config ls-assets - List assets cozy-stack config ls-contexts - List contexts cozy-stack config passwd - Generate an admin passphrase cozy-stack config rm-asset - Removes an asset cozy-stack config show-context - Show a context", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-creds/", "text": "cozy-stack config decrypt-creds \u00b6 Decrypt the given credentials cipher text with the specified decryption keyfile. cozy-stack config decrypt-creds [flags] Options \u00b6 -h, --help help for decrypt-creds Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config decrypt creds"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-creds/#cozy-stack-config-decrypt-creds", "text": "Decrypt the given credentials cipher text with the specified decryption keyfile. cozy-stack config decrypt-creds [flags]", "title": "cozy-stack config decrypt-creds"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-creds/#options", "text": "-h, --help help for decrypt-creds", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-creds/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-creds/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-data/", "text": "cozy-stack config decrypt-data \u00b6 Decrypt data with the specified decryption keyfile. cozy-stack config decrypt-data [flags] Options \u00b6 -h, --help help for decrypt-data Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config decrypt data"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-data/#cozy-stack-config-decrypt-data", "text": "Decrypt data with the specified decryption keyfile. cozy-stack config decrypt-data [flags]", "title": "cozy-stack config decrypt-data"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-data/#options", "text": "-h, --help help for decrypt-data", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-data/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_decrypt-data/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-creds/", "text": "cozy-stack config encrypt-creds \u00b6 Encrypt the given credentials with the specified decryption keyfile. cozy-stack config encrypt-creds [flags] Options \u00b6 -h, --help help for encrypt-creds Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config encrypt creds"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-creds/#cozy-stack-config-encrypt-creds", "text": "Encrypt the given credentials with the specified decryption keyfile. cozy-stack config encrypt-creds [flags]", "title": "cozy-stack config encrypt-creds"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-creds/#options", "text": "-h, --help help for encrypt-creds", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-creds/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-creds/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-data/", "text": "cozy-stack config encrypt-data \u00b6 Encrypt data with the specified encryption keyfile. Synopsis \u00b6 cozy-stack config encrypt-data encrypts any valid JSON data cozy-stack config encrypt-data [flags] Examples \u00b6 $ ./cozy-stack config encrypt-data ~/.cozy/key.enc \"{\\\"foo\\\": \\\"bar\\\"}\" $ bmFjbNFjY+XZkS26YtVPUIKKm/JdnAGwG30n6A4ypS1p1dHev8hOtaRbW+lGneoO7PS9JCW8U5GSXhASu+c3UkaZ Options \u00b6 -h, --help help for encrypt-data Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config encrypt data"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-data/#cozy-stack-config-encrypt-data", "text": "Encrypt data with the specified encryption keyfile.", "title": "cozy-stack config encrypt-data"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-data/#synopsis", "text": "cozy-stack config encrypt-data encrypts any valid JSON data cozy-stack config encrypt-data [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-data/#examples", "text": "$ ./cozy-stack config encrypt-data ~/.cozy/key.enc \"{\\\"foo\\\": \\\"bar\\\"}\" $ bmFjbNFjY+XZkS26YtVPUIKKm/JdnAGwG30n6A4ypS1p1dHev8hOtaRbW+lGneoO7PS9JCW8U5GSXhASu+c3UkaZ", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-data/#options", "text": "-h, --help help for encrypt-data", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-data/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_encrypt-data/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_gen-keys/", "text": "cozy-stack config gen-keys \u00b6 Generate an key pair for encryption and decryption of credentials Synopsis \u00b6 cozy-stack config gen-keys generate a key-pair and save them in the specified path. The decryptor key filename is given the \u201c.dec\u201d extension suffix. The encryptor key filename is given the \u201c.enc\u201d extension suffix. The files permissions are 0400. cozy-stack config gen-keys [flags] Examples \u00b6 $ cozy-stack config gen-keys ~/credentials-key keyfiles written in: ~/credentials-key.enc ~/credentials-key.dec Options \u00b6 -h, --help help for gen-keys Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config gen keys"}, {"location": "cozy-stack/cli/cozy-stack_config_gen-keys/#cozy-stack-config-gen-keys", "text": "Generate an key pair for encryption and decryption of credentials", "title": "cozy-stack config gen-keys"}, {"location": "cozy-stack/cli/cozy-stack_config_gen-keys/#synopsis", "text": "cozy-stack config gen-keys generate a key-pair and save them in the specified path. The decryptor key filename is given the \u201c.dec\u201d extension suffix. The encryptor key filename is given the \u201c.enc\u201d extension suffix. The files permissions are 0400. cozy-stack config gen-keys [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config_gen-keys/#examples", "text": "$ cozy-stack config gen-keys ~/credentials-key keyfiles written in: ~/credentials-key.enc ~/credentials-key.dec", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_config_gen-keys/#options", "text": "-h, --help help for gen-keys", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_gen-keys/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_gen-keys/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_insert-asset/", "text": "cozy-stack config insert-asset \u00b6 Inserts an asset Synopsis \u00b6 Inserts a custom asset in a specific context Deprecated: please use the command cozy-stack assets add. cozy-stack config insert-asset --url --name --shasum --context [flags] Options \u00b6 --context string The context of the asset -h, --help help for insert-asset --name string The name of the asset --shasum string The shasum of the asset --url string The URL of the asset Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config insert asset"}, {"location": "cozy-stack/cli/cozy-stack_config_insert-asset/#cozy-stack-config-insert-asset", "text": "Inserts an asset", "title": "cozy-stack config insert-asset"}, {"location": "cozy-stack/cli/cozy-stack_config_insert-asset/#synopsis", "text": "Inserts a custom asset in a specific context Deprecated: please use the command cozy-stack assets add. cozy-stack config insert-asset --url --name --shasum --context [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config_insert-asset/#options", "text": "--context string The context of the asset -h, --help help for insert-asset --name string The name of the asset --shasum string The shasum of the asset --url string The URL of the asset", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_insert-asset/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_insert-asset/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-assets/", "text": "cozy-stack config ls-assets \u00b6 List assets Synopsis \u00b6 List assets currently served by the stack Deprecated: please use the command cozy-stack assets ls. cozy-stack config ls-assets [flags] Options \u00b6 -h, --help help for ls-assets Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config ls assets"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-assets/#cozy-stack-config-ls-assets", "text": "List assets", "title": "cozy-stack config ls-assets"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-assets/#synopsis", "text": "List assets currently served by the stack Deprecated: please use the command cozy-stack assets ls. cozy-stack config ls-assets [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-assets/#options", "text": "-h, --help help for ls-assets", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-assets/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-assets/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-contexts/", "text": "cozy-stack config ls-contexts \u00b6 List contexts Synopsis \u00b6 List contexts currently used by the stack cozy-stack config ls-contexts [flags] Examples \u00b6 $ cozy-stack config ls-contexts Options \u00b6 -h, --help help for ls-contexts Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config ls contexts"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-contexts/#cozy-stack-config-ls-contexts", "text": "List contexts", "title": "cozy-stack config ls-contexts"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-contexts/#synopsis", "text": "List contexts currently used by the stack cozy-stack config ls-contexts [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-contexts/#examples", "text": "$ cozy-stack config ls-contexts", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-contexts/#options", "text": "-h, --help help for ls-contexts", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-contexts/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_ls-contexts/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_passwd/", "text": "cozy-stack config passwd \u00b6 Generate an admin passphrase Synopsis \u00b6 cozy-stack config passwd generates a passphrase hash and save it to the specified file. If no file is specified, it is directly printed in standard output. This passphrase is the one used to authenticate accesses to the administration API. The environment variable \u2018COZY_ADMIN_PASSPHRASE\u2019 can be used to pass the passphrase if needed. cozy-stack config passwd [flags] Examples \u00b6 $ cozy-stack config passwd ~/.cozy/cozy-admin-passphrase Options \u00b6 -h, --help help for passwd Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config passwd"}, {"location": "cozy-stack/cli/cozy-stack_config_passwd/#cozy-stack-config-passwd", "text": "Generate an admin passphrase", "title": "cozy-stack config passwd"}, {"location": "cozy-stack/cli/cozy-stack_config_passwd/#synopsis", "text": "cozy-stack config passwd generates a passphrase hash and save it to the specified file. If no file is specified, it is directly printed in standard output. This passphrase is the one used to authenticate accesses to the administration API. The environment variable \u2018COZY_ADMIN_PASSPHRASE\u2019 can be used to pass the passphrase if needed. cozy-stack config passwd [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config_passwd/#examples", "text": "$ cozy-stack config passwd ~/.cozy/cozy-admin-passphrase", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_config_passwd/#options", "text": "-h, --help help for passwd", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_passwd/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_passwd/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_rm-asset/", "text": "cozy-stack config rm-asset \u00b6 Removes an asset Synopsis \u00b6 Removes a custom asset in a specific context Deprecated: please use the command cozy-stack assets rm. cozy-stack config rm-asset [context] [name] [flags] Options \u00b6 -h, --help help for rm-asset Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config rm asset"}, {"location": "cozy-stack/cli/cozy-stack_config_rm-asset/#cozy-stack-config-rm-asset", "text": "Removes an asset", "title": "cozy-stack config rm-asset"}, {"location": "cozy-stack/cli/cozy-stack_config_rm-asset/#synopsis", "text": "Removes a custom asset in a specific context Deprecated: please use the command cozy-stack assets rm. cozy-stack config rm-asset [context] [name] [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_config_rm-asset/#options", "text": "-h, --help help for rm-asset", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_rm-asset/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_rm-asset/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_config_show-context/", "text": "cozy-stack config show-context \u00b6 Show a context cozy-stack config show-context [flags] Examples \u00b6 $ cozy-stack config show-context cozy_demo Options \u00b6 -h, --help help for show-context Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack config - Show and manage configuration elements", "title": "Cozy stack config show context"}, {"location": "cozy-stack/cli/cozy-stack_config_show-context/#cozy-stack-config-show-context", "text": "Show a context cozy-stack config show-context [flags]", "title": "cozy-stack config show-context"}, {"location": "cozy-stack/cli/cozy-stack_config_show-context/#examples", "text": "$ cozy-stack config show-context cozy_demo", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_config_show-context/#options", "text": "-h, --help help for show-context", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_config_show-context/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_config_show-context/#see-also", "text": "cozy-stack config - Show and manage configuration elements", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_doc/", "text": "cozy-stack doc \u00b6 Print the documentation Synopsis \u00b6 Print the documentation about the usage of cozy-stack in command-line cozy-stack doc [flags] Options \u00b6 -h, --help help for doc Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack doc man - Print the manpages of cozy-stack cozy-stack doc markdown - Print the documentation of cozy-stack as markdown", "title": "Cozy stack doc"}, {"location": "cozy-stack/cli/cozy-stack_doc/#cozy-stack-doc", "text": "Print the documentation", "title": "cozy-stack doc"}, {"location": "cozy-stack/cli/cozy-stack_doc/#synopsis", "text": "Print the documentation about the usage of cozy-stack in command-line cozy-stack doc [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_doc/#options", "text": "-h, --help help for doc", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_doc/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_doc/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack doc man - Print the manpages of cozy-stack cozy-stack doc markdown - Print the documentation of cozy-stack as markdown", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_doc_man/", "text": "cozy-stack doc man \u00b6 Print the manpages of cozy-stack Synopsis \u00b6 Print the manual pages for using cozy-stack in command-line cozy-stack doc man [flags] Examples \u00b6 $ mkdir -p ~/share/man $ export MANPATH = ~/share/man: $MANPATH $ cozy-stack doc man ~/share/man $ man cozy-stack Options \u00b6 -h, --help help for man Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack doc - Print the documentation", "title": "Cozy stack doc man"}, {"location": "cozy-stack/cli/cozy-stack_doc_man/#cozy-stack-doc-man", "text": "Print the manpages of cozy-stack", "title": "cozy-stack doc man"}, {"location": "cozy-stack/cli/cozy-stack_doc_man/#synopsis", "text": "Print the manual pages for using cozy-stack in command-line cozy-stack doc man [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_doc_man/#examples", "text": "$ mkdir -p ~/share/man $ export MANPATH = ~/share/man: $MANPATH $ cozy-stack doc man ~/share/man $ man cozy-stack", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_doc_man/#options", "text": "-h, --help help for man", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_doc_man/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_doc_man/#see-also", "text": "cozy-stack doc - Print the documentation", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_doc_markdown/", "text": "cozy-stack doc markdown \u00b6 Print the documentation of cozy-stack as markdown cozy-stack doc markdown [flags] Examples \u00b6 $ cozy-stack doc markdown docs/cli Options \u00b6 -h, --help help for markdown Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack doc - Print the documentation", "title": "Cozy stack doc markdown"}, {"location": "cozy-stack/cli/cozy-stack_doc_markdown/#cozy-stack-doc-markdown", "text": "Print the documentation of cozy-stack as markdown cozy-stack doc markdown [flags]", "title": "cozy-stack doc markdown"}, {"location": "cozy-stack/cli/cozy-stack_doc_markdown/#examples", "text": "$ cozy-stack doc markdown docs/cli", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_doc_markdown/#options", "text": "-h, --help help for markdown", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_doc_markdown/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_doc_markdown/#see-also", "text": "cozy-stack doc - Print the documentation", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_features/", "text": "cozy-stack features \u00b6 Manage the feature flags Options \u00b6 -h, --help help for features Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack features config - Display the feature flags from configuration for a context cozy-stack features defaults - Display and update the default values for feature flags cozy-stack features flags - Display and update the feature flags for an instance cozy-stack features ratio - Display and update the feature flags for a context cozy-stack features sets - Display and update the feature sets for an instance cozy-stack features show - Display the computed feature flags for an instance", "title": "Cozy stack features"}, {"location": "cozy-stack/cli/cozy-stack_features/#cozy-stack-features", "text": "Manage the feature flags", "title": "cozy-stack features"}, {"location": "cozy-stack/cli/cozy-stack_features/#options", "text": "-h, --help help for features", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_features/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_features/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack features config - Display the feature flags from configuration for a context cozy-stack features defaults - Display and update the default values for feature flags cozy-stack features flags - Display and update the feature flags for an instance cozy-stack features ratio - Display and update the feature flags for a context cozy-stack features sets - Display and update the feature sets for an instance cozy-stack features show - Display the computed feature flags for an instance", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_features_config/", "text": "cozy-stack features config \u00b6 Display the feature flags from configuration for a context Synopsis \u00b6 cozy-stack feature config displays the feature flags from configuration for a context. These flags are read only and can only be updated by changing configuration and restarting the stack. cozy-stack features config [flags] Examples \u00b6 $ cozy-stack feature config --context beta Options \u00b6 --context string The context for the feature flags -h, --help help for config Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack features - Manage the feature flags", "title": "Cozy stack features config"}, {"location": "cozy-stack/cli/cozy-stack_features_config/#cozy-stack-features-config", "text": "Display the feature flags from configuration for a context", "title": "cozy-stack features config"}, {"location": "cozy-stack/cli/cozy-stack_features_config/#synopsis", "text": "cozy-stack feature config displays the feature flags from configuration for a context. These flags are read only and can only be updated by changing configuration and restarting the stack. cozy-stack features config [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_features_config/#examples", "text": "$ cozy-stack feature config --context beta", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_features_config/#options", "text": "--context string The context for the feature flags -h, --help help for config", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_features_config/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_features_config/#see-also", "text": "cozy-stack features - Manage the feature flags", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_features_defaults/", "text": "cozy-stack features defaults \u00b6 Display and update the default values for feature flags Synopsis \u00b6 cozy-stack feature defaults displays the default values for feature flags. It can also take a list of flags to update. If you give a null value, the flag will be removed. cozy-stack features defaults [flags] Examples \u00b6 $ cozy-stack feature defaults '{\"add_this_flag\": true, \"remove_this_flag\": null}' Options \u00b6 -h, --help help for defaults Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack features - Manage the feature flags", "title": "Cozy stack features defaults"}, {"location": "cozy-stack/cli/cozy-stack_features_defaults/#cozy-stack-features-defaults", "text": "Display and update the default values for feature flags", "title": "cozy-stack features defaults"}, {"location": "cozy-stack/cli/cozy-stack_features_defaults/#synopsis", "text": "cozy-stack feature defaults displays the default values for feature flags. It can also take a list of flags to update. If you give a null value, the flag will be removed. cozy-stack features defaults [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_features_defaults/#examples", "text": "$ cozy-stack feature defaults '{\"add_this_flag\": true, \"remove_this_flag\": null}'", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_features_defaults/#options", "text": "-h, --help help for defaults", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_features_defaults/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_features_defaults/#see-also", "text": "cozy-stack features - Manage the feature flags", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_features_flags/", "text": "cozy-stack features flags \u00b6 Display and update the feature flags for an instance Synopsis \u00b6 cozy-stack feature flags displays the feature flags that are specific to an instance. It can also take a list of flags to update. If you give a null value, the flag will be removed. cozy-stack features flags [flags] Examples \u00b6 $ cozy-stack feature flags --domain cozy.localhost:8080 '{\"add_this_flag\": true, \"remove_this_flag\": null}' Options \u00b6 --domain string Specify the domain name of the instance -h, --help help for flags Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack features - Manage the feature flags", "title": "Cozy stack features flags"}, {"location": "cozy-stack/cli/cozy-stack_features_flags/#cozy-stack-features-flags", "text": "Display and update the feature flags for an instance", "title": "cozy-stack features flags"}, {"location": "cozy-stack/cli/cozy-stack_features_flags/#synopsis", "text": "cozy-stack feature flags displays the feature flags that are specific to an instance. It can also take a list of flags to update. If you give a null value, the flag will be removed. cozy-stack features flags [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_features_flags/#examples", "text": "$ cozy-stack feature flags --domain cozy.localhost:8080 '{\"add_this_flag\": true, \"remove_this_flag\": null}'", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_features_flags/#options", "text": "--domain string Specify the domain name of the instance -h, --help help for flags", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_features_flags/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_features_flags/#see-also", "text": "cozy-stack features - Manage the feature flags", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_features_ratio/", "text": "cozy-stack features ratio \u00b6 Display and update the feature flags for a context Synopsis \u00b6 cozy-stack feature ratio displays the feature flags for a context. It can also create, update, or remove flags (with a ratio and value). To remove a flag, set it to an empty array (or null). cozy-stack features ratio [flags] Examples \u00b6 $ cozy-stack feature ratio --context beta '{\"set_this_flag\": [{\"ratio\": 0.1, \"value\": 1}, {\"ratio\": 0.9, \"value\": 2}] }' Options \u00b6 --context string The context for the feature flags -h, --help help for ratio Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack features - Manage the feature flags", "title": "Cozy stack features ratio"}, {"location": "cozy-stack/cli/cozy-stack_features_ratio/#cozy-stack-features-ratio", "text": "Display and update the feature flags for a context", "title": "cozy-stack features ratio"}, {"location": "cozy-stack/cli/cozy-stack_features_ratio/#synopsis", "text": "cozy-stack feature ratio displays the feature flags for a context. It can also create, update, or remove flags (with a ratio and value). To remove a flag, set it to an empty array (or null). cozy-stack features ratio [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_features_ratio/#examples", "text": "$ cozy-stack feature ratio --context beta '{\"set_this_flag\": [{\"ratio\": 0.1, \"value\": 1}, {\"ratio\": 0.9, \"value\": 2}] }'", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_features_ratio/#options", "text": "--context string The context for the feature flags -h, --help help for ratio", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_features_ratio/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_features_ratio/#see-also", "text": "cozy-stack features - Manage the feature flags", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_features_sets/", "text": "cozy-stack features sets \u00b6 Display and update the feature sets for an instance Synopsis \u00b6 cozy-stack feature sets displays the feature sets coming from the manager. It can also take a space-separated list of sets that will replace the previous list (no merge). All the sets can be removed by setting an empty list (\u2018\u2019). cozy-stack features sets [flags] Examples \u00b6 $ cozy-stack feature sets --domain cozy.localhost:8080 'set1 set2' Options \u00b6 --domain string Specify the domain name of the instance -h, --help help for sets Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack features - Manage the feature flags", "title": "Cozy stack features sets"}, {"location": "cozy-stack/cli/cozy-stack_features_sets/#cozy-stack-features-sets", "text": "Display and update the feature sets for an instance", "title": "cozy-stack features sets"}, {"location": "cozy-stack/cli/cozy-stack_features_sets/#synopsis", "text": "cozy-stack feature sets displays the feature sets coming from the manager. It can also take a space-separated list of sets that will replace the previous list (no merge). All the sets can be removed by setting an empty list (\u2018\u2019). cozy-stack features sets [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_features_sets/#examples", "text": "$ cozy-stack feature sets --domain cozy.localhost:8080 'set1 set2'", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_features_sets/#options", "text": "--domain string Specify the domain name of the instance -h, --help help for sets", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_features_sets/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_features_sets/#see-also", "text": "cozy-stack features - Manage the feature flags", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_features_show/", "text": "cozy-stack features show \u00b6 Display the computed feature flags for an instance Synopsis \u00b6 cozy-stack feature show displays the feature flags that are shown by apps. cozy-stack features show [flags] Examples \u00b6 $ cozy-stack feature show --domain cozy.localhost:8080 Options \u00b6 --domain string Specify the domain name of the instance -h, --help help for show --source Show the sources of the feature flags Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack features - Manage the feature flags", "title": "Cozy stack features show"}, {"location": "cozy-stack/cli/cozy-stack_features_show/#cozy-stack-features-show", "text": "Display the computed feature flags for an instance", "title": "cozy-stack features show"}, {"location": "cozy-stack/cli/cozy-stack_features_show/#synopsis", "text": "cozy-stack feature show displays the feature flags that are shown by apps. cozy-stack features show [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_features_show/#examples", "text": "$ cozy-stack feature show --domain cozy.localhost:8080", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_features_show/#options", "text": "--domain string Specify the domain name of the instance -h, --help help for show --source Show the sources of the feature flags", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_features_show/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_features_show/#see-also", "text": "cozy-stack features - Manage the feature flags", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_files/", "text": "cozy-stack files \u00b6 Interact with the cozy filesystem Synopsis \u00b6 cozy-stack files allows to interact with the cozy filesystem. It provides command to create, move copy or delete files and directories inside your cozy instance, using the command line interface. It also provide an import command to import from your current filesystem into cozy. cozy-stack files [flags] Options \u00b6 --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for files Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack files exec - Execute the given command on the specified domain and leave cozy-stack files import - Import the specified file or directory into cozy cozy-stack files usage - Show the usage and quota for the files of this instance", "title": "Cozy stack files"}, {"location": "cozy-stack/cli/cozy-stack_files/#cozy-stack-files", "text": "Interact with the cozy filesystem", "title": "cozy-stack files"}, {"location": "cozy-stack/cli/cozy-stack_files/#synopsis", "text": "cozy-stack files allows to interact with the cozy filesystem. It provides command to create, move copy or delete files and directories inside your cozy instance, using the command line interface. It also provide an import command to import from your current filesystem into cozy. cozy-stack files [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_files/#options", "text": "--domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for files", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_files/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_files/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack files exec - Execute the given command on the specified domain and leave cozy-stack files import - Import the specified file or directory into cozy cozy-stack files usage - Show the usage and quota for the files of this instance", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_files_exec/", "text": "cozy-stack files exec \u00b6 Execute the given command on the specified domain and leave Synopsis \u00b6 Execute a command on the VFS of the specified domain. Available commands: mkdir Creates a directory with specified name ls [-l] [-a] [-h] Prints the children of the specified directory tree [-l] Prints the tree structure of the specified directory attrs Prints the attributes of the specified file or directory cat Echo the file content in stdout mv Rename a file or directory rm [-f] [-r] Move the file to trash, or delete it permanently with -f flag restore Restore a file or directory from trash Don't forget to put quotes around the command! cozy-stack files exec [--domain domain] [flags] Options \u00b6 -h, --help help for exec Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack files - Interact with the cozy filesystem", "title": "Cozy stack files exec"}, {"location": "cozy-stack/cli/cozy-stack_files_exec/#cozy-stack-files-exec", "text": "Execute the given command on the specified domain and leave", "title": "cozy-stack files exec"}, {"location": "cozy-stack/cli/cozy-stack_files_exec/#synopsis", "text": "Execute a command on the VFS of the specified domain. Available commands: mkdir Creates a directory with specified name ls [-l] [-a] [-h] Prints the children of the specified directory tree [-l] Prints the tree structure of the specified directory attrs Prints the attributes of the specified file or directory cat Echo the file content in stdout mv Rename a file or directory rm [-f] [-r] Move the file to trash, or delete it permanently with -f flag restore Restore a file or directory from trash Don't forget to put quotes around the command! cozy-stack files exec [--domain domain] [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_files_exec/#options", "text": "-h, --help help for exec", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_files_exec/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_files_exec/#see-also", "text": "cozy-stack files - Interact with the cozy filesystem", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_files_import/", "text": "cozy-stack files import \u00b6 Import the specified file or directory into cozy cozy - stack files import [ -- domain domain ] [ -- match pattern ] -- from < name > -- to < name > [ flags ] Options \u00b6 -- dry - run do not actually import the files -- from string directory to import from in cozy - h , -- help help for import -- match string pattern that the imported files must match -- to string directory to import to in cozy ( default \"/\" ) Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack files - Interact with the cozy filesystem", "title": "Cozy stack files import"}, {"location": "cozy-stack/cli/cozy-stack_files_import/#cozy-stack-files-import", "text": "Import the specified file or directory into cozy cozy - stack files import [ -- domain domain ] [ -- match pattern ] -- from < name > -- to < name > [ flags ]", "title": "cozy-stack files import"}, {"location": "cozy-stack/cli/cozy-stack_files_import/#options", "text": "-- dry - run do not actually import the files -- from string directory to import from in cozy - h , -- help help for import -- match string pattern that the imported files must match -- to string directory to import to in cozy ( default \"/\" )", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_files_import/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_files_import/#see-also", "text": "cozy-stack files - Interact with the cozy filesystem", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_files_usage/", "text": "cozy-stack files usage \u00b6 Show the usage and quota for the files of this instance cozy-stack files usage [--domain domain] [--trash] [flags] Options \u00b6 -h, --help help for usage --trash Include trashed files total size Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack files - Interact with the cozy filesystem", "title": "Cozy stack files usage"}, {"location": "cozy-stack/cli/cozy-stack_files_usage/#cozy-stack-files-usage", "text": "Show the usage and quota for the files of this instance cozy-stack files usage [--domain domain] [--trash] [flags]", "title": "cozy-stack files usage"}, {"location": "cozy-stack/cli/cozy-stack_files_usage/#options", "text": "-h, --help help for usage --trash Include trashed files total size", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_files_usage/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_files_usage/#see-also", "text": "cozy-stack files - Interact with the cozy filesystem", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix/", "text": "cozy-stack fix \u00b6 A set of tools to fix issues or migrate content. cozy-stack fix [flags] Options \u00b6 -h, --help help for fix Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack fix contact-emails - Detect and try to fix invalid emails on contacts cozy-stack fix indexes - Rebuild the CouchDB views and indexes cozy-stack fix jobs - Take a look at the consistency of the jobs cozy-stack fix mime - Fix the class computed from the mime-type cozy-stack fix orphan-account - Remove the orphan accounts cozy-stack fix password-defined - Set the password_defined setting cozy-stack fix redis - Rebuild scheduling data strucutures in redis cozy-stack fix service-triggers - Clean the triggers for webapp services cozy-stack fix thumbnails - Rebuild thumbnails image for images files", "title": "Cozy stack fix"}, {"location": "cozy-stack/cli/cozy-stack_fix/#cozy-stack-fix", "text": "A set of tools to fix issues or migrate content. cozy-stack fix [flags]", "title": "cozy-stack fix"}, {"location": "cozy-stack/cli/cozy-stack_fix/#options", "text": "-h, --help help for fix", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack fix contact-emails - Detect and try to fix invalid emails on contacts cozy-stack fix indexes - Rebuild the CouchDB views and indexes cozy-stack fix jobs - Take a look at the consistency of the jobs cozy-stack fix mime - Fix the class computed from the mime-type cozy-stack fix orphan-account - Remove the orphan accounts cozy-stack fix password-defined - Set the password_defined setting cozy-stack fix redis - Rebuild scheduling data strucutures in redis cozy-stack fix service-triggers - Clean the triggers for webapp services cozy-stack fix thumbnails - Rebuild thumbnails image for images files", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_contact-emails/", "text": "cozy-stack fix contact-emails \u00b6 Detect and try to fix invalid emails on contacts cozy-stack fix contact-emails [flags] Options \u00b6 -h, --help help for contact-emails Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix contact emails"}, {"location": "cozy-stack/cli/cozy-stack_fix_contact-emails/#cozy-stack-fix-contact-emails", "text": "Detect and try to fix invalid emails on contacts cozy-stack fix contact-emails [flags]", "title": "cozy-stack fix contact-emails"}, {"location": "cozy-stack/cli/cozy-stack_fix_contact-emails/#options", "text": "-h, --help help for contact-emails", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_contact-emails/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_contact-emails/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_indexes/", "text": "cozy-stack fix indexes \u00b6 Rebuild the CouchDB views and indexes Synopsis \u00b6 This fixer ensures that the CouchDB views and indexes used by the stack for this instance are correctly set. cozy-stack fix indexes [flags] Options \u00b6 -h, --help help for indexes Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix indexes"}, {"location": "cozy-stack/cli/cozy-stack_fix_indexes/#cozy-stack-fix-indexes", "text": "Rebuild the CouchDB views and indexes", "title": "cozy-stack fix indexes"}, {"location": "cozy-stack/cli/cozy-stack_fix_indexes/#synopsis", "text": "This fixer ensures that the CouchDB views and indexes used by the stack for this instance are correctly set. cozy-stack fix indexes [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_fix_indexes/#options", "text": "-h, --help help for indexes", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_indexes/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_indexes/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_jobs/", "text": "cozy-stack fix jobs \u00b6 Take a look at the consistency of the jobs cozy-stack fix jobs [flags] Options \u00b6 -h, --help help for jobs Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix jobs"}, {"location": "cozy-stack/cli/cozy-stack_fix_jobs/#cozy-stack-fix-jobs", "text": "Take a look at the consistency of the jobs cozy-stack fix jobs [flags]", "title": "cozy-stack fix jobs"}, {"location": "cozy-stack/cli/cozy-stack_fix_jobs/#options", "text": "-h, --help help for jobs", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_jobs/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_jobs/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_mime/", "text": "cozy-stack fix mime \u00b6 Fix the class computed from the mime-type cozy-stack fix mime [flags] Options \u00b6 -h, --help help for mime Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix mime"}, {"location": "cozy-stack/cli/cozy-stack_fix_mime/#cozy-stack-fix-mime", "text": "Fix the class computed from the mime-type cozy-stack fix mime [flags]", "title": "cozy-stack fix mime"}, {"location": "cozy-stack/cli/cozy-stack_fix_mime/#options", "text": "-h, --help help for mime", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_mime/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_mime/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_orphan-account/", "text": "cozy-stack fix orphan-account \u00b6 Remove the orphan accounts Synopsis \u00b6 This fixer detects the accounts that are linked to a konnector that has been uninstalled, and then removed them. For banking accounts, the konnector must run to also clean the account remotely. To do so, the konnector is installed, the account is deleted, the stack runs the konnector with the AccountDeleted flag, and when it\u2019s done, the konnector is uninstalled again. cozy-stack fix orphan-account [flags] Options \u00b6 -h, --help help for orphan-account Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix orphan account"}, {"location": "cozy-stack/cli/cozy-stack_fix_orphan-account/#cozy-stack-fix-orphan-account", "text": "Remove the orphan accounts", "title": "cozy-stack fix orphan-account"}, {"location": "cozy-stack/cli/cozy-stack_fix_orphan-account/#synopsis", "text": "This fixer detects the accounts that are linked to a konnector that has been uninstalled, and then removed them. For banking accounts, the konnector must run to also clean the account remotely. To do so, the konnector is installed, the account is deleted, the stack runs the konnector with the AccountDeleted flag, and when it\u2019s done, the konnector is uninstalled again. cozy-stack fix orphan-account [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_fix_orphan-account/#options", "text": "-h, --help help for orphan-account", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_orphan-account/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_orphan-account/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_password-defined/", "text": "cozy-stack fix password-defined \u00b6 Set the password_defined setting Synopsis \u00b6 A password_defined field has been added to the io.cozy.settings.instance (available on GET /settings/instance). This fixer can fill it for existing Cozy instances if it was missing. cozy-stack fix password-defined [flags] Options \u00b6 -h, --help help for password-defined Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix password defined"}, {"location": "cozy-stack/cli/cozy-stack_fix_password-defined/#cozy-stack-fix-password-defined", "text": "Set the password_defined setting", "title": "cozy-stack fix password-defined"}, {"location": "cozy-stack/cli/cozy-stack_fix_password-defined/#synopsis", "text": "A password_defined field has been added to the io.cozy.settings.instance (available on GET /settings/instance). This fixer can fill it for existing Cozy instances if it was missing. cozy-stack fix password-defined [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_fix_password-defined/#options", "text": "-h, --help help for password-defined", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_password-defined/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_password-defined/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_redis/", "text": "cozy-stack fix redis \u00b6 Rebuild scheduling data strucutures in redis cozy-stack fix redis [flags] Options \u00b6 --force Do not ask for confirmation before fixing redis on all instances -h, --help help for redis Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix redis"}, {"location": "cozy-stack/cli/cozy-stack_fix_redis/#cozy-stack-fix-redis", "text": "Rebuild scheduling data strucutures in redis cozy-stack fix redis [flags]", "title": "cozy-stack fix redis"}, {"location": "cozy-stack/cli/cozy-stack_fix_redis/#options", "text": "--force Do not ask for confirmation before fixing redis on all instances -h, --help help for redis", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_redis/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_redis/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_service-triggers/", "text": "cozy-stack fix service-triggers \u00b6 Clean the triggers for webapp services Synopsis \u00b6 This fixer cleans duplicate triggers for webapp services, and recreates missing triggers. cozy-stack fix service-triggers [flags] Options \u00b6 -h, --help help for service-triggers Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix service triggers"}, {"location": "cozy-stack/cli/cozy-stack_fix_service-triggers/#cozy-stack-fix-service-triggers", "text": "Clean the triggers for webapp services", "title": "cozy-stack fix service-triggers"}, {"location": "cozy-stack/cli/cozy-stack_fix_service-triggers/#synopsis", "text": "This fixer cleans duplicate triggers for webapp services, and recreates missing triggers. cozy-stack fix service-triggers [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_fix_service-triggers/#options", "text": "-h, --help help for service-triggers", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_service-triggers/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_service-triggers/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_fix_thumbnails/", "text": "cozy-stack fix thumbnails \u00b6 Rebuild thumbnails image for images files cozy-stack fix thumbnails [flags] Options \u00b6 --dry-run Dry run -h, --help help for thumbnails --with-metadata Recalculate images metadata Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "Cozy stack fix thumbnails"}, {"location": "cozy-stack/cli/cozy-stack_fix_thumbnails/#cozy-stack-fix-thumbnails", "text": "Rebuild thumbnails image for images files cozy-stack fix thumbnails [flags]", "title": "cozy-stack fix thumbnails"}, {"location": "cozy-stack/cli/cozy-stack_fix_thumbnails/#options", "text": "--dry-run Dry run -h, --help help for thumbnails --with-metadata Recalculate images metadata", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_fix_thumbnails/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_fix_thumbnails/#see-also", "text": "cozy-stack fix - A set of tools to fix issues or migrate content.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances/", "text": "cozy-stack instances \u00b6 Manage instances of a stack Synopsis \u00b6 cozy-stack instances allows to manage the instances of this stack An instance is a logical space owned by one user and identified by a domain. For example, bob.cozycloud.cc is the instance of Bob. A single cozy-stack process can manage several instances. Each instance has a separate space for storing files and a prefix used to create its CouchDB databases. cozy-stack instances [flags] Options \u00b6 -h, --help help for instances Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack instances add - Manage instances of a stack cozy-stack instances auth-mode - Set instance auth-mode cozy-stack instances clean-sessions - Remove the io.cozy.sessions and io.cozy.sessions.logins bases cozy-stack instances client-oauth - Register a new OAuth client cozy-stack instances count - Count the instances cozy-stack instances debug - Activate or deactivate debugging of the instance cozy-stack instances destroy - Remove instance cozy-stack instances export - Export an instance cozy-stack instances find-oauth-client - Find an OAuth client cozy-stack instances fsck - Check a vfs cozy-stack instances import - Import data from an export link cozy-stack instances ls - List instances cozy-stack instances modify - Modify the instance properties cozy-stack instances refresh-token-oauth - Generate a new OAuth refresh token cozy-stack instances set-disk-quota - Change the disk-quota of the instance cozy-stack instances set-passphrase - Change the passphrase of the instance cozy-stack instances show - Show the instance of the specified domain cozy-stack instances show-app-version - Show instances that have a particular app version cozy-stack instances show-db-prefix - Show the instance DB prefix of the specified domain cozy-stack instances show-swift-prefix - Show the instance swift prefix of the specified domain cozy-stack instances token-app - Generate a new application token cozy-stack instances token-cli - Generate a new CLI access token (global access) cozy-stack instances token-konnector - Generate a new konnector token cozy-stack instances token-oauth - Generate a new OAuth access token", "title": "Cozy stack instances"}, {"location": "cozy-stack/cli/cozy-stack_instances/#cozy-stack-instances", "text": "Manage instances of a stack", "title": "cozy-stack instances"}, {"location": "cozy-stack/cli/cozy-stack_instances/#synopsis", "text": "cozy-stack instances allows to manage the instances of this stack An instance is a logical space owned by one user and identified by a domain. For example, bob.cozycloud.cc is the instance of Bob. A single cozy-stack process can manage several instances. Each instance has a separate space for storing files and a prefix used to create its CouchDB databases. cozy-stack instances [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances/#options", "text": "-h, --help help for instances", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack instances add - Manage instances of a stack cozy-stack instances auth-mode - Set instance auth-mode cozy-stack instances clean-sessions - Remove the io.cozy.sessions and io.cozy.sessions.logins bases cozy-stack instances client-oauth - Register a new OAuth client cozy-stack instances count - Count the instances cozy-stack instances debug - Activate or deactivate debugging of the instance cozy-stack instances destroy - Remove instance cozy-stack instances export - Export an instance cozy-stack instances find-oauth-client - Find an OAuth client cozy-stack instances fsck - Check a vfs cozy-stack instances import - Import data from an export link cozy-stack instances ls - List instances cozy-stack instances modify - Modify the instance properties cozy-stack instances refresh-token-oauth - Generate a new OAuth refresh token cozy-stack instances set-disk-quota - Change the disk-quota of the instance cozy-stack instances set-passphrase - Change the passphrase of the instance cozy-stack instances show - Show the instance of the specified domain cozy-stack instances show-app-version - Show instances that have a particular app version cozy-stack instances show-db-prefix - Show the instance DB prefix of the specified domain cozy-stack instances show-swift-prefix - Show the instance swift prefix of the specified domain cozy-stack instances token-app - Generate a new application token cozy-stack instances token-cli - Generate a new CLI access token (global access) cozy-stack instances token-konnector - Generate a new konnector token cozy-stack instances token-oauth - Generate a new OAuth access token", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_add/", "text": "cozy-stack instances add \u00b6 Manage instances of a stack Synopsis \u00b6 cozy-stack instances add allows to create an instance on the cozy for a given domain. If the COZY_DISABLE_INSTANCES_ADD_RM env variable is set, creating and destroying instances will be disabled and the content of this variable will be used as the error message. cozy-stack instances add [flags] Examples \u00b6 $ cozy-stack instances add --passphrase cozy --apps drive,photos,settings,home,store cozy.localhost:8080 Options \u00b6 --apps strings Apps to be preinstalled --context-name string Context name of the instance --couch-cluster int Specify the CouchDB cluster where the instance will be created (-1 means the default) (default -1) --dev To create a development instance (deprecated) --disk-quota string The quota allowed to the instance's VFS --domain-aliases strings Specify one or more aliases domain for the instance (separated by ',') --email string The email of the owner --franceconnect_id string The identifier for checking authentication with FranceConnect -h, --help help for add --locale string Locale of the new cozy instance (default \"en\") --magic_link Enable authentication with magic links sent by email --oidc_id string The identifier for checking authentication from OIDC --passphrase string Register the instance with this passphrase (useful for tests) --public-name string The public name of the owner --settings string A list of settings (eg context:foo,offer:premium) --sponsorships strings Sponsorships of the instance (comma separated list) --swift-layout int Specify the layout to use for Swift (from 0 for layout V1 to 2 for layout V3, -1 means the default) (default -1) --tos string The TOS version signed --trace Show where time is spent --tz string The timezone for the user --uuid string The UUID of the instance Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances add"}, {"location": "cozy-stack/cli/cozy-stack_instances_add/#cozy-stack-instances-add", "text": "Manage instances of a stack", "title": "cozy-stack instances add"}, {"location": "cozy-stack/cli/cozy-stack_instances_add/#synopsis", "text": "cozy-stack instances add allows to create an instance on the cozy for a given domain. If the COZY_DISABLE_INSTANCES_ADD_RM env variable is set, creating and destroying instances will be disabled and the content of this variable will be used as the error message. cozy-stack instances add [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_add/#examples", "text": "$ cozy-stack instances add --passphrase cozy --apps drive,photos,settings,home,store cozy.localhost:8080", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_add/#options", "text": "--apps strings Apps to be preinstalled --context-name string Context name of the instance --couch-cluster int Specify the CouchDB cluster where the instance will be created (-1 means the default) (default -1) --dev To create a development instance (deprecated) --disk-quota string The quota allowed to the instance's VFS --domain-aliases strings Specify one or more aliases domain for the instance (separated by ',') --email string The email of the owner --franceconnect_id string The identifier for checking authentication with FranceConnect -h, --help help for add --locale string Locale of the new cozy instance (default \"en\") --magic_link Enable authentication with magic links sent by email --oidc_id string The identifier for checking authentication from OIDC --passphrase string Register the instance with this passphrase (useful for tests) --public-name string The public name of the owner --settings string A list of settings (eg context:foo,offer:premium) --sponsorships strings Sponsorships of the instance (comma separated list) --swift-layout int Specify the layout to use for Swift (from 0 for layout V1 to 2 for layout V3, -1 means the default) (default -1) --tos string The TOS version signed --trace Show where time is spent --tz string The timezone for the user --uuid string The UUID of the instance", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_add/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_add/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_auth-mode/", "text": "cozy-stack instances auth-mode \u00b6 Set instance auth-mode Synopsis \u00b6 Change the authentication mode for an instance. Two options are allowed: - two_factor_mail - basic cozy-stack instances auth-mode [domain] [auth-mode] [flags] Examples \u00b6 $ cozy-stack instances auth-mode cozy.localhost:8080 two_factor_mail Options \u00b6 -h, --help help for auth-mode Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances auth mode"}, {"location": "cozy-stack/cli/cozy-stack_instances_auth-mode/#cozy-stack-instances-auth-mode", "text": "Set instance auth-mode", "title": "cozy-stack instances auth-mode"}, {"location": "cozy-stack/cli/cozy-stack_instances_auth-mode/#synopsis", "text": "Change the authentication mode for an instance. Two options are allowed: - two_factor_mail - basic cozy-stack instances auth-mode [domain] [auth-mode] [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_auth-mode/#examples", "text": "$ cozy-stack instances auth-mode cozy.localhost:8080 two_factor_mail", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_auth-mode/#options", "text": "-h, --help help for auth-mode", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_auth-mode/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_auth-mode/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_clean-sessions/", "text": "cozy-stack instances clean-sessions \u00b6 Remove the io.cozy.sessions and io.cozy.sessions.logins bases cozy-stack instances clean-sessions [flags] Examples \u00b6 $ cozy-stack instance clean-sessions cozy.localhost:8080 Options \u00b6 -h, --help help for clean-sessions Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances clean sessions"}, {"location": "cozy-stack/cli/cozy-stack_instances_clean-sessions/#cozy-stack-instances-clean-sessions", "text": "Remove the io.cozy.sessions and io.cozy.sessions.logins bases cozy-stack instances clean-sessions [flags]", "title": "cozy-stack instances clean-sessions"}, {"location": "cozy-stack/cli/cozy-stack_instances_clean-sessions/#examples", "text": "$ cozy-stack instance clean-sessions cozy.localhost:8080", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_clean-sessions/#options", "text": "-h, --help help for clean-sessions", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_clean-sessions/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_clean-sessions/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_client-oauth/", "text": "cozy-stack instances client-oauth \u00b6 Register a new OAuth client Synopsis \u00b6 It registers a new OAuth client and returns its client_id cozy-stack instances client-oauth [flags] Options \u00b6 --allow-login-scope Allow login scope -h, --help help for client-oauth --json Output more informations in JSON format --onboarding-app string Specify an OnboardingApp --onboarding-permissions string Specify an OnboardingPermissions --onboarding-secret string Specify an OnboardingSecret --onboarding-state string Specify an OnboardingState Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances client oauth"}, {"location": "cozy-stack/cli/cozy-stack_instances_client-oauth/#cozy-stack-instances-client-oauth", "text": "Register a new OAuth client", "title": "cozy-stack instances client-oauth"}, {"location": "cozy-stack/cli/cozy-stack_instances_client-oauth/#synopsis", "text": "It registers a new OAuth client and returns its client_id cozy-stack instances client-oauth [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_client-oauth/#options", "text": "--allow-login-scope Allow login scope -h, --help help for client-oauth --json Output more informations in JSON format --onboarding-app string Specify an OnboardingApp --onboarding-permissions string Specify an OnboardingPermissions --onboarding-secret string Specify an OnboardingSecret --onboarding-state string Specify an OnboardingState", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_client-oauth/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_client-oauth/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_count/", "text": "cozy-stack instances count \u00b6 Count the instances cozy-stack instances count [flags] Examples \u00b6 $ cozy-stack instances count Options \u00b6 -h, --help help for count Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances count"}, {"location": "cozy-stack/cli/cozy-stack_instances_count/#cozy-stack-instances-count", "text": "Count the instances cozy-stack instances count [flags]", "title": "cozy-stack instances count"}, {"location": "cozy-stack/cli/cozy-stack_instances_count/#examples", "text": "$ cozy-stack instances count", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_count/#options", "text": "-h, --help help for count", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_count/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_count/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_debug/", "text": "cozy-stack instances debug \u00b6 Activate or deactivate debugging of the instance Synopsis \u00b6 cozy-stack instances debug allows to activate or deactivate the debugging of a specific domain. cozy-stack instances debug [flags] Examples \u00b6 $ cozy-stack instances debug --domain cozy.localhost:8080 true Options \u00b6 --domain string Specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for debug --ttl duration Specify how long the debug mode will last (default 24h0m0s) Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances debug"}, {"location": "cozy-stack/cli/cozy-stack_instances_debug/#cozy-stack-instances-debug", "text": "Activate or deactivate debugging of the instance", "title": "cozy-stack instances debug"}, {"location": "cozy-stack/cli/cozy-stack_instances_debug/#synopsis", "text": "cozy-stack instances debug allows to activate or deactivate the debugging of a specific domain. cozy-stack instances debug [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_debug/#examples", "text": "$ cozy-stack instances debug --domain cozy.localhost:8080 true", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_debug/#options", "text": "--domain string Specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for debug --ttl duration Specify how long the debug mode will last (default 24h0m0s)", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_debug/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_debug/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_destroy/", "text": "cozy-stack instances destroy \u00b6 Remove instance Synopsis \u00b6 cozy-stack instances destroy allows to remove an instance and all its data. cozy-stack instances destroy [flags] Options \u00b6 --force Force the deletion without asking for confirmation -h, --help help for destroy Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances destroy"}, {"location": "cozy-stack/cli/cozy-stack_instances_destroy/#cozy-stack-instances-destroy", "text": "Remove instance", "title": "cozy-stack instances destroy"}, {"location": "cozy-stack/cli/cozy-stack_instances_destroy/#synopsis", "text": "cozy-stack instances destroy allows to remove an instance and all its data. cozy-stack instances destroy [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_destroy/#options", "text": "--force Force the deletion without asking for confirmation -h, --help help for destroy", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_destroy/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_destroy/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_export/", "text": "cozy-stack instances export \u00b6 Export an instance Synopsis \u00b6 Export the files, documents, and settings cozy-stack instances export [flags] Options \u00b6 --domain string Specify the domain name of the instance -h, --help help for export --path string Specify the local path where to store the export archive Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances export"}, {"location": "cozy-stack/cli/cozy-stack_instances_export/#cozy-stack-instances-export", "text": "Export an instance", "title": "cozy-stack instances export"}, {"location": "cozy-stack/cli/cozy-stack_instances_export/#synopsis", "text": "Export the files, documents, and settings cozy-stack instances export [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_export/#options", "text": "--domain string Specify the domain name of the instance -h, --help help for export --path string Specify the local path where to store the export archive", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_export/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_export/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_find-oauth-client/", "text": "cozy-stack instances find-oauth-client \u00b6 Find an OAuth client Synopsis \u00b6 Search an OAuth client from its SoftwareID cozy-stack instances find-oauth-client [flags] Options \u00b6 -h, --help help for find-oauth-client Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances find oauth client"}, {"location": "cozy-stack/cli/cozy-stack_instances_find-oauth-client/#cozy-stack-instances-find-oauth-client", "text": "Find an OAuth client", "title": "cozy-stack instances find-oauth-client"}, {"location": "cozy-stack/cli/cozy-stack_instances_find-oauth-client/#synopsis", "text": "Search an OAuth client from its SoftwareID cozy-stack instances find-oauth-client [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_find-oauth-client/#options", "text": "-h, --help help for find-oauth-client", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_find-oauth-client/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_find-oauth-client/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_fsck/", "text": "cozy-stack instances fsck \u00b6 Check a vfs Synopsis \u00b6 The cozy-stack fsck command checks that the files in the VFS are not desynchronized, ie a file present in CouchDB but not swift/localfs, or present in swift/localfs but not couchdb. There are 2 steps: index integrity checks that there are nothing wrong in the index (CouchDB), like a file present in a directory that has been deleted files consistency checks that the files are the same in the index (CouchDB) and the storage (Swift or localfs). By default, both operations are done, but you can choose one or the other via the flags. cozy-stack instances fsck [flags] Options \u00b6 --fail-fast Stop the FSCK on the first error --files-consistency Check the files consistency only (between CouchDB and Swift) -h, --help help for fsck --index-integrity Check the index integrity only --json Output more informations in JSON format Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances fsck"}, {"location": "cozy-stack/cli/cozy-stack_instances_fsck/#cozy-stack-instances-fsck", "text": "Check a vfs", "title": "cozy-stack instances fsck"}, {"location": "cozy-stack/cli/cozy-stack_instances_fsck/#synopsis", "text": "The cozy-stack fsck command checks that the files in the VFS are not desynchronized, ie a file present in CouchDB but not swift/localfs, or present in swift/localfs but not couchdb. There are 2 steps: index integrity checks that there are nothing wrong in the index (CouchDB), like a file present in a directory that has been deleted files consistency checks that the files are the same in the index (CouchDB) and the storage (Swift or localfs). By default, both operations are done, but you can choose one or the other via the flags. cozy-stack instances fsck [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_fsck/#options", "text": "--fail-fast Stop the FSCK on the first error --files-consistency Check the files consistency only (between CouchDB and Swift) -h, --help help for fsck --index-integrity Check the index integrity only --json Output more informations in JSON format", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_fsck/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_fsck/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_import/", "text": "cozy-stack instances import \u00b6 Import data from an export link Synopsis \u00b6 This command will reset the Cozy instance and import data from an export link cozy - stack instances import < URL > [ flags ] Options \u00b6 -- domain string Specify the domain name of the instance -- force Force the import without asking for confirmation - h , -- help help for import Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances import"}, {"location": "cozy-stack/cli/cozy-stack_instances_import/#cozy-stack-instances-import", "text": "Import data from an export link", "title": "cozy-stack instances import"}, {"location": "cozy-stack/cli/cozy-stack_instances_import/#synopsis", "text": "This command will reset the Cozy instance and import data from an export link cozy - stack instances import < URL > [ flags ]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_import/#options", "text": "-- domain string Specify the domain name of the instance -- force Force the import without asking for confirmation - h , -- help help for import", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_import/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_import/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_ls/", "text": "cozy-stack instances ls \u00b6 List instances Synopsis \u00b6 cozy-stack instances ls allows to list all the instances that can be served by this server. cozy-stack instances ls [flags] Examples \u00b6 $ cozy-stack instances ls Options \u00b6 --available-fields List available fields for --fields option --fields strings Arguments shown for each line in the list -h, --help help for ls --json Show each line as a json representation of the instance Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances ls"}, {"location": "cozy-stack/cli/cozy-stack_instances_ls/#cozy-stack-instances-ls", "text": "List instances", "title": "cozy-stack instances ls"}, {"location": "cozy-stack/cli/cozy-stack_instances_ls/#synopsis", "text": "cozy-stack instances ls allows to list all the instances that can be served by this server. cozy-stack instances ls [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_ls/#examples", "text": "$ cozy-stack instances ls", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_ls/#options", "text": "--available-fields List available fields for --fields option --fields strings Arguments shown for each line in the list -h, --help help for ls --json Show each line as a json representation of the instance", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_ls/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_ls/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_modify/", "text": "cozy-stack instances modify \u00b6 Modify the instance properties Synopsis \u00b6 cozy-stack instances modify allows to change the instance properties and settings for a specified domain. cozy-stack instances modify [flags] Options \u00b6 --blocked Block the instance --blocking-reason string Code that explains why the instance is blocked (PAYMENT_FAILED, LOGIN_FAILED, etc.) --context-name string New context name --deleting --deleting=false Set (or remove) the deleting flag (ex: --deleting=false) --disk-quota string Specify a new disk quota --domain-aliases strings Specify one or more aliases domain for the instance (separated by ',') --email string New email --franceconnect_id string The identifier for checking authentication with FranceConnect -h, --help help for modify --locale string New locale --magic_link Enable authentication with magic links sent by email --oidc_id string New identifier for checking authentication from OIDC --onboarding-finished Force the finishing of the onboarding --public-name string New public name --settings string New list of settings (eg offer:premium) --sponsorships strings Sponsorships of the instance (comma separated list) --tos string Update the TOS version signed --tos-latest string Update the latest TOS version --tz string New timezone --uuid string New UUID Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances modify"}, {"location": "cozy-stack/cli/cozy-stack_instances_modify/#cozy-stack-instances-modify", "text": "Modify the instance properties", "title": "cozy-stack instances modify"}, {"location": "cozy-stack/cli/cozy-stack_instances_modify/#synopsis", "text": "cozy-stack instances modify allows to change the instance properties and settings for a specified domain. cozy-stack instances modify [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_modify/#options", "text": "--blocked Block the instance --blocking-reason string Code that explains why the instance is blocked (PAYMENT_FAILED, LOGIN_FAILED, etc.) --context-name string New context name --deleting --deleting=false Set (or remove) the deleting flag (ex: --deleting=false) --disk-quota string Specify a new disk quota --domain-aliases strings Specify one or more aliases domain for the instance (separated by ',') --email string New email --franceconnect_id string The identifier for checking authentication with FranceConnect -h, --help help for modify --locale string New locale --magic_link Enable authentication with magic links sent by email --oidc_id string New identifier for checking authentication from OIDC --onboarding-finished Force the finishing of the onboarding --public-name string New public name --settings string New list of settings (eg offer:premium) --sponsorships strings Sponsorships of the instance (comma separated list) --tos string Update the TOS version signed --tos-latest string Update the latest TOS version --tz string New timezone --uuid string New UUID", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_modify/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_modify/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_refresh-token-oauth/", "text": "cozy-stack instances refresh-token-oauth \u00b6 Generate a new OAuth refresh token cozy-stack instances refresh-token-oauth [flags] Examples \u00b6 $ cozy-stack instances refresh-token-oauth cozy.localhost:8080 727e677187a51d14ccd59cc0bd000a1d io.cozy.files io.cozy.jobs:POST:sendmail:worker Options \u00b6 -h, --help help for refresh-token-oauth Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances refresh token oauth"}, {"location": "cozy-stack/cli/cozy-stack_instances_refresh-token-oauth/#cozy-stack-instances-refresh-token-oauth", "text": "Generate a new OAuth refresh token cozy-stack instances refresh-token-oauth [flags]", "title": "cozy-stack instances refresh-token-oauth"}, {"location": "cozy-stack/cli/cozy-stack_instances_refresh-token-oauth/#examples", "text": "$ cozy-stack instances refresh-token-oauth cozy.localhost:8080 727e677187a51d14ccd59cc0bd000a1d io.cozy.files io.cozy.jobs:POST:sendmail:worker", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_refresh-token-oauth/#options", "text": "-h, --help help for refresh-token-oauth", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_refresh-token-oauth/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_refresh-token-oauth/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-disk-quota/", "text": "cozy-stack instances set-disk-quota \u00b6 Change the disk-quota of the instance Synopsis \u00b6 cozy-stack instances set-disk-quota allows to change the disk-quota of the instance of the given domain. Set the quota to 0 to remove the quota. cozy-stack instances set-disk-quota [flags] Examples \u00b6 $ cozy-stack instances set-disk-quota cozy.localhost:8080 3GB Options \u00b6 -h, --help help for set-disk-quota Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances set disk quota"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-disk-quota/#cozy-stack-instances-set-disk-quota", "text": "Change the disk-quota of the instance", "title": "cozy-stack instances set-disk-quota"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-disk-quota/#synopsis", "text": "cozy-stack instances set-disk-quota allows to change the disk-quota of the instance of the given domain. Set the quota to 0 to remove the quota. cozy-stack instances set-disk-quota [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-disk-quota/#examples", "text": "$ cozy-stack instances set-disk-quota cozy.localhost:8080 3GB", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-disk-quota/#options", "text": "-h, --help help for set-disk-quota", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-disk-quota/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-disk-quota/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-passphrase/", "text": "cozy-stack instances set-passphrase \u00b6 Change the passphrase of the instance cozy-stack instances set-passphrase [flags] Examples \u00b6 $ cozy-stack instances set-passphrase cozy.localhost:8080 myN3wP4ssowrd! Options \u00b6 -h, --help help for set-passphrase Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances set passphrase"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-passphrase/#cozy-stack-instances-set-passphrase", "text": "Change the passphrase of the instance cozy-stack instances set-passphrase [flags]", "title": "cozy-stack instances set-passphrase"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-passphrase/#examples", "text": "$ cozy-stack instances set-passphrase cozy.localhost:8080 myN3wP4ssowrd!", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-passphrase/#options", "text": "-h, --help help for set-passphrase", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-passphrase/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_set-passphrase/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-app-version/", "text": "cozy-stack instances show-app-version \u00b6 Show instances that have a particular app version cozy-stack instances show-app-version [app-slug] [version] [flags] Examples \u00b6 $ cozy-stack instances show-app-version drive 1 .0.1 Options \u00b6 -h, --help help for show-app-version Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances show app version"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-app-version/#cozy-stack-instances-show-app-version", "text": "Show instances that have a particular app version cozy-stack instances show-app-version [app-slug] [version] [flags]", "title": "cozy-stack instances show-app-version"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-app-version/#examples", "text": "$ cozy-stack instances show-app-version drive 1 .0.1", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-app-version/#options", "text": "-h, --help help for show-app-version", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-app-version/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-app-version/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-db-prefix/", "text": "cozy-stack instances show-db-prefix \u00b6 Show the instance DB prefix of the specified domain Synopsis \u00b6 cozy-stack instances show allows to show the instance prefix on the cozy for a given domain. The prefix is used for databases and VFS prefixing. It will also show the couch_cluster if it is not the default one. cozy-stack instances show-db-prefix [flags] Examples \u00b6 $ cozy-stack instances show-db-prefix cozy.localhost:8080 Options \u00b6 -h, --help help for show-db-prefix Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances show db prefix"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-db-prefix/#cozy-stack-instances-show-db-prefix", "text": "Show the instance DB prefix of the specified domain", "title": "cozy-stack instances show-db-prefix"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-db-prefix/#synopsis", "text": "cozy-stack instances show allows to show the instance prefix on the cozy for a given domain. The prefix is used for databases and VFS prefixing. It will also show the couch_cluster if it is not the default one. cozy-stack instances show-db-prefix [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-db-prefix/#examples", "text": "$ cozy-stack instances show-db-prefix cozy.localhost:8080", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-db-prefix/#options", "text": "-h, --help help for show-db-prefix", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-db-prefix/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-db-prefix/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-swift-prefix/", "text": "cozy-stack instances show-swift-prefix \u00b6 Show the instance swift prefix of the specified domain cozy-stack instances show-swift-prefix [flags] Examples \u00b6 $ cozy-stack instances show-swift-prefix cozy.localhost:8080 Options \u00b6 -h, --help help for show-swift-prefix Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances show swift prefix"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-swift-prefix/#cozy-stack-instances-show-swift-prefix", "text": "Show the instance swift prefix of the specified domain cozy-stack instances show-swift-prefix [flags]", "title": "cozy-stack instances show-swift-prefix"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-swift-prefix/#examples", "text": "$ cozy-stack instances show-swift-prefix cozy.localhost:8080", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-swift-prefix/#options", "text": "-h, --help help for show-swift-prefix", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-swift-prefix/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_show-swift-prefix/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_show/", "text": "cozy-stack instances show \u00b6 Show the instance of the specified domain Synopsis \u00b6 cozy-stack instances show allows to show the instance on the cozy for a given domain. cozy-stack instances show [flags] Examples \u00b6 $ cozy-stack instances show cozy.localhost:8080 Options \u00b6 -h, --help help for show Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances show"}, {"location": "cozy-stack/cli/cozy-stack_instances_show/#cozy-stack-instances-show", "text": "Show the instance of the specified domain", "title": "cozy-stack instances show"}, {"location": "cozy-stack/cli/cozy-stack_instances_show/#synopsis", "text": "cozy-stack instances show allows to show the instance on the cozy for a given domain. cozy-stack instances show [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_instances_show/#examples", "text": "$ cozy-stack instances show cozy.localhost:8080", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_show/#options", "text": "-h, --help help for show", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_show/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_show/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-app/", "text": "cozy-stack instances token-app \u00b6 Generate a new application token cozy-stack instances token-app [flags] Options \u00b6 --expire duration Make the token expires in this amount of time -h, --help help for token-app Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances token app"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-app/#cozy-stack-instances-token-app", "text": "Generate a new application token cozy-stack instances token-app [flags]", "title": "cozy-stack instances token-app"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-app/#options", "text": "--expire duration Make the token expires in this amount of time -h, --help help for token-app", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-app/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-app/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-cli/", "text": "cozy-stack instances token-cli \u00b6 Generate a new CLI access token (global access) cozy-stack instances token-cli [flags] Options \u00b6 -h, --help help for token-cli Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances token cli"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-cli/#cozy-stack-instances-token-cli", "text": "Generate a new CLI access token (global access) cozy-stack instances token-cli [flags]", "title": "cozy-stack instances token-cli"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-cli/#options", "text": "-h, --help help for token-cli", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-cli/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-cli/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-konnector/", "text": "cozy-stack instances token-konnector \u00b6 Generate a new konnector token cozy-stack instances token-konnector [flags] Options \u00b6 -h, --help help for token-konnector Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances token konnector"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-konnector/#cozy-stack-instances-token-konnector", "text": "Generate a new konnector token cozy-stack instances token-konnector [flags]", "title": "cozy-stack instances token-konnector"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-konnector/#options", "text": "-h, --help help for token-konnector", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-konnector/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-konnector/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-oauth/", "text": "cozy-stack instances token-oauth \u00b6 Generate a new OAuth access token cozy-stack instances token-oauth [flags] Examples \u00b6 $ cozy-stack instances token-oauth cozy.localhost:8080 727e677187a51d14ccd59cc0bd000a1d io.cozy.files io.cozy.jobs:POST:sendmail:worker Options \u00b6 --expire duration Make the token expires in this amount of time, as a duration string, e.g. \"1h\" -h, --help help for token-oauth Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack instances - Manage instances of a stack", "title": "Cozy stack instances token oauth"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-oauth/#cozy-stack-instances-token-oauth", "text": "Generate a new OAuth access token cozy-stack instances token-oauth [flags]", "title": "cozy-stack instances token-oauth"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-oauth/#examples", "text": "$ cozy-stack instances token-oauth cozy.localhost:8080 727e677187a51d14ccd59cc0bd000a1d io.cozy.files io.cozy.jobs:POST:sendmail:worker", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-oauth/#options", "text": "--expire duration Make the token expires in this amount of time, as a duration string, e.g. \"1h\" -h, --help help for token-oauth", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-oauth/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_instances_token-oauth/#see-also", "text": "cozy-stack instances - Manage instances of a stack", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_jobs/", "text": "cozy-stack jobs \u00b6 Launch and manage jobs and workers Options \u00b6 --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for jobs Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack jobs purge-old-jobs - Purge old jobs from an instance cozy-stack jobs run -", "title": "Cozy stack jobs"}, {"location": "cozy-stack/cli/cozy-stack_jobs/#cozy-stack-jobs", "text": "Launch and manage jobs and workers", "title": "cozy-stack jobs"}, {"location": "cozy-stack/cli/cozy-stack_jobs/#options", "text": "--domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for jobs", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_jobs/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_jobs/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack jobs purge-old-jobs - Purge old jobs from an instance cozy-stack jobs run -", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_jobs_purge-old-jobs/", "text": "cozy-stack jobs purge-old-jobs \u00b6 Purge old jobs from an instance cozy-stack jobs purge-old-jobs [flags] Examples \u00b6 $ cozy-stack jobs purge-old-jobs example.mycozy.cloud Options \u00b6 --duration string duration to look for (ie. 3D, 2M) -h, --help help for purge-old-jobs --workers strings worker types to iterate over (all workers by default) Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack jobs - Launch and manage jobs and workers", "title": "Cozy stack jobs purge old jobs"}, {"location": "cozy-stack/cli/cozy-stack_jobs_purge-old-jobs/#cozy-stack-jobs-purge-old-jobs", "text": "Purge old jobs from an instance cozy-stack jobs purge-old-jobs [flags]", "title": "cozy-stack jobs purge-old-jobs"}, {"location": "cozy-stack/cli/cozy-stack_jobs_purge-old-jobs/#examples", "text": "$ cozy-stack jobs purge-old-jobs example.mycozy.cloud", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_jobs_purge-old-jobs/#options", "text": "--duration string duration to look for (ie. 3D, 2M) -h, --help help for purge-old-jobs --workers strings worker types to iterate over (all workers by default)", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_jobs_purge-old-jobs/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_jobs_purge-old-jobs/#see-also", "text": "cozy-stack jobs - Launch and manage jobs and workers", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_jobs_run/", "text": "cozy-stack jobs run \u00b6 cozy-stack jobs run [flags] Examples \u00b6 $ cozy-stack jobs run service --domain example.mycozy.cloud --json '{\"slug\": \"banks\", \"name\": \"onOperationOrBillCreate\", \"file\": \"onOperationOrBillCreate.js\"}' Options \u00b6 -h, --help help for run --json string specify the job arguments as raw JSON --logs print jobs log in stdout --logs-verbose verbose logging (with --logs flag) Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack jobs - Launch and manage jobs and workers", "title": "Cozy stack jobs run"}, {"location": "cozy-stack/cli/cozy-stack_jobs_run/#cozy-stack-jobs-run", "text": "cozy-stack jobs run [flags]", "title": "cozy-stack jobs run"}, {"location": "cozy-stack/cli/cozy-stack_jobs_run/#examples", "text": "$ cozy-stack jobs run service --domain example.mycozy.cloud --json '{\"slug\": \"banks\", \"name\": \"onOperationOrBillCreate\", \"file\": \"onOperationOrBillCreate.js\"}'", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_jobs_run/#options", "text": "-h, --help help for run --json string specify the job arguments as raw JSON --logs print jobs log in stdout --logs-verbose verbose logging (with --logs flag)", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_jobs_run/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_jobs_run/#see-also", "text": "cozy-stack jobs - Launch and manage jobs and workers", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors/", "text": "cozy-stack konnectors \u00b6 Interact with the konnectors Synopsis \u00b6 cozy-stack konnectors allows to interact with the cozy konnectors. It provides commands to install or update applications on a cozy. cozy-stack konnectors [flags] Options \u00b6 --all-domains work on all domains iteratively --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for konnectors --parameters string override the parameters of the installed konnector Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack konnectors deactivate-maintenance - Deactivate maintenance for the given konnector cozy-stack konnectors install - Install a konnector with the specified slug name from the given source URL. cozy-stack konnectors ls - List the installed konnectors. cozy-stack konnectors ls-maintenances - List the konnectors in maintenance cozy-stack konnectors maintenance - Activate the maintenance for the given konnector cozy-stack konnectors run - Run a konnector. cozy-stack konnectors show - Show the application attributes cozy-stack konnectors uninstall - Uninstall the konnector with the specified slug name. cozy-stack konnectors update - Update the konnector with the specified slug name.", "title": "Cozy stack konnectors"}, {"location": "cozy-stack/cli/cozy-stack_konnectors/#cozy-stack-konnectors", "text": "Interact with the konnectors", "title": "cozy-stack konnectors"}, {"location": "cozy-stack/cli/cozy-stack_konnectors/#synopsis", "text": "cozy-stack konnectors allows to interact with the cozy konnectors. It provides commands to install or update applications on a cozy. cozy-stack konnectors [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_konnectors/#options", "text": "--all-domains work on all domains iteratively --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for konnectors --parameters string override the parameters of the installed konnector", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack konnectors deactivate-maintenance - Deactivate maintenance for the given konnector cozy-stack konnectors install - Install a konnector with the specified slug name from the given source URL. cozy-stack konnectors ls - List the installed konnectors. cozy-stack konnectors ls-maintenances - List the konnectors in maintenance cozy-stack konnectors maintenance - Activate the maintenance for the given konnector cozy-stack konnectors run - Run a konnector. cozy-stack konnectors show - Show the application attributes cozy-stack konnectors uninstall - Uninstall the konnector with the specified slug name. cozy-stack konnectors update - Update the konnector with the specified slug name.", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_deactivate-maintenance/", "text": "cozy-stack konnectors deactivate-maintenance \u00b6 Deactivate maintenance for the given konnector cozy-stack konnectors deactivate-maintenance [slug] [flags] Options \u00b6 -h, --help help for deactivate-maintenance Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors deactivate maintenance"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_deactivate-maintenance/#cozy-stack-konnectors-deactivate-maintenance", "text": "Deactivate maintenance for the given konnector cozy-stack konnectors deactivate-maintenance [slug] [flags]", "title": "cozy-stack konnectors deactivate-maintenance"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_deactivate-maintenance/#options", "text": "-h, --help help for deactivate-maintenance", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_deactivate-maintenance/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_deactivate-maintenance/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_install/", "text": "cozy-stack konnectors install \u00b6 Install a konnector with the specified slug name from the given source URL. Synopsis \u00b6 Install a konnector with the specified slug name. You can also provide the version number to install a specific release if you use the registry:// scheme. Following formats are accepted: registry:// / / registry:// / registry:// / registry:// If you provide a channel and a version, the channel is ignored. Default channel is stable. Default version is latest. cozy-stack konnectors install [sourceurl] [flags] Examples \u00b6 $ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline/stable/1.0.1 $ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline/stable $ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline/1.2.0 $ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline Options \u00b6 -h, --help help for install Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors install"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_install/#cozy-stack-konnectors-install", "text": "Install a konnector with the specified slug name from the given source URL.", "title": "cozy-stack konnectors install"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_install/#synopsis", "text": "Install a konnector with the specified slug name. You can also provide the version number to install a specific release if you use the registry:// scheme. Following formats are accepted: registry:// / / registry:// / registry:// / registry:// If you provide a channel and a version, the channel is ignored. Default channel is stable. Default version is latest. cozy-stack konnectors install [sourceurl] [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_install/#examples", "text": "$ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline/stable/1.0.1 $ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline/stable $ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline/1.2.0 $ cozy-stack konnectors install --domain cozy.localhost:8080 trainline registry://trainline", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_install/#options", "text": "-h, --help help for install", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_install/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_install/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls-maintenances/", "text": "cozy-stack konnectors ls-maintenances \u00b6 List the konnectors in maintenance cozy-stack konnectors ls-maintenances [flags] Options \u00b6 --context string include konnectors in maintenance for apps registry of this context -h, --help help for ls-maintenances Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors ls maintenances"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls-maintenances/#cozy-stack-konnectors-ls-maintenances", "text": "List the konnectors in maintenance cozy-stack konnectors ls-maintenances [flags]", "title": "cozy-stack konnectors ls-maintenances"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls-maintenances/#options", "text": "--context string include konnectors in maintenance for apps registry of this context -h, --help help for ls-maintenances", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls-maintenances/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls-maintenances/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls/", "text": "cozy-stack konnectors ls \u00b6 List the installed konnectors. cozy-stack konnectors ls [flags] Options \u00b6 -h, --help help for ls Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors ls"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls/#cozy-stack-konnectors-ls", "text": "List the installed konnectors. cozy-stack konnectors ls [flags]", "title": "cozy-stack konnectors ls"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls/#options", "text": "-h, --help help for ls", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_ls/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_maintenance/", "text": "cozy-stack konnectors maintenance \u00b6 Activate the maintenance for the given konnector cozy-stack konnectors maintenance [slug] [flags] Options \u00b6 -h, --help help for maintenance --no-manual-exec specify a maintenance disallowing manual execution --short specify a short maintenance Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors maintenance"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_maintenance/#cozy-stack-konnectors-maintenance", "text": "Activate the maintenance for the given konnector cozy-stack konnectors maintenance [slug] [flags]", "title": "cozy-stack konnectors maintenance"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_maintenance/#options", "text": "-h, --help help for maintenance --no-manual-exec specify a maintenance disallowing manual execution --short specify a short maintenance", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_maintenance/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_maintenance/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_run/", "text": "cozy-stack konnectors run \u00b6 Run a konnector. Synopsis \u00b6 Run a konnector named with specified slug using the specified options. cozy-stack konnectors run [flags] Options \u00b6 --account-id string specify the account ID to use for running the konnector -h, --help help for run Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors run"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_run/#cozy-stack-konnectors-run", "text": "Run a konnector.", "title": "cozy-stack konnectors run"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_run/#synopsis", "text": "Run a konnector named with specified slug using the specified options. cozy-stack konnectors run [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_run/#options", "text": "--account-id string specify the account ID to use for running the konnector -h, --help help for run", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_run/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_run/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_show/", "text": "cozy-stack konnectors show \u00b6 Show the application attributes cozy-stack konnectors show [flags] Options \u00b6 -h, --help help for show Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors show"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_show/#cozy-stack-konnectors-show", "text": "Show the application attributes cozy-stack konnectors show [flags]", "title": "cozy-stack konnectors show"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_show/#options", "text": "-h, --help help for show", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_show/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_show/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_uninstall/", "text": "cozy-stack konnectors uninstall \u00b6 Uninstall the konnector with the specified slug name. cozy-stack konnectors uninstall [flags] Options \u00b6 -h, --help help for uninstall Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors uninstall"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_uninstall/#cozy-stack-konnectors-uninstall", "text": "Uninstall the konnector with the specified slug name. cozy-stack konnectors uninstall [flags]", "title": "cozy-stack konnectors uninstall"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_uninstall/#options", "text": "-h, --help help for uninstall", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_uninstall/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_uninstall/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_update/", "text": "cozy-stack konnectors update \u00b6 Update the konnector with the specified slug name. cozy-stack konnectors update [sourceurl] [flags] Options \u00b6 -h, --help help for update --safe do not upgrade if there are blocking changes Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack konnectors - Interact with the konnectors", "title": "Cozy stack konnectors update"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_update/#cozy-stack-konnectors-update", "text": "Update the konnector with the specified slug name. cozy-stack konnectors update [sourceurl] [flags]", "title": "cozy-stack konnectors update"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_update/#options", "text": "-h, --help help for update --safe do not upgrade if there are blocking changes", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_update/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) --all-domains work on all domains iteratively -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") --parameters string override the parameters of the installed konnector -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_konnectors_update/#see-also", "text": "cozy-stack konnectors - Interact with the konnectors", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_serve/", "text": "cozy-stack serve \u00b6 Starts the stack and listens for HTTP calls Synopsis \u00b6 Starts the stack and listens for HTTP calls It will accept HTTP requests on localhost:8080 by default. Use the \u2013port and \u2013host flags to change the listening option. The SIGINT signal will trigger a graceful stop of cozy-stack: it will wait that current HTTP requests and jobs are finished (in a limit of 2 minutes) before exiting. If you are the developer of a client-side app, you can use \u2013appdir to mount a directory as the application with the \u2018app\u2019 slug. cozy-stack serve [flags] Examples \u00b6 The most often, this command is used in its simple form: $ cozy-stack serve But if you want to develop two apps in local (to test their interactions for example), you can use the --appdir flag like this: $ cozy-stack serve --appdir appone:/path/to/app_one,apptwo:/path/to/app_two Options \u00b6 --allow-root Allow to start as root (disabled by default) --appdir strings Mount a directory as the 'app' application --assets string path to the directory with the assets (use the packed assets by default) --couchdb-url string CouchDB URL (default \"http://localhost:5984/\") --csp-allowlist string Add domains for the default allowed origins of the Content Secury Policy --dev Allow to run in dev mode for a prod release (disabled by default) --disable-csp Disable the Content Security Policy (only available for development) --doctypes string path to the directory with the doctypes (for developing/testing a remote doctype) --downloads-url string URL for the download secret storage, redis or in-memory --flagship-apk-certificate-digests strings SHA-256 hash (base64 encoded) of the flagship app's signing certificate on android (default [u2eUUnfB4Y7k7eqQL7u2jiYDJeVBwZoSV3PZSs8pttc=]) --flagship-apk-package-names strings Package name for the flagship app on android (default [io.cozy.drive.mobile,io.cozy.flagship.mobile]) --flagship-apple-app-ids strings App ID of the flagship app on iOS (default [3AKXFMV43J.io.cozy.drive.mobile,3AKXFMV43J.io.cozy.flagship.mobile]) --flagship-play-integrity-decryption-keys strings Decryption key for the Google Play Integrity API (default [bVcBAv0eO64NKIvDoRHpnTOZVxAkhMuFwRHrTEMr23U=]) --flagship-play-integrity-verification-keys strings Verification key for the Google Play Integrity API (default [MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElTF2uARN7oxfoDWyERYMe6QutI2NqS+CAtVmsPDIRjBBxF96fYojFVXRRsMb86PjkE21Ol+sO1YuspY+YuDRMw==]) --fs-default-layout int Default layout for Swift (2 for layout v3) (default -1) --fs-url string filesystem url (default \"file:///home/runner/work/cozy-stack/cozy-stack/storage\") --geodb string define the location of the database for IP -> City lookups (default \".\") -h, --help help for serve --jobs-url string URL for the jobs system synchronization, redis or in-memory --konnectors-cmd string konnectors command to be executed --konnectors-oauthstate string URL for the storage of OAuth state for konnectors, redis or in-memory --lock-url string URL for the locks, redis or in-memory --log-level string define the log level (default \"info\") --log-syslog use the local syslog for logging --mail-alert-address string mail address used for alerts (instance deletion failure for example) --mail-disable-tls disable starttls on smtp (default true) --mail-host string mail smtp host (default \"localhost\") --mail-local-name string hostname sent to the smtp server with the HELO command (default \"localhost\") --mail-noreply-address string mail address used for sending mail as a noreply (forgot passwords for example) --mail-noreply-name string mail name used for sending mail as a noreply (forgot passwords for example) (default \"My Cozy\") --mail-password string mail smtp password --mail-port int mail smtp port (default 25) --mail-reply-to string mail address used to the reply-to (support for example) --mail-use-ssl use ssl for mail sending (smtps) --mail-username string mail smtp username --mailhog Alias of --mail-disable-tls --mail-port 1025, useful for MailHog --move-url string URL for the move wizard (default \"https://move.cozycloud.cc/\") --onlyoffice-inbox-secret string Secret used for signing requests to the OnlyOffice server --onlyoffice-outbox-secret string Secret used for verifying requests from the OnlyOffice server --onlyoffice-url string URL for the OnlyOffice server --password-reset-interval string minimal duration between two password reset (default \"15m\") --rate-limiting-url string URL for rate-limiting counters, redis or in-memory --realtime-url string URL for realtime in the browser via webocket, redis or in-memory --remote-allow-custom-port Allow to specify a port in request files for remote doctypes --sessions-url string URL for the sessions storage, redis or in-memory --subdomains string how to structure the subdomains for apps (can be nested or flat) (default \"nested\") --vault-decryptor-key string the path to the key used to decrypt credentials --vault-encryptor-key string the path to the key used to encrypt credentials Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command", "title": "Cozy stack serve"}, {"location": "cozy-stack/cli/cozy-stack_serve/#cozy-stack-serve", "text": "Starts the stack and listens for HTTP calls", "title": "cozy-stack serve"}, {"location": "cozy-stack/cli/cozy-stack_serve/#synopsis", "text": "Starts the stack and listens for HTTP calls It will accept HTTP requests on localhost:8080 by default. Use the \u2013port and \u2013host flags to change the listening option. The SIGINT signal will trigger a graceful stop of cozy-stack: it will wait that current HTTP requests and jobs are finished (in a limit of 2 minutes) before exiting. If you are the developer of a client-side app, you can use \u2013appdir to mount a directory as the application with the \u2018app\u2019 slug. cozy-stack serve [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_serve/#examples", "text": "The most often, this command is used in its simple form: $ cozy-stack serve But if you want to develop two apps in local (to test their interactions for example), you can use the --appdir flag like this: $ cozy-stack serve --appdir appone:/path/to/app_one,apptwo:/path/to/app_two", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_serve/#options", "text": "--allow-root Allow to start as root (disabled by default) --appdir strings Mount a directory as the 'app' application --assets string path to the directory with the assets (use the packed assets by default) --couchdb-url string CouchDB URL (default \"http://localhost:5984/\") --csp-allowlist string Add domains for the default allowed origins of the Content Secury Policy --dev Allow to run in dev mode for a prod release (disabled by default) --disable-csp Disable the Content Security Policy (only available for development) --doctypes string path to the directory with the doctypes (for developing/testing a remote doctype) --downloads-url string URL for the download secret storage, redis or in-memory --flagship-apk-certificate-digests strings SHA-256 hash (base64 encoded) of the flagship app's signing certificate on android (default [u2eUUnfB4Y7k7eqQL7u2jiYDJeVBwZoSV3PZSs8pttc=]) --flagship-apk-package-names strings Package name for the flagship app on android (default [io.cozy.drive.mobile,io.cozy.flagship.mobile]) --flagship-apple-app-ids strings App ID of the flagship app on iOS (default [3AKXFMV43J.io.cozy.drive.mobile,3AKXFMV43J.io.cozy.flagship.mobile]) --flagship-play-integrity-decryption-keys strings Decryption key for the Google Play Integrity API (default [bVcBAv0eO64NKIvDoRHpnTOZVxAkhMuFwRHrTEMr23U=]) --flagship-play-integrity-verification-keys strings Verification key for the Google Play Integrity API (default [MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElTF2uARN7oxfoDWyERYMe6QutI2NqS+CAtVmsPDIRjBBxF96fYojFVXRRsMb86PjkE21Ol+sO1YuspY+YuDRMw==]) --fs-default-layout int Default layout for Swift (2 for layout v3) (default -1) --fs-url string filesystem url (default \"file:///home/runner/work/cozy-stack/cozy-stack/storage\") --geodb string define the location of the database for IP -> City lookups (default \".\") -h, --help help for serve --jobs-url string URL for the jobs system synchronization, redis or in-memory --konnectors-cmd string konnectors command to be executed --konnectors-oauthstate string URL for the storage of OAuth state for konnectors, redis or in-memory --lock-url string URL for the locks, redis or in-memory --log-level string define the log level (default \"info\") --log-syslog use the local syslog for logging --mail-alert-address string mail address used for alerts (instance deletion failure for example) --mail-disable-tls disable starttls on smtp (default true) --mail-host string mail smtp host (default \"localhost\") --mail-local-name string hostname sent to the smtp server with the HELO command (default \"localhost\") --mail-noreply-address string mail address used for sending mail as a noreply (forgot passwords for example) --mail-noreply-name string mail name used for sending mail as a noreply (forgot passwords for example) (default \"My Cozy\") --mail-password string mail smtp password --mail-port int mail smtp port (default 25) --mail-reply-to string mail address used to the reply-to (support for example) --mail-use-ssl use ssl for mail sending (smtps) --mail-username string mail smtp username --mailhog Alias of --mail-disable-tls --mail-port 1025, useful for MailHog --move-url string URL for the move wizard (default \"https://move.cozycloud.cc/\") --onlyoffice-inbox-secret string Secret used for signing requests to the OnlyOffice server --onlyoffice-outbox-secret string Secret used for verifying requests from the OnlyOffice server --onlyoffice-url string URL for the OnlyOffice server --password-reset-interval string minimal duration between two password reset (default \"15m\") --rate-limiting-url string URL for rate-limiting counters, redis or in-memory --realtime-url string URL for realtime in the browser via webocket, redis or in-memory --remote-allow-custom-port Allow to specify a port in request files for remote doctypes --sessions-url string URL for the sessions storage, redis or in-memory --subdomains string how to structure the subdomains for apps (can be nested or flat) (default \"nested\") --vault-decryptor-key string the path to the key used to decrypt credentials --vault-encryptor-key string the path to the key used to encrypt credentials", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_serve/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_serve/#see-also", "text": "cozy-stack - cozy-stack is the main command", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_settings/", "text": "cozy-stack settings \u00b6 Display and update settings Synopsis \u00b6 cozy-stack settings displays the settings. It can also take a list of settings to update. If you give a blank value, the setting will be removed. cozy-stack settings [settings] [flags] Examples \u00b6 $ cozy-stack settings --domain cozy.localhost:8080 context:beta,public_name:John,to_remove: Options \u00b6 --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for settings Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command", "title": "Cozy stack settings"}, {"location": "cozy-stack/cli/cozy-stack_settings/#cozy-stack-settings", "text": "Display and update settings", "title": "cozy-stack settings"}, {"location": "cozy-stack/cli/cozy-stack_settings/#synopsis", "text": "cozy-stack settings displays the settings. It can also take a list of settings to update. If you give a blank value, the setting will be removed. cozy-stack settings [settings] [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_settings/#examples", "text": "$ cozy-stack settings --domain cozy.localhost:8080 context:beta,public_name:John,to_remove:", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_settings/#options", "text": "--domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for settings", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_settings/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_settings/#see-also", "text": "cozy-stack - cozy-stack is the main command", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_status/", "text": "cozy-stack status \u00b6 Check if the HTTP server is running Synopsis \u00b6 Check if the HTTP server has been started and answer 200 for /status. cozy-stack status [flags] Options \u00b6 -h, --help help for status Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command", "title": "Cozy stack status"}, {"location": "cozy-stack/cli/cozy-stack_status/#cozy-stack-status", "text": "Check if the HTTP server is running", "title": "cozy-stack status"}, {"location": "cozy-stack/cli/cozy-stack_status/#synopsis", "text": "Check if the HTTP server has been started and answer 200 for /status. cozy-stack status [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_status/#options", "text": "-h, --help help for status", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_status/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_status/#see-also", "text": "cozy-stack - cozy-stack is the main command", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_swift/", "text": "cozy-stack swift \u00b6 Interact directly with OpenStack Swift object storage cozy-stack swift [flags] Options \u00b6 -h, --help help for swift Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack swift get - cozy-stack swift ls - cozy-stack swift ls-layouts - Count layouts by types (v3a, v3b, unknown) cozy-stack swift put - cozy-stack swift rm -", "title": "Cozy stack swift"}, {"location": "cozy-stack/cli/cozy-stack_swift/#cozy-stack-swift", "text": "Interact directly with OpenStack Swift object storage cozy-stack swift [flags]", "title": "cozy-stack swift"}, {"location": "cozy-stack/cli/cozy-stack_swift/#options", "text": "-h, --help help for swift", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_swift/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_swift/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack swift get - cozy-stack swift ls - cozy-stack swift ls-layouts - Count layouts by types (v3a, v3b, unknown) cozy-stack swift put - cozy-stack swift rm -", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_swift_get/", "text": "cozy-stack swift get \u00b6 cozy-stack swift get [flags] Options \u00b6 -h, --help help for get Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "Cozy stack swift get"}, {"location": "cozy-stack/cli/cozy-stack_swift_get/#cozy-stack-swift-get", "text": "cozy-stack swift get [flags]", "title": "cozy-stack swift get"}, {"location": "cozy-stack/cli/cozy-stack_swift_get/#options", "text": "-h, --help help for get", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_swift_get/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_swift_get/#see-also", "text": "cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls-layouts/", "text": "cozy-stack swift ls-layouts \u00b6 Count layouts by types (v3a, v3b, unknown) cozy-stack swift ls-layouts [flags] Examples \u00b6 $ cozy-stack swift ls-layouts Options \u00b6 -h, --help help for ls-layouts --show-domains Show the domains along the counter Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "Cozy stack swift ls layouts"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls-layouts/#cozy-stack-swift-ls-layouts", "text": "Count layouts by types (v3a, v3b, unknown) cozy-stack swift ls-layouts [flags]", "title": "cozy-stack swift ls-layouts"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls-layouts/#examples", "text": "$ cozy-stack swift ls-layouts", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls-layouts/#options", "text": "-h, --help help for ls-layouts --show-domains Show the domains along the counter", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls-layouts/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls-layouts/#see-also", "text": "cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls/", "text": "cozy-stack swift ls \u00b6 cozy-stack swift ls [flags] Options \u00b6 -h, --help help for ls Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "Cozy stack swift ls"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls/#cozy-stack-swift-ls", "text": "cozy-stack swift ls [flags]", "title": "cozy-stack swift ls"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls/#options", "text": "-h, --help help for ls", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_swift_ls/#see-also", "text": "cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_swift_put/", "text": "cozy-stack swift put \u00b6 Synopsis \u00b6 cozy-stack swift put can be used to create or update an object in the swift container associated to the given domain. The content of the file is expected on the standard input. cozy-stack swift put [flags] Options \u00b6 --content-type string Specify a Content-Type for the created object -h, --help help for put Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "Cozy stack swift put"}, {"location": "cozy-stack/cli/cozy-stack_swift_put/#cozy-stack-swift-put", "text": "", "title": "cozy-stack swift put"}, {"location": "cozy-stack/cli/cozy-stack_swift_put/#synopsis", "text": "cozy-stack swift put can be used to create or update an object in the swift container associated to the given domain. The content of the file is expected on the standard input. cozy-stack swift put [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_swift_put/#options", "text": "--content-type string Specify a Content-Type for the created object -h, --help help for put", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_swift_put/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_swift_put/#see-also", "text": "cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_swift_rm/", "text": "cozy-stack swift rm \u00b6 cozy-stack swift rm [flags] Options \u00b6 -h, --help help for rm Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "Cozy stack swift rm"}, {"location": "cozy-stack/cli/cozy-stack_swift_rm/#cozy-stack-swift-rm", "text": "cozy-stack swift rm [flags]", "title": "cozy-stack swift rm"}, {"location": "cozy-stack/cli/cozy-stack_swift_rm/#options", "text": "-h, --help help for rm", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_swift_rm/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_swift_rm/#see-also", "text": "cozy-stack swift - Interact directly with OpenStack Swift object storage", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_tools/", "text": "cozy-stack tools \u00b6 Regroup some tools for debugging and tests cozy-stack tools [flags] Options \u00b6 -h, --help help for tools Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack tools bug - start a bug report cozy-stack tools encrypt-with-rsa - encrypt a payload in RSA cozy-stack tools heap - Dump a sampling of memory allocations of live objects cozy-stack tools unxor-document-id - transform the id of a shared document", "title": "Cozy stack tools"}, {"location": "cozy-stack/cli/cozy-stack_tools/#cozy-stack-tools", "text": "Regroup some tools for debugging and tests cozy-stack tools [flags]", "title": "cozy-stack tools"}, {"location": "cozy-stack/cli/cozy-stack_tools/#options", "text": "-h, --help help for tools", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_tools/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_tools/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack tools bug - start a bug report cozy-stack tools encrypt-with-rsa - encrypt a payload in RSA cozy-stack tools heap - Dump a sampling of memory allocations of live objects cozy-stack tools unxor-document-id - transform the id of a shared document", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_tools_bug/", "text": "cozy-stack tools bug \u00b6 start a bug report Synopsis \u00b6 Bug opens the default browser and starts a new bug report. The report includes useful system information. cozy-stack tools bug [flags] Options \u00b6 -h, --help help for bug Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack tools - Regroup some tools for debugging and tests", "title": "Cozy stack tools bug"}, {"location": "cozy-stack/cli/cozy-stack_tools_bug/#cozy-stack-tools-bug", "text": "start a bug report", "title": "cozy-stack tools bug"}, {"location": "cozy-stack/cli/cozy-stack_tools_bug/#synopsis", "text": "Bug opens the default browser and starts a new bug report. The report includes useful system information. cozy-stack tools bug [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_tools_bug/#options", "text": "-h, --help help for bug", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_tools_bug/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_tools_bug/#see-also", "text": "cozy-stack tools - Regroup some tools for debugging and tests", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_tools_encrypt-with-rsa/", "text": "cozy-stack tools encrypt-with-rsa \u00b6 encrypt a payload in RSA Synopsis \u00b6 This command is used by system tests to encrypt bitwarden organization keys. It takes the public or private key of the user and the payload (= the organization key) as inputs (both encoded in base64), and print on stdout the encrypted data (encoded as base64 too). cozy-stack tools encrypt-with-rsa heap.pprof && go tool pprof heap.pprof Options \u00b6 -h, --help help for heap Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack tools - Regroup some tools for debugging and tests", "title": "Cozy stack tools heap"}, {"location": "cozy-stack/cli/cozy-stack_tools_heap/#cozy-stack-tools-heap", "text": "Dump a sampling of memory allocations of live objects", "title": "cozy-stack tools heap"}, {"location": "cozy-stack/cli/cozy-stack_tools_heap/#synopsis", "text": "This command can be used for memory profiling. It dumps a sampling of memory allocations of live objects on stdout. See https://go.dev/doc/diagnostics#profiling. cozy-stack tools heap [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_tools_heap/#examples", "text": "$ cozy-stack tools heap > heap.pprof && go tool pprof heap.pprof", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_tools_heap/#options", "text": "-h, --help help for heap", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_tools_heap/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_tools_heap/#see-also", "text": "cozy-stack tools - Regroup some tools for debugging and tests", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_tools_unxor-document-id/", "text": "cozy-stack tools unxor-document-id \u00b6 transform the id of a shared document Synopsis \u00b6 This command can be used when you have the identifier of a shared document on a recipient instance, and you want the identifier of the same document on the owner\u2019s instance. cozy-stack tools unxor-document-id [flags] Examples \u00b6 $ cozy-stack tools unxor-document-id bob.localhost:8080 7f47c470c7b1013a8a8818c04daba326 8cced87acb34b151cc8d7e864e0690ed Options \u00b6 -h, --help help for unxor-document-id Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack tools - Regroup some tools for debugging and tests", "title": "Cozy stack tools unxor document id"}, {"location": "cozy-stack/cli/cozy-stack_tools_unxor-document-id/#cozy-stack-tools-unxor-document-id", "text": "transform the id of a shared document", "title": "cozy-stack tools unxor-document-id"}, {"location": "cozy-stack/cli/cozy-stack_tools_unxor-document-id/#synopsis", "text": "This command can be used when you have the identifier of a shared document on a recipient instance, and you want the identifier of the same document on the owner\u2019s instance. cozy-stack tools unxor-document-id [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_tools_unxor-document-id/#examples", "text": "$ cozy-stack tools unxor-document-id bob.localhost:8080 7f47c470c7b1013a8a8818c04daba326 8cced87acb34b151cc8d7e864e0690ed", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_tools_unxor-document-id/#options", "text": "-h, --help help for unxor-document-id", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_tools_unxor-document-id/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_tools_unxor-document-id/#see-also", "text": "cozy-stack tools - Regroup some tools for debugging and tests", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_triggers/", "text": "cozy-stack triggers \u00b6 Interact with the triggers Synopsis \u00b6 cozy-stack apps allows to interact with the cozy triggers. It provides command to run a specific trigger. cozy-stack triggers [flags] Options \u00b6 --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for triggers Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command cozy-stack triggers launch - Creates a job from a specific trigger cozy-stack triggers ls - List triggers cozy-stack triggers show-from-app - Show the application triggers", "title": "Cozy stack triggers"}, {"location": "cozy-stack/cli/cozy-stack_triggers/#cozy-stack-triggers", "text": "Interact with the triggers", "title": "cozy-stack triggers"}, {"location": "cozy-stack/cli/cozy-stack_triggers/#synopsis", "text": "cozy-stack apps allows to interact with the cozy triggers. It provides command to run a specific trigger. cozy-stack triggers [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_triggers/#options", "text": "--domain string specify the domain name of the instance (default \"cozy.localhost:8080\") -h, --help help for triggers", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_triggers/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_triggers/#see-also", "text": "cozy-stack - cozy-stack is the main command cozy-stack triggers launch - Creates a job from a specific trigger cozy-stack triggers ls - List triggers cozy-stack triggers show-from-app - Show the application triggers", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_triggers_launch/", "text": "cozy-stack triggers launch \u00b6 Creates a job from a specific trigger cozy-stack triggers launch [triggerId] [flags] Examples \u00b6 $ cozy-stack triggers launch --domain cozy.localhost:8080 748f42b65aca8c99ec2492eb660d1891 Options \u00b6 -h, --help help for launch Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack triggers - Interact with the triggers", "title": "Cozy stack triggers launch"}, {"location": "cozy-stack/cli/cozy-stack_triggers_launch/#cozy-stack-triggers-launch", "text": "Creates a job from a specific trigger cozy-stack triggers launch [triggerId] [flags]", "title": "cozy-stack triggers launch"}, {"location": "cozy-stack/cli/cozy-stack_triggers_launch/#examples", "text": "$ cozy-stack triggers launch --domain cozy.localhost:8080 748f42b65aca8c99ec2492eb660d1891", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_triggers_launch/#options", "text": "-h, --help help for launch", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_triggers_launch/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_triggers_launch/#see-also", "text": "cozy-stack triggers - Interact with the triggers", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_triggers_ls/", "text": "cozy-stack triggers ls \u00b6 List triggers cozy-stack triggers ls [flags] Examples \u00b6 $ cozy-stack triggers ls --domain cozy.localhost:8080 Options \u00b6 -h, --help help for ls Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack triggers - Interact with the triggers", "title": "Cozy stack triggers ls"}, {"location": "cozy-stack/cli/cozy-stack_triggers_ls/#cozy-stack-triggers-ls", "text": "List triggers cozy-stack triggers ls [flags]", "title": "cozy-stack triggers ls"}, {"location": "cozy-stack/cli/cozy-stack_triggers_ls/#examples", "text": "$ cozy-stack triggers ls --domain cozy.localhost:8080", "title": "Examples"}, {"location": "cozy-stack/cli/cozy-stack_triggers_ls/#options", "text": "-h, --help help for ls", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_triggers_ls/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_triggers_ls/#see-also", "text": "cozy-stack triggers - Interact with the triggers", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_triggers_show-from-app/", "text": "cozy-stack triggers show-from-app \u00b6 Show the application triggers cozy-stack triggers show-from-app [flags] Options \u00b6 -h, --help help for show-from-app Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack triggers - Interact with the triggers", "title": "Cozy stack triggers show from app"}, {"location": "cozy-stack/cli/cozy-stack_triggers_show-from-app/#cozy-stack-triggers-show-from-app", "text": "Show the application triggers cozy-stack triggers show-from-app [flags]", "title": "cozy-stack triggers show-from-app"}, {"location": "cozy-stack/cli/cozy-stack_triggers_show-from-app/#options", "text": "-h, --help help for show-from-app", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_triggers_show-from-app/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --domain string specify the domain name of the instance (default \"cozy.localhost:8080\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_triggers_show-from-app/#see-also", "text": "cozy-stack triggers - Interact with the triggers", "title": "SEE ALSO"}, {"location": "cozy-stack/cli/cozy-stack_version/", "text": "cozy-stack version \u00b6 Print the version number Synopsis \u00b6 Print the current version number of the binary cozy-stack version [flags] Options \u00b6 -h, --help help for version Options inherited from parent commands \u00b6 --admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080) SEE ALSO \u00b6 cozy-stack - cozy-stack is the main command", "title": "Cozy stack version"}, {"location": "cozy-stack/cli/cozy-stack_version/#cozy-stack-version", "text": "Print the version number", "title": "cozy-stack version"}, {"location": "cozy-stack/cli/cozy-stack_version/#synopsis", "text": "Print the current version number of the binary cozy-stack version [flags]", "title": "Synopsis"}, {"location": "cozy-stack/cli/cozy-stack_version/#options", "text": "-h, --help help for version", "title": "Options"}, {"location": "cozy-stack/cli/cozy-stack_version/#options-inherited-from-parent-commands", "text": "--admin-host string administration server host (default \"localhost\") --admin-port int administration server port (default 6060) -c, --config string configuration file (default \"$HOME/.cozy.yaml\") --host string server host (default \"localhost\") -p, --port int server port (default 8080)", "title": "Options inherited from parent commands"}, {"location": "cozy-stack/cli/cozy-stack_version/#see-also", "text": "cozy-stack - cozy-stack is the main command", "title": "SEE ALSO"}, {"location": "cozy-ui/", "text": "Cozy UI \u00b6 CSS classes and React components designed to build Cozy apps. If you plan to build a webapp to run on Cozy, you\u2019ll probably want to use a simple and elegant solution to build your interfaces without the mess of dealing with complex markup and CSS. Then Cozy UI is here for you! Cozy UI relies heavily on Material UI v4 and it can be useful to know how it works. React components (styleguidist) \u00b6 Check out UI components to see how to use ready made React components. CSS Styleguide \u00b6 Check the styleguide to see all the variables, mixins, classes, utilities and how to use them with only CSS classes. Usage \u00b6 As a Components library \u00b6 Add Cozy UI to a dependency to your project. yarn add cozy-ui If you use the transpiled components (from cozy-ui/transpiled/react ), you need to import the stylesheet (once): import Button from 'cozy-ui/transpiled/react/deprecated/Button' import 'cozy-ui/transpiled/react/stylesheet.css' < Button /> You\u2019re now ready to use Cozy UI\u2019s React components Utility classes \u00b6 React components only come with the needed style, nothing more, but you may need some more utility classes to build your apps. To do so you have at your disposal a special CSS build cozy-ui.utils.min.css that you can add like this: import 'cozy-ui/dist/cozy-ui.utils.min.css' As a vanilla CSS library (deprecated) \u00b6 The entire library is also available as a good ol\u2019 CSS library. You can simply add it to your app by linking the distributed minified file. < link media = \"all\" rel = \"stylesheet\" href = \u201ccozy-ui/dist/cozy-ui.min.css\" /> Develop on Cozy UI \u00b6 If you want to develop inside cozy-ui, you need a local version cozy-ui. git clone git@github.com:cozy/cozy-ui.git Install \u00b6 First nvm use (to set node version as defined in .nvmrc) then yarn install Develop inside the styleguidist \u00b6 It is convenient when modifying a component to use the styleguide site. yarn makeSpriteAndPalette # Create sprite and palette yarn start # Transpile the files in watch mode yarn build:css:all # Build CSS files needed by the documentation yarn start:doc # Run the styleguide in watch mode Add a component \u00b6 If you want to add a new component, you must follow these steps: Add the new component in /react folder with its README.md file Expose it in the API by adding it in react/index.js Add it in the documentation by modifying docs/styleguide.config.js If necessary you can add snapshots for it by modifying react/examples.spec.jsx and updating them yarn makeSpriteAndPalette && yarn build && yarn test -u Remember to propagate the possible ref with React.forwardRef . See forwardRef documentation Try to think of ARIA attributes if you are coding new components Be careful to respect MUI API when creating a new component. See our guidelines to create a new component . Rename/Move a component \u00b6 When renaming or moving a Cozy-UI component, it may cause a breaking change. In this case, you should provide a codemod as much as possible to fix it. Guidelines for component development \u00b6 Use material UI whenever possible Override material UI components inside makeOverrides.js when necessary Avoid stylus to style new components based on MUI and prefer /helpers/makeStyles Use semantic variables for colors from stylus/settings/palettes.styl , or color from theme objects in makeStyles Add an icon \u00b6 If you want to add a new icon to cozy-ui, you must follow these steps: If you SVG file is an icon (not an illustration), verify that the file doesn\u2019t have any fill or fill-opacity properties. Remove them if necessary Add the SVG in the assets/icons/[ui || illus] folder Optimize it with yarn svgo assets/icons/[ui || illus]/[new icon file name] Generate the react component by running yarn makeSvgr assets/icons/[ui || illus]/[new icon file name] Update the documentation by adding the new file in react/Icon/Readme.md. If it\u2019s an icon, add it in SVGr icons and Available UI icons sections, or in SVGr illustrations and Available illustrations sections if it\u2019s an illustration Don\u2019t forget to check the icon\u2019s color on different theme (inverted, etc.) Update the tests by running yarn makeSpriteAndPalette && yarn build && yarn test -u Develop inside an app \u00b6 Sometimes, you want to develop on a component, from the context of an app. Then you need to link cozy-ui with yarn link . Since cozy-ui is transpiled, when linking you must first yarn release . If you change the icons, or the palette, you must run yarn release again. cd cozy-ui yarn makeSpriteAndPalette # if first time yarn link yarn start # Launch transpilation yarn makeSpriteAndPalette # if you change icons or palette Then in your application folder, you can link to your local Cozy UI. You can use rlink instead of yarn link . It will prevent common build problems due to module resolution inside symlinked folders. If your application doesn\u2019t use cozy-ui directly as dependency but through a library, you have to use rlink inside your application folder, not inside the library\u2019s one. rlink only copies the build and not the node_modules of cozy-ui, so you have to install a version of cozy-ui before making a rlink . cd my-app rlink cozy-ui # Prefer rlink to yarn link yarn start All your modifications in your local Cozy UI will now be visible in your application! Making a demo when creating a pull request \u00b6 When sending a PR, if your changes have graphic impacts, it is useful for the reviewers if you have deployed a version of the styleguidist containing your changes to your fork\u2019s repository. Don\u2019t forget to change USERNAME by yours. yarn build:all && yarn deploy:doc --repo git@github.com:USERNAME/cozy-ui.git \u26a0\ufe0f If the deploy:doc failed, you need to checkout your dev branch by doing git checkout - Unit testing \u00b6 Be aware that snapshots in unit tests use the transpiled version of cozy-ui. Therefore if you make changes and need to update the snapshots, you need to transpile first. yarn makeSpriteAndPalette && yarn build && yarn test -u We suggest to use @testing-library/react over enzyme for tests. We have historically used enzyme but we prefer the philosophy behind testing-library since it pushes to test for what the user sees. For complex components, we expose testing helpers in the testing file in their respective folders. import { getCloseButton , getAllDialogs } from 'cozy-ui/transpiled/react/CozyDialogs/testing' it ( 'should close dialog' , () => { const onClose = jest . fn () const root = render (< MyApp onCloseDialog = { onClose } />) const dialog = getDialog ( root ) const closeBtn = getCloseButton ( dialog ) fireEvent . click ( closeBtn ) expect ( onClose ). toHaveBeenCalled () }) UI regression testing \u00b6 Components in cozy-ui are showcased with React Styleguidist . To prevent UI regressions, for each PR, each component is screenshotted and compared to the master version to find any regression (thanks Argos !). If your app uses React Styleguidist , cozy-ui provides rsg-screenshots , a CLI tool to take screenshots of your components (uses Puppeteer under the hood). yarn add cozy-ui # The rsg-screenshots binary is now installed yarn makeSpriteAndPalette yarn build:doc:react # Build our styleguide, the output directory is docs/react rsg-screenshots --screenshot-dir screenshots/ --styleguide-dir docs/react # Each component in the styleguide will be screenshotted and saved inside the screenshots/ directory See our travis configuration for more information. License \u00b6 Cozy UI is developed by Cozy Cloud and distributed under the MIT license. What is Cozy? \u00b6 Cozy is a platform that brings all your web services in the same private space. With it, your web apps and your devices can share data easily, providing you with a new experience. You can install Cozy on your own hardware where no one profiles you. Community \u00b6 You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on irc.freenode.net Posting on our Forum Posting issues on the Github repos Mentioning us on Twitter", "title": "Build the user interface (ui)"}, {"location": "cozy-ui/#cozy-ui", "text": "CSS classes and React components designed to build Cozy apps. If you plan to build a webapp to run on Cozy, you\u2019ll probably want to use a simple and elegant solution to build your interfaces without the mess of dealing with complex markup and CSS. Then Cozy UI is here for you! Cozy UI relies heavily on Material UI v4 and it can be useful to know how it works.", "title": "Cozy UI"}, {"location": "cozy-ui/#react-components-styleguidist", "text": "Check out UI components to see how to use ready made React components.", "title": "React components (styleguidist)"}, {"location": "cozy-ui/#css-styleguide", "text": "Check the styleguide to see all the variables, mixins, classes, utilities and how to use them with only CSS classes.", "title": "CSS Styleguide"}, {"location": "cozy-ui/#usage", "text": "", "title": "Usage"}, {"location": "cozy-ui/#as-a-components-library", "text": "Add Cozy UI to a dependency to your project. yarn add cozy-ui If you use the transpiled components (from cozy-ui/transpiled/react ), you need to import the stylesheet (once): import Button from 'cozy-ui/transpiled/react/deprecated/Button' import 'cozy-ui/transpiled/react/stylesheet.css' < Button /> You\u2019re now ready to use Cozy UI\u2019s React components", "title": "As a Components library"}, {"location": "cozy-ui/#utility-classes", "text": "React components only come with the needed style, nothing more, but you may need some more utility classes to build your apps. To do so you have at your disposal a special CSS build cozy-ui.utils.min.css that you can add like this: import 'cozy-ui/dist/cozy-ui.utils.min.css'", "title": "Utility classes"}, {"location": "cozy-ui/#as-a-vanilla-css-library-deprecated", "text": "The entire library is also available as a good ol\u2019 CSS library. You can simply add it to your app by linking the distributed minified file. < link media = \"all\" rel = \"stylesheet\" href = \u201ccozy-ui/dist/cozy-ui.min.css\" />", "title": "As a vanilla CSS library (deprecated)"}, {"location": "cozy-ui/#develop-on-cozy-ui", "text": "If you want to develop inside cozy-ui, you need a local version cozy-ui. git clone git@github.com:cozy/cozy-ui.git", "title": "Develop on Cozy UI"}, {"location": "cozy-ui/#install", "text": "First nvm use (to set node version as defined in .nvmrc) then yarn install", "title": "Install"}, {"location": "cozy-ui/#develop-inside-the-styleguidist", "text": "It is convenient when modifying a component to use the styleguide site. yarn makeSpriteAndPalette # Create sprite and palette yarn start # Transpile the files in watch mode yarn build:css:all # Build CSS files needed by the documentation yarn start:doc # Run the styleguide in watch mode", "title": "Develop inside the styleguidist"}, {"location": "cozy-ui/#add-a-component", "text": "If you want to add a new component, you must follow these steps: Add the new component in /react folder with its README.md file Expose it in the API by adding it in react/index.js Add it in the documentation by modifying docs/styleguide.config.js If necessary you can add snapshots for it by modifying react/examples.spec.jsx and updating them yarn makeSpriteAndPalette && yarn build && yarn test -u Remember to propagate the possible ref with React.forwardRef . See forwardRef documentation Try to think of ARIA attributes if you are coding new components Be careful to respect MUI API when creating a new component. See our guidelines to create a new component .", "title": "Add a component"}, {"location": "cozy-ui/#renamemove-a-component", "text": "When renaming or moving a Cozy-UI component, it may cause a breaking change. In this case, you should provide a codemod as much as possible to fix it.", "title": "Rename/Move a component"}, {"location": "cozy-ui/#guidelines-for-component-development", "text": "Use material UI whenever possible Override material UI components inside makeOverrides.js when necessary Avoid stylus to style new components based on MUI and prefer /helpers/makeStyles Use semantic variables for colors from stylus/settings/palettes.styl , or color from theme objects in makeStyles", "title": "Guidelines for component development"}, {"location": "cozy-ui/#add-an-icon", "text": "If you want to add a new icon to cozy-ui, you must follow these steps: If you SVG file is an icon (not an illustration), verify that the file doesn\u2019t have any fill or fill-opacity properties. Remove them if necessary Add the SVG in the assets/icons/[ui || illus] folder Optimize it with yarn svgo assets/icons/[ui || illus]/[new icon file name] Generate the react component by running yarn makeSvgr assets/icons/[ui || illus]/[new icon file name] Update the documentation by adding the new file in react/Icon/Readme.md. If it\u2019s an icon, add it in SVGr icons and Available UI icons sections, or in SVGr illustrations and Available illustrations sections if it\u2019s an illustration Don\u2019t forget to check the icon\u2019s color on different theme (inverted, etc.) Update the tests by running yarn makeSpriteAndPalette && yarn build && yarn test -u", "title": "Add an icon"}, {"location": "cozy-ui/#develop-inside-an-app", "text": "Sometimes, you want to develop on a component, from the context of an app. Then you need to link cozy-ui with yarn link . Since cozy-ui is transpiled, when linking you must first yarn release . If you change the icons, or the palette, you must run yarn release again. cd cozy-ui yarn makeSpriteAndPalette # if first time yarn link yarn start # Launch transpilation yarn makeSpriteAndPalette # if you change icons or palette Then in your application folder, you can link to your local Cozy UI. You can use rlink instead of yarn link . It will prevent common build problems due to module resolution inside symlinked folders. If your application doesn\u2019t use cozy-ui directly as dependency but through a library, you have to use rlink inside your application folder, not inside the library\u2019s one. rlink only copies the build and not the node_modules of cozy-ui, so you have to install a version of cozy-ui before making a rlink . cd my-app rlink cozy-ui # Prefer rlink to yarn link yarn start All your modifications in your local Cozy UI will now be visible in your application!", "title": "Develop inside an app"}, {"location": "cozy-ui/#making-a-demo-when-creating-a-pull-request", "text": "When sending a PR, if your changes have graphic impacts, it is useful for the reviewers if you have deployed a version of the styleguidist containing your changes to your fork\u2019s repository. Don\u2019t forget to change USERNAME by yours. yarn build:all && yarn deploy:doc --repo git@github.com:USERNAME/cozy-ui.git \u26a0\ufe0f If the deploy:doc failed, you need to checkout your dev branch by doing git checkout -", "title": "Making a demo when creating a pull request"}, {"location": "cozy-ui/#unit-testing", "text": "Be aware that snapshots in unit tests use the transpiled version of cozy-ui. Therefore if you make changes and need to update the snapshots, you need to transpile first. yarn makeSpriteAndPalette && yarn build && yarn test -u We suggest to use @testing-library/react over enzyme for tests. We have historically used enzyme but we prefer the philosophy behind testing-library since it pushes to test for what the user sees. For complex components, we expose testing helpers in the testing file in their respective folders. import { getCloseButton , getAllDialogs } from 'cozy-ui/transpiled/react/CozyDialogs/testing' it ( 'should close dialog' , () => { const onClose = jest . fn () const root = render (< MyApp onCloseDialog = { onClose } />) const dialog = getDialog ( root ) const closeBtn = getCloseButton ( dialog ) fireEvent . click ( closeBtn ) expect ( onClose ). toHaveBeenCalled () })", "title": "Unit testing"}, {"location": "cozy-ui/#ui-regression-testing", "text": "Components in cozy-ui are showcased with React Styleguidist . To prevent UI regressions, for each PR, each component is screenshotted and compared to the master version to find any regression (thanks Argos !). If your app uses React Styleguidist , cozy-ui provides rsg-screenshots , a CLI tool to take screenshots of your components (uses Puppeteer under the hood). yarn add cozy-ui # The rsg-screenshots binary is now installed yarn makeSpriteAndPalette yarn build:doc:react # Build our styleguide, the output directory is docs/react rsg-screenshots --screenshot-dir screenshots/ --styleguide-dir docs/react # Each component in the styleguide will be screenshotted and saved inside the screenshots/ directory See our travis configuration for more information.", "title": "UI regression testing"}, {"location": "cozy-ui/#license", "text": "Cozy UI is developed by Cozy Cloud and distributed under the MIT license.", "title": "License"}, {"location": "cozy-ui/#what-is-cozy", "text": "Cozy is a platform that brings all your web services in the same private space. With it, your web apps and your devices can share data easily, providing you with a new experience. You can install Cozy on your own hardware where no one profiles you.", "title": "What is Cozy?"}, {"location": "cozy-ui/#community", "text": "You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on irc.freenode.net Posting on our Forum Posting issues on the Github repos Mentioning us on Twitter", "title": "Community"}, {"location": "cozy-ui/dev/", "text": "Transform markdown examples \u00b6 remark is a processor for markdown: it parses markdown source into an AST, transforms the tree and stringifies it afterwards. It can be used along with jscodeshift to automatically migrate and transform examples. When an API has changed and we need to update example, it can be useful to do it via a codemod. Here is an example, running a jscodeshift codemod through the remark-jscodeshift plugin: remark -o --use remark-jscodeshift=allowNoLang:true,transform:\\\"codemods/transform-dialog-imports.js\\\" . Screenshot testing locally \u00b6 You can screenshot old components into pristine_screenshots directory Screenshot the new one inside screenshots Run pixelmatch-server, which shows screenshots side by side like on Argos (you need the pixelmatch binary to be available) # Screenshot all the components yarn build:all mkdir ./screenshots yarn screenshots cp -r screenshots pristine_screenshots # yarn watch:doc:react # Make changes to BarButton... # Screenshot BarButton export COMPONENT = BarButton yarn screenshots --component $COMPONENT # Run pixel diff on a single component pixelmatch pristine_screenshots/ $COMPONENT .png screenshots/ $COMPONENT .png diff/ $COMPONENT .png 0 .1 # Open pixelmatch server to check diffs $ yarn screenshots:server # Enable hot reload $ livereload screenshots,pristine_screenshots,diffs -w 1000", "title": "Transform markdown examples"}, {"location": "cozy-ui/dev/#transform-markdown-examples", "text": "remark is a processor for markdown: it parses markdown source into an AST, transforms the tree and stringifies it afterwards. It can be used along with jscodeshift to automatically migrate and transform examples. When an API has changed and we need to update example, it can be useful to do it via a codemod. Here is an example, running a jscodeshift codemod through the remark-jscodeshift plugin: remark -o --use remark-jscodeshift=allowNoLang:true,transform:\\\"codemods/transform-dialog-imports.js\\\" .", "title": "Transform markdown examples"}, {"location": "cozy-ui/dev/#screenshot-testing-locally", "text": "You can screenshot old components into pristine_screenshots directory Screenshot the new one inside screenshots Run pixelmatch-server, which shows screenshots side by side like on Argos (you need the pixelmatch binary to be available) # Screenshot all the components yarn build:all mkdir ./screenshots yarn screenshots cp -r screenshots pristine_screenshots # yarn watch:doc:react # Make changes to BarButton... # Screenshot BarButton export COMPONENT = BarButton yarn screenshots --component $COMPONENT # Run pixel diff on a single component pixelmatch pristine_screenshots/ $COMPONENT .png screenshots/ $COMPONENT .png diff/ $COMPONENT .png 0 .1 # Open pixelmatch server to check diffs $ yarn screenshots:server # Enable hot reload $ livereload screenshots,pristine_screenshots,diffs -w 1000", "title": "Screenshot testing locally"}, {"location": "cozy-ui/guidelines/", "text": "Guidelines \u00b6 These guidelines are mainly dedicated to cozy-ui designers and maintainers. New component \u00b6 We want to stay as close as possible to MUI components and properties. When we create a new component, we have 4 cases. A MUI component exists and has every properties and values we want. => All right, we just reexport the MUI component. A MUI component exists but misses some values we want. => We add support for missing values to the MUI component. e.g. We want a Button component with 3 variants contained , outlined and ghost . MUIButton has only contained and outlined variants. So we create a Button component using MUIButton where we add support for ghost variant. A MUI component exists but misses some properties we want. => We add a new property to the MUI component. e.g. We want a Fab component with 2 variants circular and extended and we want that these variants can be filled or outlined . MUIButton has only circular and outlined variants and no concept of filled or outlined . We do not force filled or outlined in variants because they are not the same. We add a new property which can be filled or outlined . Nothing exists on MUI => We create a new component from scratch. Generally speaking : color prop changes color (and not shape). Possible values : primary , secondary , success , error , warning , info variant prop changes shape (and not color). Possible values : filled , outlined , ghost , \u2026", "title": "Guidelines"}, {"location": "cozy-ui/guidelines/#guidelines", "text": "These guidelines are mainly dedicated to cozy-ui designers and maintainers.", "title": "Guidelines"}, {"location": "cozy-ui/guidelines/#new-component", "text": "We want to stay as close as possible to MUI components and properties. When we create a new component, we have 4 cases. A MUI component exists and has every properties and values we want. => All right, we just reexport the MUI component. A MUI component exists but misses some values we want. => We add support for missing values to the MUI component. e.g. We want a Button component with 3 variants contained , outlined and ghost . MUIButton has only contained and outlined variants. So we create a Button component using MUIButton where we add support for ghost variant. A MUI component exists but misses some properties we want. => We add a new property to the MUI component. e.g. We want a Fab component with 2 variants circular and extended and we want that these variants can be filled or outlined . MUIButton has only circular and outlined variants and no concept of filled or outlined . We do not force filled or outlined in variants because they are not the same. We add a new property which can be filled or outlined . Nothing exists on MUI => We create a new component from scratch. Generally speaking : color prop changes color (and not shape). Possible values : primary , secondary , success , error , warning , info variant prop changes shape (and not color). Possible values : filled , outlined , ghost , \u2026", "title": "New component"}, {"location": "cozy-ui/how-to-extract/", "text": "How to extract particular styles from Cozy-UI \u00b6 Sometimes, you only need some parts of Cozy UI. You can manually use stylus . $ git clone git@github.com:cozy/cozy-ui.git $ cd cozy-ui $ yarn stylus react/Button/styles.styl compiled react/Button/styles.css", "title": "How to extract"}, {"location": "cozy-ui/how-to-extract/#how-to-extract-particular-styles-from-cozy-ui", "text": "Sometimes, you only need some parts of Cozy UI. You can manually use stylus . $ git clone git@github.com:cozy/cozy-ui.git $ cd cozy-ui $ yarn stylus react/Button/styles.styl compiled react/Button/styles.css", "title": "How to extract particular styles from Cozy-UI"}, {"location": "cozy-ui/how-to-transpile/", "text": "How to use the transpiled cozy-ui \u00b6 Having a transpiled version of cozy-ui allows application developers to remove the webpack specific configs. How to \u00b6 1. Install the next version of cozy-ui \u00b6 yarn add cozy-ui@next 2. Add stylesheet.css \u00b6 + import 'cozy-ui/transpiled/react/stylesheet.css' 3. Replace occurences of cozy-ui/react by cozy-ui/transpiled/react \u00b6 - import { Icon } from 'cozy-ui/react' + import { Icon } from 'cozy-ui/transpiled/react' Alternatively, you can use a webpack alias. Inside webpack.config.js : +resolve: { + alias: { + 'cozy-ui/react': 'cozy-ui/transpiled/react' + } +} 4. Add the icon sprite \u00b6 import Sprite from 'cozy-ui/transpiled/react/Icon/Sprite' const App = () => { return ( < Layout > ... < Main > ... + < Sprite /> ) } 5. Replace palette location \u00b6 - import palette from 'cozy-ui/stylus/settings/palette.json' + import palette from 'cozy-ui/transpiled/react/palette' Caveats \u00b6 You need to keep the stylus plugin if you use it in your stylus files, for example if you use a cozy-ui icon in your stylus files. // If you do this, then keep the stylus plugin since it adds the cozy-ui // folder in the PATH of stylus background-image embedurl('../assets/icons/ui/share.svg')", "title": "How to use the transpiled cozy-ui"}, {"location": "cozy-ui/how-to-transpile/#how-to-use-the-transpiled-cozy-ui", "text": "Having a transpiled version of cozy-ui allows application developers to remove the webpack specific configs.", "title": "How to use the transpiled cozy-ui"}, {"location": "cozy-ui/how-to-transpile/#how-to", "text": "", "title": "How to"}, {"location": "cozy-ui/how-to-transpile/#1-install-the-next-version-of-cozy-ui", "text": "yarn add cozy-ui@next", "title": "1. Install the next version of cozy-ui"}, {"location": "cozy-ui/how-to-transpile/#2-add-stylesheetcss", "text": "+ import 'cozy-ui/transpiled/react/stylesheet.css'", "title": "2. Add stylesheet.css"}, {"location": "cozy-ui/how-to-transpile/#3-replace-occurences-of-cozy-uireact-by-cozy-uitranspiledreact", "text": "- import { Icon } from 'cozy-ui/react' + import { Icon } from 'cozy-ui/transpiled/react' Alternatively, you can use a webpack alias. Inside webpack.config.js : +resolve: { + alias: { + 'cozy-ui/react': 'cozy-ui/transpiled/react' + } +}", "title": "3. Replace occurences of cozy-ui/react by cozy-ui/transpiled/react"}, {"location": "cozy-ui/how-to-transpile/#4-add-the-icon-sprite", "text": "import Sprite from 'cozy-ui/transpiled/react/Icon/Sprite' const App = () => { return ( < Layout > ... < Main > ... + < Sprite /> ) }", "title": "4. Add the icon sprite"}, {"location": "cozy-ui/how-to-transpile/#5-replace-palette-location", "text": "- import palette from 'cozy-ui/stylus/settings/palette.json' + import palette from 'cozy-ui/transpiled/react/palette'", "title": "5. Replace palette location"}, {"location": "cozy-ui/how-to-transpile/#caveats", "text": "You need to keep the stylus plugin if you use it in your stylus files, for example if you use a cozy-ui icon in your stylus files. // If you do this, then keep the stylus plugin since it adds the cozy-ui // folder in the PATH of stylus background-image embedurl('../assets/icons/ui/share.svg')", "title": "Caveats"}, {"location": "cozy-ui/components/Readme/", "text": "", "title": "Readme"}, {"location": "cozy-ui/components/Readme/Readme/", "text": "Welcome on Cozy-ui documentation. Cozy-ui is largely based on Material-ui v4 so this documentation only presents the high-level components and the overridden Mui components. You can find everything you need to know about cozy-ui there : https://github.com/cozy/cozy-ui#readme Use left sidebar to pick a component and see how it works.", "title": "Readme"}, {"location": "eslint-config-cozy-app/", "text": "Eslint Config Cozy App What\u2019s eslint-config-cozy-app? \u00b6 Shareable configurations for Cozy Applications and scripts. This package is an ESLint shareable config already used by create-cozy-app . To install: yarn add --dev eslint-config-cozy-app Usage with a Create Cozy App projects \u00b6 If you started your project using create-cozy-app , you don\u2019t need to do anything, you should already have an .eslintrc.json configured to used this preset. Usage with other projects \u00b6 In a file named .eslintrc.json (the ESLint configuration file), you can use the config by extending it. For example (see following available configurations documentation): { \"extends\" : [ \"cozy-app\" ] } Available configurations \u00b6 Basics \u00b6 Basic configuration for common Javascript code, this is the default configuration. To use in your .eslintrc.json : { \"extends\" : [ \"cozy-app\" ] } Or if you want to use it explicitely: { \"extends\" : [ \"cozy-app/basics\" ] } React \u00b6 Configuration for React applications (basics configuration included). To use in your .eslintrc.json : { \"extends\" : [ \"cozy-app/react\" ] } Community \u00b6 What\u2019s Cozy? \u00b6 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\u2019s tracking you. Get in touch \u00b6 You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter License \u00b6 eslint-config-cozy-app is distributed under the MIT license.", "title": "ESLint"}, {"location": "eslint-config-cozy-app/#whats-eslint-config-cozy-app", "text": "Shareable configurations for Cozy Applications and scripts. This package is an ESLint shareable config already used by create-cozy-app . To install: yarn add --dev eslint-config-cozy-app", "title": "What's eslint-config-cozy-app?"}, {"location": "eslint-config-cozy-app/#usage-with-a-create-cozy-app-projects", "text": "If you started your project using create-cozy-app , you don\u2019t need to do anything, you should already have an .eslintrc.json configured to used this preset.", "title": "Usage with a Create Cozy App projects"}, {"location": "eslint-config-cozy-app/#usage-with-other-projects", "text": "In a file named .eslintrc.json (the ESLint configuration file), you can use the config by extending it. For example (see following available configurations documentation): { \"extends\" : [ \"cozy-app\" ] }", "title": "Usage with other projects"}, {"location": "eslint-config-cozy-app/#available-configurations", "text": "", "title": "Available configurations"}, {"location": "eslint-config-cozy-app/#basics", "text": "Basic configuration for common Javascript code, this is the default configuration. To use in your .eslintrc.json : { \"extends\" : [ \"cozy-app\" ] } Or if you want to use it explicitely: { \"extends\" : [ \"cozy-app/basics\" ] }", "title": "Basics"}, {"location": "eslint-config-cozy-app/#react", "text": "Configuration for React applications (basics configuration included). To use in your .eslintrc.json : { \"extends\" : [ \"cozy-app/react\" ] }", "title": "React"}, {"location": "eslint-config-cozy-app/#community", "text": "", "title": "Community"}, {"location": "eslint-config-cozy-app/#whats-cozy", "text": "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\u2019s tracking you.", "title": "What's Cozy?"}, {"location": "eslint-config-cozy-app/#get-in-touch", "text": "You can reach the Cozy Community by: Chatting with us on IRC #cozycloud on Libera.Chat Posting on our Forum Posting issues on the Github repos Say Hi! on Twitter", "title": "Get in touch"}, {"location": "eslint-config-cozy-app/#license", "text": "eslint-config-cozy-app is distributed under the MIT license.", "title": "License"}, {"location": "eslint-config-cozy-app/CHANGELOG/", "text": "Change Log \u00b6 All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines. 6.1.0 (2023-03-06) \u00b6 Features \u00b6 eslint-config-cozy-app: Update rules ( 1fffa41 ) 6.0.0 (2023-03-02) \u00b6 Features \u00b6 Add new rules to the config ( 84c3157 ) Remove Vue rules ( a61e28d ) Update dependencies to peerDeps ( a556dcb ) BREAKING CHANGES \u00b6 As eslint flat config is still experimental, it\u2019s better to rely on the peerDep patterns. When using this config, it will be needed to install the peerDeps. 5.5.0 (2023-02-11) \u00b6 Features \u00b6 Upgrade eslint cozy config ( 414c1ef ) 5.4.0 (2023-01-31) \u00b6 Features \u00b6 Update cozy-client and cozy-ui ( 6ae3b04 ) 5.3.0 (2023-01-27) \u00b6 Features \u00b6 Add tax_notice aquisitionSteps ( 7dc2ce6 ) 5.2.0 (2022-11-28) \u00b6 Bug Fixes \u00b6 mespapiers: Breaking change of cozy-ui 77 ( be3098e ) Features \u00b6 Update eslint-config-cozy-app ( a0a55db ) 5.1.1 (2022-10-03) \u00b6 Note: Version bump only for package eslint-config-cozy-app 5.1.0 (2022-09-12) \u00b6 Features \u00b6 Add new extend for TS files in lint conf ( 70c0370 ) 5.0.0 (2022-08-31) \u00b6 Features \u00b6 mespapiers-lib: Update cozy-ui dependency to v70.5.1 ( ce13857 ) Update eslint-config-cozy-app ( d86a9ec ) BREAKING CHANGES \u00b6 Removing Vue linting We were a bit behind in versions, bugs started to leak in our lints. These version upgrades should fix them, but they also have a small chance to detect new lint errors. 4.2.1 (2022-08-01) \u00b6 Bug Fixes \u00b6 node: Upgrade to Node 16 ( 3a82521 ) 4.2.0 (2022-06-10) \u00b6 Features \u00b6 Upgrade eslint-plugin-react-hooks ( b8d3895 ) 4.1.1 (2022-06-10) \u00b6 Bug Fixes \u00b6 eslint-config-cozy-app: Settings for react ( 37dbedb ) 4.1.0 (2022-06-09) \u00b6 Features \u00b6 eslint-config: Add react/jsx-curly-brace-presence rule ( be2e0a9 ), closes #1549 4.0.2 (2022-04-22) \u00b6 Bug Fixes \u00b6 eslint-config: Add rule for Windows user ( 58918cf ) 4.0.1 (2022-04-14) \u00b6 Bug Fixes \u00b6 eslint-config: Upgrade dependencies ( 7a3111a ) 4.0.0 (2022-01-07) \u00b6 Features \u00b6 eslint: Propose Eslint plugin promise ( 1fded18 ) BREAKING CHANGES \u00b6 eslint: Most errors are not auto fixable, if needed, use // disable-next-line Or insert in .eslintrc: { \u201crules\u201d: { \u201cpromise/always-return\u201d: \u201cwarn\u201d, \u201cpromise/no-return-wrap\u201d: \u201cwarn\u201d, \u201cpromise/param-names\u201d: \u201cwarn\u201d, \u201cpromise/catch-or-return\u201d: \u201cwarn\u201d, \u201cpromise/no-native\u201d: \u201cwarn\u201d, \u201cpromise/no-nesting\u201d: \u201cwarn\u201d, \u201cpromise/no-promise-in-callback\u201d: \u201cwarn\u201d, \u201cpromise/no-callback-in-promise\u201d: \u201cwarn\u201d, \u201cpromise/avoid-new\u201d: \u201cwarn\u201d, \u201cpromise/no-new-statics\u201d: \u201cwarn\u201d, \u201cpromise/no-return-in-finally\u201d: \u201cwarn\u201d, \u201cpromise/valid-params\u201d: \u201cwarn\u201d } } 3.0.1 (2022-01-01) \u00b6 Bug Fixes \u00b6 Update eslint config to better handle TS projects ( 5d35039 ) 3.0.0 (2021-12-02) \u00b6 Features \u00b6 Add confirm trusted recipients dialog ( dfe1695 ) Handle Typescript files in eslint and babel configs ( fe658ed ) BREAKING CHANGES \u00b6 upgrade from eslint 5 to eslint 8 upgrade prettier from 1 to 2 you\u2019ll need to run \u2013fix to fix lint issues after the upgrade. Few errors are not auto fixable, you can // disable-next-line if needed 2.1.1 (2021-09-03) \u00b6 Bug Fixes \u00b6 deps: update dependency eslint-plugin-react to v7.24.0 ( 43af8c1 ) 2.1.0 (2021-02-12) \u00b6 Features \u00b6 Add finance theme ( bb8cf35 ) 2.0.0 (2020-10-01) \u00b6 Bug Fixes \u00b6 Lint issue ( aa10617 ) Features \u00b6 Throw error if comments are not spaced ( 6dae942 ) BREAKING CHANGES \u00b6 Comments without starting with a space will throw an error. To fix them, you should run lint \u2013fix 1.6.0 (2020-09-01) \u00b6 Features \u00b6 Activate the no-param-reassign rule ( 4bf903f ), closes #1073 1.5.0 (2020-02-14) \u00b6 Features \u00b6 Adds no-console as eslint errors ( e5605fd ) 1.4.0 (2020-01-21) \u00b6 Features \u00b6 eslint-config-cozy-app: Add react-hooks plugin ( 6bea38b ) 1.3.4 (2020-01-06) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.3.3 (2019-10-07) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.3.2 (2019-09-16) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.3.1 (2019-09-05) \u00b6 Bug Fixes \u00b6 deps: update dependency eslint-config-prettier to v4.3.0 ( b92900c ) 1.3.0 (2019-09-05) \u00b6 Features \u00b6 Add account route ( 7986708 ) 1.2.3 (2019-09-04) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.2.2 (2019-08-21) \u00b6 Bug Fixes \u00b6 deps: update dependency eslint-plugin-prettier to v3.1.0 ( 96d689f ) 1.2.1 (2019-08-20) \u00b6 Bug Fixes \u00b6 Only use defaultDir in the manifest ( dee6277 ) 1.2.0 (2019-07-18) \u00b6 Bug Fixes \u00b6 eslint-config-cozy-app: Update eslint-plugin-vue to v5.2.3 ( #663 ) ( 8049e10 ) Features \u00b6 cozy-doctypes: Add BankAccountStats model ( 4535696 ) 1.1.12 (2019-03-12) \u00b6 Bug Fixes \u00b6 deps: update dependency eslint-config-prettier to v4 ( 1825941 ) deps: Update dependency eslint-plugin-vue to v5.2.2 ( 536670d ) 1.1.11 (2019-03-12) \u00b6 Bug Fixes \u00b6 deps: update dependency prettier to v1.16.4 ( 0bbe7ac ) 1.1.10 (2019-03-08) \u00b6 Bug Fixes \u00b6 deps: update dependency eslint to v5.15.1 ( #79 ) ( 21c246a ) 1.1.9 (2019-03-04) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.1.8 (2019-01-21) \u00b6 Bug Fixes \u00b6 deps: update dependency eslint-config-prettier to v3 ( c146f84 ) 1.1.7 (2019-01-03) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.1.6 (2019-01-03) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.1.5 (2018-12-10) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.1.4 (2018-10-17) \u00b6 Bug Fixes \u00b6 eslint-config-cozy-app: Use latest react version ( 69c5b05 ) 1.1.3 (2018-09-21) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.1.2 (2018-09-21) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.1.1 (2018-08-22) \u00b6 Note: Version bump only for package eslint-config-cozy-app 1.1.0 (2018-08-09) \u00b6 Features \u00b6 import babel and eslint cozy-app from create-cozy-app ( 0a3ab19 )", "title": "Change Log"}, {"location": "eslint-config-cozy-app/CHANGELOG/#change-log", "text": "All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.", "title": "Change Log"}, {"location": "eslint-config-cozy-app/CHANGELOG/#610-2023-03-06", "text": "", "title": "6.1.0 (2023-03-06)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features", "text": "eslint-config-cozy-app: Update rules ( 1fffa41 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#600-2023-03-02", "text": "", "title": "6.0.0 (2023-03-02)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_1", "text": "Add new rules to the config ( 84c3157 ) Remove Vue rules ( a61e28d ) Update dependencies to peerDeps ( a556dcb )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#breaking-changes", "text": "As eslint flat config is still experimental, it\u2019s better to rely on the peerDep patterns. When using this config, it will be needed to install the peerDeps.", "title": "BREAKING CHANGES"}, {"location": "eslint-config-cozy-app/CHANGELOG/#550-2023-02-11", "text": "", "title": "5.5.0 (2023-02-11)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_2", "text": "Upgrade eslint cozy config ( 414c1ef )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#540-2023-01-31", "text": "", "title": "5.4.0 (2023-01-31)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_3", "text": "Update cozy-client and cozy-ui ( 6ae3b04 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#530-2023-01-27", "text": "", "title": "5.3.0 (2023-01-27)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_4", "text": "Add tax_notice aquisitionSteps ( 7dc2ce6 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#520-2022-11-28", "text": "", "title": "5.2.0 (2022-11-28)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes", "text": "mespapiers: Breaking change of cozy-ui 77 ( be3098e )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_5", "text": "Update eslint-config-cozy-app ( a0a55db )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#511-2022-10-03", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "5.1.1 (2022-10-03)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#510-2022-09-12", "text": "", "title": "5.1.0 (2022-09-12)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_6", "text": "Add new extend for TS files in lint conf ( 70c0370 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#500-2022-08-31", "text": "", "title": "5.0.0 (2022-08-31)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_7", "text": "mespapiers-lib: Update cozy-ui dependency to v70.5.1 ( ce13857 ) Update eslint-config-cozy-app ( d86a9ec )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#breaking-changes_1", "text": "Removing Vue linting We were a bit behind in versions, bugs started to leak in our lints. These version upgrades should fix them, but they also have a small chance to detect new lint errors.", "title": "BREAKING CHANGES"}, {"location": "eslint-config-cozy-app/CHANGELOG/#421-2022-08-01", "text": "", "title": "4.2.1 (2022-08-01)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_1", "text": "node: Upgrade to Node 16 ( 3a82521 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#420-2022-06-10", "text": "", "title": "4.2.0 (2022-06-10)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_8", "text": "Upgrade eslint-plugin-react-hooks ( b8d3895 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#411-2022-06-10", "text": "", "title": "4.1.1 (2022-06-10)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_2", "text": "eslint-config-cozy-app: Settings for react ( 37dbedb )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#410-2022-06-09", "text": "", "title": "4.1.0 (2022-06-09)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_9", "text": "eslint-config: Add react/jsx-curly-brace-presence rule ( be2e0a9 ), closes #1549", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#402-2022-04-22", "text": "", "title": "4.0.2 (2022-04-22)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_3", "text": "eslint-config: Add rule for Windows user ( 58918cf )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#401-2022-04-14", "text": "", "title": "4.0.1 (2022-04-14)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_4", "text": "eslint-config: Upgrade dependencies ( 7a3111a )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#400-2022-01-07", "text": "", "title": "4.0.0 (2022-01-07)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_10", "text": "eslint: Propose Eslint plugin promise ( 1fded18 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#breaking-changes_2", "text": "eslint: Most errors are not auto fixable, if needed, use // disable-next-line Or insert in .eslintrc: { \u201crules\u201d: { \u201cpromise/always-return\u201d: \u201cwarn\u201d, \u201cpromise/no-return-wrap\u201d: \u201cwarn\u201d, \u201cpromise/param-names\u201d: \u201cwarn\u201d, \u201cpromise/catch-or-return\u201d: \u201cwarn\u201d, \u201cpromise/no-native\u201d: \u201cwarn\u201d, \u201cpromise/no-nesting\u201d: \u201cwarn\u201d, \u201cpromise/no-promise-in-callback\u201d: \u201cwarn\u201d, \u201cpromise/no-callback-in-promise\u201d: \u201cwarn\u201d, \u201cpromise/avoid-new\u201d: \u201cwarn\u201d, \u201cpromise/no-new-statics\u201d: \u201cwarn\u201d, \u201cpromise/no-return-in-finally\u201d: \u201cwarn\u201d, \u201cpromise/valid-params\u201d: \u201cwarn\u201d } }", "title": "BREAKING CHANGES"}, {"location": "eslint-config-cozy-app/CHANGELOG/#301-2022-01-01", "text": "", "title": "3.0.1 (2022-01-01)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_5", "text": "Update eslint config to better handle TS projects ( 5d35039 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#300-2021-12-02", "text": "", "title": "3.0.0 (2021-12-02)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_11", "text": "Add confirm trusted recipients dialog ( dfe1695 ) Handle Typescript files in eslint and babel configs ( fe658ed )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#breaking-changes_3", "text": "upgrade from eslint 5 to eslint 8 upgrade prettier from 1 to 2 you\u2019ll need to run \u2013fix to fix lint issues after the upgrade. Few errors are not auto fixable, you can // disable-next-line if needed", "title": "BREAKING CHANGES"}, {"location": "eslint-config-cozy-app/CHANGELOG/#211-2021-09-03", "text": "", "title": "2.1.1 (2021-09-03)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_6", "text": "deps: update dependency eslint-plugin-react to v7.24.0 ( 43af8c1 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#210-2021-02-12", "text": "", "title": "2.1.0 (2021-02-12)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_12", "text": "Add finance theme ( bb8cf35 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#200-2020-10-01", "text": "", "title": "2.0.0 (2020-10-01)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_7", "text": "Lint issue ( aa10617 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_13", "text": "Throw error if comments are not spaced ( 6dae942 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#breaking-changes_4", "text": "Comments without starting with a space will throw an error. To fix them, you should run lint \u2013fix", "title": "BREAKING CHANGES"}, {"location": "eslint-config-cozy-app/CHANGELOG/#160-2020-09-01", "text": "", "title": "1.6.0 (2020-09-01)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_14", "text": "Activate the no-param-reassign rule ( 4bf903f ), closes #1073", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#150-2020-02-14", "text": "", "title": "1.5.0 (2020-02-14)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_15", "text": "Adds no-console as eslint errors ( e5605fd )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#140-2020-01-21", "text": "", "title": "1.4.0 (2020-01-21)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_16", "text": "eslint-config-cozy-app: Add react-hooks plugin ( 6bea38b )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#134-2020-01-06", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.3.4 (2020-01-06)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#133-2019-10-07", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.3.3 (2019-10-07)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#132-2019-09-16", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.3.2 (2019-09-16)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#131-2019-09-05", "text": "", "title": "1.3.1 (2019-09-05)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_8", "text": "deps: update dependency eslint-config-prettier to v4.3.0 ( b92900c )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#130-2019-09-05", "text": "", "title": "1.3.0 (2019-09-05)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_17", "text": "Add account route ( 7986708 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#123-2019-09-04", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.2.3 (2019-09-04)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#122-2019-08-21", "text": "", "title": "1.2.2 (2019-08-21)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_9", "text": "deps: update dependency eslint-plugin-prettier to v3.1.0 ( 96d689f )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#121-2019-08-20", "text": "", "title": "1.2.1 (2019-08-20)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_10", "text": "Only use defaultDir in the manifest ( dee6277 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#120-2019-07-18", "text": "", "title": "1.2.0 (2019-07-18)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_11", "text": "eslint-config-cozy-app: Update eslint-plugin-vue to v5.2.3 ( #663 ) ( 8049e10 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_18", "text": "cozy-doctypes: Add BankAccountStats model ( 4535696 )", "title": "Features"}, {"location": "eslint-config-cozy-app/CHANGELOG/#1112-2019-03-12", "text": "", "title": "1.1.12 (2019-03-12)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_12", "text": "deps: update dependency eslint-config-prettier to v4 ( 1825941 ) deps: Update dependency eslint-plugin-vue to v5.2.2 ( 536670d )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#1111-2019-03-12", "text": "", "title": "1.1.11 (2019-03-12)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_13", "text": "deps: update dependency prettier to v1.16.4 ( 0bbe7ac )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#1110-2019-03-08", "text": "", "title": "1.1.10 (2019-03-08)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_14", "text": "deps: update dependency eslint to v5.15.1 ( #79 ) ( 21c246a )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#119-2019-03-04", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.1.9 (2019-03-04)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#118-2019-01-21", "text": "", "title": "1.1.8 (2019-01-21)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_15", "text": "deps: update dependency eslint-config-prettier to v3 ( c146f84 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#117-2019-01-03", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.1.7 (2019-01-03)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#116-2019-01-03", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.1.6 (2019-01-03)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#115-2018-12-10", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.1.5 (2018-12-10)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#114-2018-10-17", "text": "", "title": "1.1.4 (2018-10-17)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#bug-fixes_16", "text": "eslint-config-cozy-app: Use latest react version ( 69c5b05 )", "title": "Bug Fixes"}, {"location": "eslint-config-cozy-app/CHANGELOG/#113-2018-09-21", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.1.3 (2018-09-21)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#112-2018-09-21", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.1.2 (2018-09-21)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#111-2018-08-22", "text": "Note: Version bump only for package eslint-config-cozy-app", "title": "1.1.1 (2018-08-22)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#110-2018-08-09", "text": "", "title": "1.1.0 (2018-08-09)"}, {"location": "eslint-config-cozy-app/CHANGELOG/#features_19", "text": "import babel and eslint cozy-app from create-cozy-app ( 0a3ab19 )", "title": "Features"}, {"location": "faq/", "text": "Frequently Asked Questions \u00b6 Before starting Security", "title": "Frequently Asked Questions"}, {"location": "faq/#frequently-asked-questions", "text": "Before starting Security", "title": "Frequently Asked Questions"}, {"location": "faq/security/", "text": "Security \u00b6 Are my data encrypted? \u00b6 No Where are my data hosted? \u00b6 On our servers. In the cloud.", "title": "Security {: .faq}"}, {"location": "faq/security/#security", "text": "", "title": "Security"}, {"location": "faq/security/#are-my-data-encrypted", "text": "No", "title": "Are my data encrypted?"}, {"location": "faq/security/#where-are-my-data-hosted", "text": "On our servers. In the cloud.", "title": "Where are my data hosted?"}, {"location": "faq/start/", "text": "", "title": "Start"}, {"location": "howTos/dev/connect-mobile-app-local-stack/", "text": "Sometimes we need to test a feature on a mobile app by connecting it to our locally installed stack. For this to work, we need to achieve some things. Prerequisite \u00b6 Have a local stack installed Have an Android emulator created Start the emulator with the ability to remount its file system as writable \u00b6 Since we will need to edit the hosts of the emulator, we need to be able to remount its file system as writable. For that, we need to start our emulator with the following command: ./emulator -writable-system -avd Pixel_API_27 The emulator binary is located at /home/user/Android/Sdk/emulator/ on Linux systems by default. Pixel_API_27 is the name of the emulator I want to start. If you don\u2019t know the name of your emulator, you can get it with: ./emulator -list-avds Root the emulator \u00b6 Now that the emulator is started, we need to gain root access on it. Run the following command: adb root This restarts the adb daemon with root privileges. Remount the file system as writable \u00b6 By default, the file system is read-only. We need it to be writable, so we run this command: adb remount Pull the emulator\u2019s hosts file \u00b6 To edit the hosts file, we need to pull it on our system: adb pull /etc/hosts hosts This creates a hosts file in your current directory. Edit the hosts \u00b6 For the emulator to be able to connect to our stack, we need to add the IP address of our machine to the hosts. Actually, we don\u2019t really need it since in an Android emulator 10.0.2.2 is automatically pointing to our machine. So we just need to add this to the hosts file: 10.0.2.2 cozy.tools Push the new file to the emulator \u00b6 Now that we have added what\u2019s necessary in the file, we have to push it to the emulator: adb push hosts /system/etc/hosts Then try to ping cozy.tools to see if everything is working well: adb shell ping cozy.tools You can now enter http://cozy.tools in the login page of your mobile app and you will not get an error anymore.", "title": "Connect a Mobile App to Your Local Stack"}, {"location": "howTos/dev/connect-mobile-app-local-stack/#prerequisite", "text": "Have a local stack installed Have an Android emulator created", "title": "Prerequisite"}, {"location": "howTos/dev/connect-mobile-app-local-stack/#start-the-emulator-with-the-ability-to-remount-its-file-system-as-writable", "text": "Since we will need to edit the hosts of the emulator, we need to be able to remount its file system as writable. For that, we need to start our emulator with the following command: ./emulator -writable-system -avd Pixel_API_27 The emulator binary is located at /home/user/Android/Sdk/emulator/ on Linux systems by default. Pixel_API_27 is the name of the emulator I want to start. If you don\u2019t know the name of your emulator, you can get it with: ./emulator -list-avds", "title": "Start the emulator with the ability to remount its file system as writable"}, {"location": "howTos/dev/connect-mobile-app-local-stack/#root-the-emulator", "text": "Now that the emulator is started, we need to gain root access on it. Run the following command: adb root This restarts the adb daemon with root privileges.", "title": "Root the emulator"}, {"location": "howTos/dev/connect-mobile-app-local-stack/#remount-the-file-system-as-writable", "text": "By default, the file system is read-only. We need it to be writable, so we run this command: adb remount", "title": "Remount the file system as writable"}, {"location": "howTos/dev/connect-mobile-app-local-stack/#pull-the-emulators-hosts-file", "text": "To edit the hosts file, we need to pull it on our system: adb pull /etc/hosts hosts This creates a hosts file in your current directory.", "title": "Pull the emulator's hosts file"}, {"location": "howTos/dev/connect-mobile-app-local-stack/#edit-the-hosts", "text": "For the emulator to be able to connect to our stack, we need to add the IP address of our machine to the hosts. Actually, we don\u2019t really need it since in an Android emulator 10.0.2.2 is automatically pointing to our machine. So we just need to add this to the hosts file: 10.0.2.2 cozy.tools", "title": "Edit the hosts"}, {"location": "howTos/dev/connect-mobile-app-local-stack/#push-the-new-file-to-the-emulator", "text": "Now that we have added what\u2019s necessary in the file, we have to push it to the emulator: adb push hosts /system/etc/hosts Then try to ping cozy.tools to see if everything is working well: adb shell ping cozy.tools You can now enter http://cozy.tools in the login page of your mobile app and you will not get an error anymore.", "title": "Push the new file to the emulator"}, {"location": "howTos/dev/cordova/", "text": "The simplest way to create a mobile Cozy application is to use JavaScript as there already are JavaScript libraries to connect to the Cozy server, as known as cozy-stack. Therefore we will use the classical stack: a JavaScript web application and cordova At the end of this documentation , you will find how-tos to help you with cordova configuration , webpack builds and cordova deployments for Android and iOS . To create your first Cozy application , just follow the guide. As you can read there, Cozy applications are served by the Cozy server, this is the way that Cozy applications retrieve a token to query data. In the case of a mobile application, you need to retrieve a token differently. Hopefully we provide everything you need to do it easily. You\u2019ll need two libraries: cozy-client ( source ) cozy-bar ( source ) In the case of Cozy web applications served by the Cozy server, these two libraries are injected in the html file with variables {{.CozyClientJS}} and {{.CozyBar}} . Setup index.html \u00b6 First thing first, add JavaScript libraries files into your index.html : < html lang = \"en\" > < head > < meta charset = \"utf-8\" > < title > mobile Cozy application with Cordova < script src = \"cozy-client.js\" > < script src = \"cozy-bar.js\" > < body > Connect to Cozy server \u00b6 When an user will start your mobile Cozy application, she/he will need to point to her/his server url to ask for permissions for her/his device. This is done by our library cozy-client , you just need to add a HTML form: < form id = \"form\" > < label > What is your cozy server url? < input name = \"url\" id = \"url\" type = \"text\" /> < button type = \"submit\" > Submit const urlInput = document . getElementById ( \"url\" ); const form = document . getElementById ( \"form\" ); form . addEventListener ( \"submit\" , registerClient ); function registerClient ( event ) { event . preventDefault (); const url = urlInput . value ; const { client , token } = await cozyClient . register ( url ); // do whatever you need with client and token like persist } JS Bin on jsbin.com When cozyClient.register(url) is called, the cordova inapp browser plugin is used to display a password request and a permission acceptation page to let the end-user to register her/his device. That\u2019s all! Then you can use the cozy-client library as you would within a classic Cozy application . Initialize the Cozy bar \u00b6 The Cozy bar needs some information to be initialized and its initialization must be done in your front-end code: cozy . bar . init ({ appName : \"App Name\" , iconPath : require ( \"./assets/app-icon.svg\" ), lang : \"en-US\" , replaceTitleOnMobile : true }) Use Cordova \u00b6 Install and setup cordova \u00b6 Cordova is a tool to build Android and iOS applications from a web app. It works with a CLI that needs node . Look at the cordova documentation to install everything needed . Once cordova is installed, just run cordova create cozy-app com.example.cozyapp CozyApp and you get the following structure: ./ \u251c\u2500\u2500 config.xml \u251c\u2500\u2500 hooks \u2502 \u2514\u2500\u2500 README.md \u251c\u2500\u2500 platforms \u251c\u2500\u2500 plugins \u2514\u2500\u2500 www \u251c\u2500\u2500 css \u2502 \u2514\u2500\u2500 index.css \u251c\u2500\u2500 img \u2502 \u2514\u2500\u2500 logo.png \u251c\u2500\u2500 index.html \u2514\u2500\u2500 js \u2514\u2500\u2500 index.js 7 directories, 6 files Note: everything you put in www/ will be served as your application content. Configure your build tool \u00b6 If you use a build tool to transpile your JavaScript code, you need to configure your tool to output the build into www/ . webpack configuration \u00b6 As Webpack is the most used build tool we will show you how to configure it with cordova: Create a webpack.config.js on the root folder of your project with: const path = require ( 'path' ); module . exports = { entry : './src/app.js' , output : { filename : 'bundle.js' , path . resolve ( __dirname , 'www' ) } } And add the output bundle in the www/index.html file: < html > < head > ... < body > ... < script src = \"bundle.js\" > See the official webpack documentation for more details. Cordova \u00b6 Android Platform \u00b6 Use cordova platform add android and check your environment with cordova requirements : A bad requirements check: Requirements check results for android: Java JDK: installed . Android SDK: installed Android target: not installed Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable. Gradle: installed Error: Some of requirements check failed A good requirements check: Requirements check results for android: Java JDK: installed . Android SDK: installed Android target: installed android-19,android-21,android-22,android-23,Google Inc.:Google APIs:19,Google Inc.:Google APIs (x86 System Image):19,Google Inc.:Google APIs:23 Gradle: installed See cordova, android and ios documentation to customize your development environment for your special needs. Once everything is right, you could run cordova build and cordova run android to create an APK and push the APK on a device. Note: The device should be connected with usb. See official android documentation for more details . iOS development \u00b6 For building an iOS app, you need xcode . See further details on the cordova official documentation about iOS .", "title": "Make a Mobile App Using Cordova"}, {"location": "howTos/dev/cordova/#setup-indexhtml", "text": "First thing first, add JavaScript libraries files into your index.html : < html lang = \"en\" > < head > < meta charset = \"utf-8\" > < title > mobile Cozy application with Cordova < script src = \"cozy-client.js\" > < script src = \"cozy-bar.js\" > < body > ", "title": "Setup index.html"}, {"location": "howTos/dev/cordova/#connect-to-cozy-server", "text": "When an user will start your mobile Cozy application, she/he will need to point to her/his server url to ask for permissions for her/his device. This is done by our library cozy-client , you just need to add a HTML form: < form id = \"form\" > < label > What is your cozy server url? < input name = \"url\" id = \"url\" type = \"text\" /> < button type = \"submit\" > Submit const urlInput = document . getElementById ( \"url\" ); const form = document . getElementById ( \"form\" ); form . addEventListener ( \"submit\" , registerClient ); function registerClient ( event ) { event . preventDefault (); const url = urlInput . value ; const { client , token } = await cozyClient . register ( url ); // do whatever you need with client and token like persist } JS Bin on jsbin.com When cozyClient.register(url) is called, the cordova inapp browser plugin is used to display a password request and a permission acceptation page to let the end-user to register her/his device. That\u2019s all! Then you can use the cozy-client library as you would within a classic Cozy application .", "title": "Connect to Cozy server"}, {"location": "howTos/dev/cordova/#initialize-the-cozy-bar", "text": "The Cozy bar needs some information to be initialized and its initialization must be done in your front-end code: cozy . bar . init ({ appName : \"App Name\" , iconPath : require ( \"./assets/app-icon.svg\" ), lang : \"en-US\" , replaceTitleOnMobile : true })", "title": "Initialize the Cozy bar"}, {"location": "howTos/dev/cordova/#use-cordova", "text": "", "title": "Use Cordova"}, {"location": "howTos/dev/cordova/#install-and-setup-cordova", "text": "Cordova is a tool to build Android and iOS applications from a web app. It works with a CLI that needs node . Look at the cordova documentation to install everything needed . Once cordova is installed, just run cordova create cozy-app com.example.cozyapp CozyApp and you get the following structure: ./ \u251c\u2500\u2500 config.xml \u251c\u2500\u2500 hooks \u2502 \u2514\u2500\u2500 README.md \u251c\u2500\u2500 platforms \u251c\u2500\u2500 plugins \u2514\u2500\u2500 www \u251c\u2500\u2500 css \u2502 \u2514\u2500\u2500 index.css \u251c\u2500\u2500 img \u2502 \u2514\u2500\u2500 logo.png \u251c\u2500\u2500 index.html \u2514\u2500\u2500 js \u2514\u2500\u2500 index.js 7 directories, 6 files Note: everything you put in www/ will be served as your application content.", "title": "Install and setup cordova"}, {"location": "howTos/dev/cordova/#configure-your-build-tool", "text": "If you use a build tool to transpile your JavaScript code, you need to configure your tool to output the build into www/ .", "title": "Configure your build tool"}, {"location": "howTos/dev/cordova/#webpack-configuration", "text": "As Webpack is the most used build tool we will show you how to configure it with cordova: Create a webpack.config.js on the root folder of your project with: const path = require ( 'path' ); module . exports = { entry : './src/app.js' , output : { filename : 'bundle.js' , path . resolve ( __dirname , 'www' ) } } And add the output bundle in the www/index.html file: < html > < head > ... < body > ... < script src = \"bundle.js\" > See the official webpack documentation for more details.", "title": "webpack configuration"}, {"location": "howTos/dev/cordova/#cordova", "text": "", "title": "Cordova"}, {"location": "howTos/dev/cordova/#android-platform", "text": "Use cordova platform add android and check your environment with cordova requirements : A bad requirements check: Requirements check results for android: Java JDK: installed . Android SDK: installed Android target: not installed Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable. Gradle: installed Error: Some of requirements check failed A good requirements check: Requirements check results for android: Java JDK: installed . Android SDK: installed Android target: installed android-19,android-21,android-22,android-23,Google Inc.:Google APIs:19,Google Inc.:Google APIs (x86 System Image):19,Google Inc.:Google APIs:23 Gradle: installed See cordova, android and ios documentation to customize your development environment for your special needs. Once everything is right, you could run cordova build and cordova run android to create an APK and push the APK on a device. Note: The device should be connected with usb. See official android documentation for more details .", "title": "Android Platform"}, {"location": "howTos/dev/cordova/#ios-development", "text": "For building an iOS app, you need xcode . See further details on the cordova official documentation about iOS .", "title": "iOS development"}, {"location": "howTos/dev/hmr/", "text": "What is Hot Module Replacement (HMR) ? \u00b6 As the Webpack documentation says: Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways: Retain application state which is lost during a full reload. Save valuable development time by only updating what\u2019s changed. Modifications made to CSS/JS in the source code results in an instant browser update which is almost comparable to changing styles directly in the browser\u2019s dev tools. For a Cozy application, having this feature allows you to have the specific changed part reloaded in your browser without reloading again the cozy-bar , the cozy-client and other layout components. Notice: The HMR will be explained here only for applications build using Webpack. Is it available for my app? \u00b6 If you created your application (React or Vue) using Create Cozy App a.k.a CCA (from v1) and: For React, you didn\u2019t change the way react-hot-loader is used For Vue, you didn\u2019t change the module.hot part in your entry point index.js (in src/targets/ ) Then, you dont\u2019 have anything to do. See the next part of this tutorial to use HMR \ud83d\ude0e If you did change these parts or you didn\u2019t create your application initialy using Create Cozy App , you can see the part Make HMR available in my application . Run my app with HMR \u00b6 To have a full HMR experience, you\u2019ll have to do two things here: Run webpack watching your changes with a webpack-dev-server and --hot option Disable CSPs in the target Cozy (the Cozy CSPs is blocking HMR script) But thanks to the last version of cozy-scripts , all of that are handled for you with the command cozy-scripts start : yarn cozy-scripts start --hot --browser # or if you have the last package.json from CCA, you can do yarn start How can I run my webpack and my stack in different terminals? \u00b6 First, you can pass an option to disable the stack handling by the start command: yarn cozy-scripts start --hot --browser --no-stack # or if you have the last package.json from CCA, you can do yarn start --no-stack Then, as said, to have your application running in a Cozy with HMR, your have to disable CSPs when running the stack. For that, cozy-scripts has a dedicated config file to pass to your Docker image in cozy-scripts/stack/disableCSP.yaml . You can use this config by running your stack in another terminal like: # in your app root directory docker run --rm -it -p 8080 :8080 -p 5984 :5984 -v \\\" $( pwd ) /build \\\" :/data/cozy-app/app -v \\\" $( pwd ) /node_modules/cozy-scripts/stack/disableCSP.yaml \\\" :/etc/cozy/cozy.yaml cozy/cozy-app-dev Make HMR available in my application \u00b6 For a React application \u00b6 You have to use react-hot-loader inside your main App component like this: import React from 'react' import { hot } from 'react-hot-loader' const App = () => ( ... ) export default hot ( module )( App ) That\u2019s it. Then, just use the last version of cozy-scripts to run your application with HMR. For a Vue application \u00b6 Inside your entry point index.js (in src/targets/ ), you have to add this part related to module.hot : import Vue from 'vue' import store from 'lib/store' const renderApp = function () { const App = require ( 'components/App' ). default return new Vue ({ store , // inject store to all children el : '[role=application]' , render : h => h ( App ) }) } if ( module . hot ) { module . hot . accept ( 'components/App' , function () { renderApp () }) } That\u2019s it. Then, just use the last version of cozy-scripts to run your application with HMR .", "title": "Use Hot Module Replacement in Your App"}, {"location": "howTos/dev/hmr/#what-is-hot-module-replacement-hmr", "text": "As the Webpack documentation says: Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways: Retain application state which is lost during a full reload. Save valuable development time by only updating what\u2019s changed. Modifications made to CSS/JS in the source code results in an instant browser update which is almost comparable to changing styles directly in the browser\u2019s dev tools. For a Cozy application, having this feature allows you to have the specific changed part reloaded in your browser without reloading again the cozy-bar , the cozy-client and other layout components. Notice: The HMR will be explained here only for applications build using Webpack.", "title": "What is Hot Module Replacement (HMR) ?"}, {"location": "howTos/dev/hmr/#is-it-available-for-my-app", "text": "If you created your application (React or Vue) using Create Cozy App a.k.a CCA (from v1) and: For React, you didn\u2019t change the way react-hot-loader is used For Vue, you didn\u2019t change the module.hot part in your entry point index.js (in src/targets/ ) Then, you dont\u2019 have anything to do. See the next part of this tutorial to use HMR \ud83d\ude0e If you did change these parts or you didn\u2019t create your application initialy using Create Cozy App , you can see the part Make HMR available in my application .", "title": "Is it available for my app?"}, {"location": "howTos/dev/hmr/#run-my-app-with-hmr", "text": "To have a full HMR experience, you\u2019ll have to do two things here: Run webpack watching your changes with a webpack-dev-server and --hot option Disable CSPs in the target Cozy (the Cozy CSPs is blocking HMR script) But thanks to the last version of cozy-scripts , all of that are handled for you with the command cozy-scripts start : yarn cozy-scripts start --hot --browser # or if you have the last package.json from CCA, you can do yarn start", "title": "Run my app with HMR"}, {"location": "howTos/dev/hmr/#how-can-i-run-my-webpack-and-my-stack-in-different-terminals", "text": "First, you can pass an option to disable the stack handling by the start command: yarn cozy-scripts start --hot --browser --no-stack # or if you have the last package.json from CCA, you can do yarn start --no-stack Then, as said, to have your application running in a Cozy with HMR, your have to disable CSPs when running the stack. For that, cozy-scripts has a dedicated config file to pass to your Docker image in cozy-scripts/stack/disableCSP.yaml . You can use this config by running your stack in another terminal like: # in your app root directory docker run --rm -it -p 8080 :8080 -p 5984 :5984 -v \\\" $( pwd ) /build \\\" :/data/cozy-app/app -v \\\" $( pwd ) /node_modules/cozy-scripts/stack/disableCSP.yaml \\\" :/etc/cozy/cozy.yaml cozy/cozy-app-dev", "title": "How can I run my webpack and my stack in different terminals?"}, {"location": "howTos/dev/hmr/#make-hmr-available-in-my-application", "text": "", "title": "Make HMR available in my application"}, {"location": "howTos/dev/hmr/#for-a-react-application", "text": "You have to use react-hot-loader inside your main App component like this: import React from 'react' import { hot } from 'react-hot-loader' const App = () => ( ... ) export default hot ( module )( App ) That\u2019s it. Then, just use the last version of cozy-scripts to run your application with HMR.", "title": "For a React application"}, {"location": "howTos/dev/hmr/#for-a-vue-application", "text": "Inside your entry point index.js (in src/targets/ ), you have to add this part related to module.hot : import Vue from 'vue' import store from 'lib/store' const renderApp = function () { const App = require ( 'components/App' ). default return new Vue ({ store , // inject store to all children el : '[role=application]' , render : h => h ( App ) }) } if ( module . hot ) { module . hot . accept ( 'components/App' , function () { renderApp () }) } That\u2019s it. Then, just use the last version of cozy-scripts to run your application with HMR .", "title": "For a Vue application"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/", "text": "Running connectors to test them with a local cozy-stack gives a quick feedback loop but requires a little setup. Prerequisite \u00b6 Have a local cozy-stack installed Have NodeJS installed at the system level Copy the default config file if not already done \u00b6 Create a directory ~/.cozy and copy the default configuration file into it. Be careful, the file name and location matter, as explained in the config documentation . cp cozy-stack/cozy.example.yaml ~/.cozy/cozy.yaml ` Edit the config file \u00b6 Edit the file ~/.cozy/cozy.yaml and change the line after the konnectors: entry to have this: cmd : /home/alice/.cozy/scripts/konnector-node-run.sh Create the script to execute the service \u00b6 Copy the file cozy-stack/scripts/konnector-node-run.sh to ~/.cozy/konnector-node-run.sh : Then you need to chmod +x ~/.cozy/scripts/konnector-node-run.sh Be sure to have node in your /usr/bin or /usr/local/bin folder. If not, you can add a symlink to node in one of those folder, for example by typing ln -s $(which node) /usr/local/bin/node Get your service logs in a isolated file \u00b6 Edit your ~/.cozy/konnector-node-run.sh by adding a tee output. set -o pipefail node \" ${ arg } \" 2 > & 1 | tee -a ~/.cozy/services.log Now you can tail -f ~/.cozy/services.log to watch logs in real time. Avoid automatic relaunch when errored \u00b6 Edit your ~/.cozy/cozy.yaml to avoid a second launch in case of error. (Already disable for LOGIN_FAILED and USER_ACTION_NEEDED) Find this option, uncomment and set to 1. jobs : workers : konnectors : max_exec_count : 1 Install your konnector \u00b6 To install the konnector containing the service on your local stack, you must give the path of your build: cozy-stack konnector install file:// # Example: # cozy-stack apps install ameli file:///home/alice/ameli/build Each time you make modifications to your builded konnector, you must update the app on the stack to propagate the changes: cozy-stack konnectors update Konnector is a service anyway \u00b6 As a konnector is subtype of service in cozy, you can look at a more global documentation here: Develop a service", "title": "Run Connectors With a Local cozy-stack"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#prerequisite", "text": "Have a local cozy-stack installed Have NodeJS installed at the system level", "title": "Prerequisite"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#copy-the-default-config-file-if-not-already-done", "text": "Create a directory ~/.cozy and copy the default configuration file into it. Be careful, the file name and location matter, as explained in the config documentation . cp cozy-stack/cozy.example.yaml ~/.cozy/cozy.yaml `", "title": "Copy the default config file if not already done"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#edit-the-config-file", "text": "Edit the file ~/.cozy/cozy.yaml and change the line after the konnectors: entry to have this: cmd : /home/alice/.cozy/scripts/konnector-node-run.sh", "title": "Edit the config file"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#create-the-script-to-execute-the-service", "text": "Copy the file cozy-stack/scripts/konnector-node-run.sh to ~/.cozy/konnector-node-run.sh : Then you need to chmod +x ~/.cozy/scripts/konnector-node-run.sh Be sure to have node in your /usr/bin or /usr/local/bin folder. If not, you can add a symlink to node in one of those folder, for example by typing ln -s $(which node) /usr/local/bin/node", "title": "Create the script to execute the service"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#get-your-service-logs-in-a-isolated-file", "text": "Edit your ~/.cozy/konnector-node-run.sh by adding a tee output. set -o pipefail node \" ${ arg } \" 2 > & 1 | tee -a ~/.cozy/services.log Now you can tail -f ~/.cozy/services.log to watch logs in real time.", "title": "Get your service logs in a isolated file"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#avoid-automatic-relaunch-when-errored", "text": "Edit your ~/.cozy/cozy.yaml to avoid a second launch in case of error. (Already disable for LOGIN_FAILED and USER_ACTION_NEEDED) Find this option, uncomment and set to 1. jobs : workers : konnectors : max_exec_count : 1", "title": "Avoid automatic relaunch when errored"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#install-your-konnector", "text": "To install the konnector containing the service on your local stack, you must give the path of your build: cozy-stack konnector install file:// # Example: # cozy-stack apps install ameli file:///home/alice/ameli/build Each time you make modifications to your builded konnector, you must update the app on the stack to propagate the changes: cozy-stack konnectors update ", "title": "Install your konnector"}, {"location": "howTos/dev/run-connectors-on-local-cozy-stack/#konnector-is-a-service-anyway", "text": "As a konnector is subtype of service in cozy, you can look at a more global documentation here: Develop a service", "title": "Konnector is a service anyway"}, {"location": "howTos/dev/runCozyDocker/", "text": "Make sure your application is built into ~/cozy/myapp (or any other path) (it should have an index.html and a manifest.webapp files), otherwise it will not work. As an example, for the Drive application , it would be ~/cozy/drive/build . Also make sure you have pulled the last version of the Docker image cozy/cozy-app-dev : docker pull cozy/cozy-app-dev On GNU/Linux, according to the documentation : \u00ab The docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. If you don\u2019t want to use sudo when you use the docker command, create a Unix group called docker and add users to it. When the Docker daemon starts, it creates a Unix socket accessible by members of the docker group. On some Linux distributions, the system automatically creates this group when installing Docker Engine using a package manager. In that case, there is no need for you to manually create the group. The docker group grants root-level privileges to the user. For details on how this impacts security in your system, see Docker Daemon Attack Surface . Notice: The default passphrase configured by cozy-stack in the Docker container is cozy . Ephemeral instance \u00b6 To run a ephemeral instance, on the ~/cozy/myapp directory, you have to mount the folder inside the server to /data/cozy-app . This is what make the application available on the server: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/myapp\" :/data/cozy-app \\ cozy/cozy-app-dev Commands explaination - `--rm` will delete the server when you stop it. This prevent Docker from keeping a lot of unused stopped images - `-it` allow to attach an interactive terminal, so you\u2019ll be able to use the command line inside the server - `-p 8080:8080`: the server listens on port 8080 on the virtual machine. We forward this port to the same port on your local machine. To use another local port, for example 9090, use `-p 9090:8080` - `-p 8025:8025`: Cozy requires a mail server. In the development image, we don\u2019t use a real email server, but a software that can display the sent messages. Just point your browser to `http://localhost:8025/` to display the messages sent by the server - `--name cozydev`: name the running virtual machine `cozydev`, so you can easily refer to it from other Docker commands. For example, if you want to connect to a shell inside the server, you can use `docker exec cozydev -it /bin/bash` - `-v \"$HOME/cozy/myapp\":/data/cozy-app`: this mount the local folder, where your application leaves, inside the container. This is what make the application available on the server With data persistence \u00b6 If you want to persist data, you have to mount two folders from the virtual server to local folders: /var/lib/couchdb (database) and /data/cozy-storage (the virtual filesystem). This can be achieved by adding two options to the command line starting with -v which will store the server\u2019s data into $HOME/cozy/data/ . $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/myapp\" :/data/cozy-app \\ -v \" $HOME /cozy/data/db\" :/var/lib/couchdb \\ -v \" $HOME /cozy/data/storage\" :/data/cozy-storage \\ cozy/cozy-app-dev Run with a custom stack config file \u00b6 The cozy-stack config file can be useful to change the log level for example. You have to load it inside /etc/cozy/cozy.yaml like this: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/myapp\" :/data/cozy-app \\ -v \" $HOME /cozy/cozy.yaml\" :/etc/cozy/cozy.yaml \\ cozy/cozy-app-dev You can learn more about the cozy-stack config file in its dedicated documentation Run two applications watched locally \u00b6 You can install more than one application into the development server, for example to test communication between applications. In order to achieve this, you have to mount the folder where your application is living into subfolders of /data/cozy-apps like this: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/appone\" :/data/cozy-app/appone \\ -v \" $HOME /cozy/apptwo\" :/data/cozy-app/apptwo \\ cozy/cozy-app-dev You\u2019ll access the applications by connecting to http://appone.cozy.localhost:8080/ and http://apptwo.cozy.localhost:8080 . Mailhog to catch e-mails and CouchDB access \u00b6 A MailHog is running inside Docker to catch emails. You can view the emails sent by the stack in a web interface on http://localhost:8025/ You can also expose the couchdb port (listening in the container on 5984) in order to access its admin page. For instance add -p 5984:5984 to access to the admin interface on http://localhost:5984/_utils .", "title": "Run an App in a Cozy using Docker"}, {"location": "howTos/dev/runCozyDocker/#ephemeral-instance", "text": "To run a ephemeral instance, on the ~/cozy/myapp directory, you have to mount the folder inside the server to /data/cozy-app . This is what make the application available on the server: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/myapp\" :/data/cozy-app \\ cozy/cozy-app-dev Commands explaination - `--rm` will delete the server when you stop it. This prevent Docker from keeping a lot of unused stopped images - `-it` allow to attach an interactive terminal, so you\u2019ll be able to use the command line inside the server - `-p 8080:8080`: the server listens on port 8080 on the virtual machine. We forward this port to the same port on your local machine. To use another local port, for example 9090, use `-p 9090:8080` - `-p 8025:8025`: Cozy requires a mail server. In the development image, we don\u2019t use a real email server, but a software that can display the sent messages. Just point your browser to `http://localhost:8025/` to display the messages sent by the server - `--name cozydev`: name the running virtual machine `cozydev`, so you can easily refer to it from other Docker commands. For example, if you want to connect to a shell inside the server, you can use `docker exec cozydev -it /bin/bash` - `-v \"$HOME/cozy/myapp\":/data/cozy-app`: this mount the local folder, where your application leaves, inside the container. This is what make the application available on the server", "title": "Ephemeral instance"}, {"location": "howTos/dev/runCozyDocker/#with-data-persistence", "text": "If you want to persist data, you have to mount two folders from the virtual server to local folders: /var/lib/couchdb (database) and /data/cozy-storage (the virtual filesystem). This can be achieved by adding two options to the command line starting with -v which will store the server\u2019s data into $HOME/cozy/data/ . $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/myapp\" :/data/cozy-app \\ -v \" $HOME /cozy/data/db\" :/var/lib/couchdb \\ -v \" $HOME /cozy/data/storage\" :/data/cozy-storage \\ cozy/cozy-app-dev", "title": "With data persistence"}, {"location": "howTos/dev/runCozyDocker/#run-with-a-custom-stack-config-file", "text": "The cozy-stack config file can be useful to change the log level for example. You have to load it inside /etc/cozy/cozy.yaml like this: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/myapp\" :/data/cozy-app \\ -v \" $HOME /cozy/cozy.yaml\" :/etc/cozy/cozy.yaml \\ cozy/cozy-app-dev You can learn more about the cozy-stack config file in its dedicated documentation", "title": "Run with a custom stack config file"}, {"location": "howTos/dev/runCozyDocker/#run-two-applications-watched-locally", "text": "You can install more than one application into the development server, for example to test communication between applications. In order to achieve this, you have to mount the folder where your application is living into subfolders of /data/cozy-apps like this: $ docker run --rm -it \\ -p 8080 :8080 \\ -p 8025 :8025 \\ --name cozydev \\ -v \" $HOME /cozy/appone\" :/data/cozy-app/appone \\ -v \" $HOME /cozy/apptwo\" :/data/cozy-app/apptwo \\ cozy/cozy-app-dev You\u2019ll access the applications by connecting to http://appone.cozy.localhost:8080/ and http://apptwo.cozy.localhost:8080 .", "title": "Run two applications watched locally"}, {"location": "howTos/dev/runCozyDocker/#mailhog-to-catch-e-mails-and-couchdb-access", "text": "A MailHog is running inside Docker to catch emails. You can view the emails sent by the stack in a web interface on http://localhost:8025/ You can also expose the couchdb port (listening in the container on 5984) in order to access its admin page. For instance add -p 5984:5984 to access to the admin interface on http://localhost:5984/_utils .", "title": "Mailhog to catch e-mails and CouchDB access"}, {"location": "howTos/dev/sendmail/", "text": "Cozy apps let users share documents from cozy to cozy . Meet Alice and Bob. Alice wants to share a folder with Bob. Alice clicks on the share button and fills in the email input with Bob\u2019s email address. Bob receives an email with a \u00ab Accept the sharing \u00bb button. Bob clicks on that button and is redirected to Alice\u2019s cozy to enter his own cozy url to link both cozys. Bob sees Alice\u2019s shared folder in his own cozy. \ud83e\udd14 But how could we do this scenario on development environment? With the docker image \u00b6 If you develop with the cozy-app-dev docker image , MailHog is running inside it to catch emails. If cozy-stack has to send an email, MailHog catches it and exposes it on its web interface on http://cozy.tools:8025/ . With the binary cozy-stack \u00b6 If you develop with the cozy-stack CLI , you have to run MailHog on your computer and tell cozy-stack serve where to find the mail server with some options : ./cozy-stack serve --appdir drive:../cozy-drive/build,settings:../cozy-settings/build --mail-disable-tls --mail-port 1025 This commands assumes you git clone cozy-drive and cozy-settings in the same folder than you git clone cozy-stack . Then simply run MailHog and open http://cozy.tools:8025/ . Retrieve sent emails \u00b6 With MailHog, every email sent by cozy-stack is caught. That means the email address does not have to be a real one , ie. bob@cozy , bob@cozy.tools are perfectly fine. It could be a real one , but the email will not reach the real recipient\u2019s inbox, say contact@cozycloud.cc .", "title": "Send and Receive E-mails in Development"}, {"location": "howTos/dev/sendmail/#with-the-docker-image", "text": "If you develop with the cozy-app-dev docker image , MailHog is running inside it to catch emails. If cozy-stack has to send an email, MailHog catches it and exposes it on its web interface on http://cozy.tools:8025/ .", "title": "With the docker image"}, {"location": "howTos/dev/sendmail/#with-the-binary-cozy-stack", "text": "If you develop with the cozy-stack CLI , you have to run MailHog on your computer and tell cozy-stack serve where to find the mail server with some options : ./cozy-stack serve --appdir drive:../cozy-drive/build,settings:../cozy-settings/build --mail-disable-tls --mail-port 1025 This commands assumes you git clone cozy-drive and cozy-settings in the same folder than you git clone cozy-stack . Then simply run MailHog and open http://cozy.tools:8025/ .", "title": "With the binary cozy-stack"}, {"location": "howTos/dev/sendmail/#retrieve-sent-emails", "text": "With MailHog, every email sent by cozy-stack is caught. That means the email address does not have to be a real one , ie. bob@cozy , bob@cozy.tools are perfectly fine. It could be a real one , but the email will not reach the real recipient\u2019s inbox, say contact@cozycloud.cc .", "title": "Retrieve sent emails"}, {"location": "howTos/dev/services/", "text": "What is it for? \u00b6 Applications may require server-side code execution that could not, or should not, be in the client. This might be useful for heavy computations or for tasks triggered after some events, typically after data is retrieved through konnectors or mobile/desktop sync, without the user being on the application. In contrast to konnectors, services have the same permissions as the web application and are not intended to collect information from the outside. It is rather meant to asynchronously analyse data inside the cozy and emit some output once the task is done. However, they share the same mechanisms as the konnectors to describe how and when they should be executed: via our trigger system . Example \u00b6 You can find an example of an existing service in the cozy-banks app . CozyClient instantiation \u00b6 By using fromEnv , you will be able to use the service in dev mode (via cozy-konnector-dev see Execution ) or in production. const client = CozyClient . fromEnv ( process . env , { schema }) You may need to add this line to your service to use the fetch for node: global . fetch = require ( 'node-fetch' ). default Service declaration \u00b6 The service must be declared in the app manifest . For example: \"services\" : { \"onOperationCreate\" : { \"type\" : \"node\" , \"file\" : \"onOperationCreate.js\" , \"trigger\" : \"@event io.cozy.bank.operations:CREATED\" , \"debounce\" : \"3m\" } } Here is an explanation of the fields: type : describe the code type (only node for now). file : the single (packaged) file containing the code to execute as a service. It must be the relative path to the built service\u2019s file, not the source one. Expl: /services/name-of-service/built-file.js . Look at your build folder or build/watch console output to find it. trigger : what triggers the service. It must follow the available triggers described in the jobs documentation . In this example, the trigger is a bank operation creation. debounce (optionnal): The debounce parameter can be used to limit the number of jobs created in a burst. It delays the creation of the job on the first input by the given time argument, and if the trigger has its condition matched again during this period, it won\u2019t create another job. Its syntax is the one understood by go\u2019s time.ParseDuration . If this parameter is omitted, the service will be executed as soon as it can. Build \u00b6 The service must be packaged into a single file containing all the dependencies. An example of a webpack rule is available here . Note that target: 'node' is important as the service is run as a Node.js process. In this example, the services are built alongside your app using yarn watch . If you use cozy-script , you should use watch and not start to have the service built. Stack \u00b6 As the service is run on a dedicated process on the server side, a running stack is necessary. You can either use a stack installed with docker or directly from source . Some configuration is required to execute the service and store the produced logs, to facilitate the development. The following instructions are for a stack installed from source, but you can adapt it for a docker installation: you have to download the default config file , modify it as described below and indicate its location through the docker command, as explained here . In the following, we assume that your $HOME is /home/alice, so change accordingly to your own $HOME . Copy the default config file if not already done \u00b6 Create a directory ~/.cozy and copy the default configuration file into it. Be careful, the file name and location matter, as explained in the config documentation . cp cozy-stack/cozy.example.yaml ~/.cozy/cozy.yaml ` Edit the config file \u00b6 Edit the file ~/.cozy/cozy.yaml and change the line after the konnectors: entry to have this: cmd : /home/alice/.cozy/scripts/konnector-node-run.sh [Optional] Then, after the entry fs: url : file:///home/alice/.cozy/storage Create the script to execute the service \u00b6 Copy the file cozy-stack/scripts/konnector-node-run.sh to ~/.cozy/konnector-node-run.sh : Then you need to chmod +x ~/.cozy/scripts/konnector-node-run.sh Be sure to have node in your /usr/bin or /usr/local/bin folder. If not, you can add a symlink to node in one of those folder, for example by typing ln -s $(which node) /usr/local/bin/node Get your service logs in a isolated file \u00b6 Edit your ~/.cozy/konnector-node-run.sh by adding a tee output. set -o pipefail node \" ${ arg } \" 2 > & 1 | tee -a ~/.cozy/services.log Now you can tail -f ~/.cozy/services.log to watch logs in real time. Install your app \u00b6 To install the app containing the service on your local stack, you must give the path of your build: cozy-stack apps install file:// # Example: # cozy-stack apps install banks file:///home/alice/cozy-banks/build Each time you make modifications to your service, you must update the app on the stack to propagate the changes: cozy-stack apps update Env variables \u00b6 When executing a service, cozy-stack injects some environment variables, listed here , so you can use them in your service, typically through process.env. . Execution \u00b6 The service will be run each time the trigger condition is met, e.g. a bank operation. However, you can force its execution thanks to the cozy-konnector-dev CLI, which can be useful for developement. Be aware, that in that case, you can\u2019t rely on any of the stack provided variables To install locally: yarn add --dev cozy-jobs-cli To run: yarn run cozy-konnector-dev -m Be carefull the mybuiltservice.js must be the built file of your service, not the source. If your mybuiltservice.js is not executable and not recognize by node, you may need this script in your app folder to fix that. Just change the target path. #!/bin/bash target = \"build/services/sync-index-displayName/contacts.js\" firstChar = $( head -c 1 $target ) chmod +x $target if [[ $firstChar ! = \\# * ]] ; then sed -i '' '1i\\ #!/usr/bin/env node ' $target fi cozy-konnector-dev -m manifest.webapp $target", "title": "Develop a service from your application"}, {"location": "howTos/dev/services/#what-is-it-for", "text": "Applications may require server-side code execution that could not, or should not, be in the client. This might be useful for heavy computations or for tasks triggered after some events, typically after data is retrieved through konnectors or mobile/desktop sync, without the user being on the application. In contrast to konnectors, services have the same permissions as the web application and are not intended to collect information from the outside. It is rather meant to asynchronously analyse data inside the cozy and emit some output once the task is done. However, they share the same mechanisms as the konnectors to describe how and when they should be executed: via our trigger system .", "title": "What is it for?"}, {"location": "howTos/dev/services/#example", "text": "You can find an example of an existing service in the cozy-banks app .", "title": "Example"}, {"location": "howTos/dev/services/#cozyclient-instantiation", "text": "By using fromEnv , you will be able to use the service in dev mode (via cozy-konnector-dev see Execution ) or in production. const client = CozyClient . fromEnv ( process . env , { schema }) You may need to add this line to your service to use the fetch for node: global . fetch = require ( 'node-fetch' ). default", "title": "CozyClient instantiation"}, {"location": "howTos/dev/services/#service-declaration", "text": "The service must be declared in the app manifest . For example: \"services\" : { \"onOperationCreate\" : { \"type\" : \"node\" , \"file\" : \"onOperationCreate.js\" , \"trigger\" : \"@event io.cozy.bank.operations:CREATED\" , \"debounce\" : \"3m\" } } Here is an explanation of the fields: type : describe the code type (only node for now). file : the single (packaged) file containing the code to execute as a service. It must be the relative path to the built service\u2019s file, not the source one. Expl: /services/name-of-service/built-file.js . Look at your build folder or build/watch console output to find it. trigger : what triggers the service. It must follow the available triggers described in the jobs documentation . In this example, the trigger is a bank operation creation. debounce (optionnal): The debounce parameter can be used to limit the number of jobs created in a burst. It delays the creation of the job on the first input by the given time argument, and if the trigger has its condition matched again during this period, it won\u2019t create another job. Its syntax is the one understood by go\u2019s time.ParseDuration . If this parameter is omitted, the service will be executed as soon as it can.", "title": "Service declaration"}, {"location": "howTos/dev/services/#build", "text": "The service must be packaged into a single file containing all the dependencies. An example of a webpack rule is available here . Note that target: 'node' is important as the service is run as a Node.js process. In this example, the services are built alongside your app using yarn watch . If you use cozy-script , you should use watch and not start to have the service built.", "title": "Build"}, {"location": "howTos/dev/services/#stack", "text": "As the service is run on a dedicated process on the server side, a running stack is necessary. You can either use a stack installed with docker or directly from source . Some configuration is required to execute the service and store the produced logs, to facilitate the development. The following instructions are for a stack installed from source, but you can adapt it for a docker installation: you have to download the default config file , modify it as described below and indicate its location through the docker command, as explained here . In the following, we assume that your $HOME is /home/alice, so change accordingly to your own $HOME .", "title": "Stack"}, {"location": "howTos/dev/services/#copy-the-default-config-file-if-not-already-done", "text": "Create a directory ~/.cozy and copy the default configuration file into it. Be careful, the file name and location matter, as explained in the config documentation . cp cozy-stack/cozy.example.yaml ~/.cozy/cozy.yaml `", "title": "Copy the default config file if not already done"}, {"location": "howTos/dev/services/#edit-the-config-file", "text": "Edit the file ~/.cozy/cozy.yaml and change the line after the konnectors: entry to have this: cmd : /home/alice/.cozy/scripts/konnector-node-run.sh [Optional] Then, after the entry fs: url : file:///home/alice/.cozy/storage", "title": "Edit the config file"}, {"location": "howTos/dev/services/#create-the-script-to-execute-the-service", "text": "Copy the file cozy-stack/scripts/konnector-node-run.sh to ~/.cozy/konnector-node-run.sh : Then you need to chmod +x ~/.cozy/scripts/konnector-node-run.sh Be sure to have node in your /usr/bin or /usr/local/bin folder. If not, you can add a symlink to node in one of those folder, for example by typing ln -s $(which node) /usr/local/bin/node", "title": "Create the script to execute the service"}, {"location": "howTos/dev/services/#get-your-service-logs-in-a-isolated-file", "text": "Edit your ~/.cozy/konnector-node-run.sh by adding a tee output. set -o pipefail node \" ${ arg } \" 2 > & 1 | tee -a ~/.cozy/services.log Now you can tail -f ~/.cozy/services.log to watch logs in real time.", "title": "Get your service logs in a isolated file"}, {"location": "howTos/dev/services/#install-your-app", "text": "To install the app containing the service on your local stack, you must give the path of your build: cozy-stack apps install file:// # Example: # cozy-stack apps install banks file:///home/alice/cozy-banks/build Each time you make modifications to your service, you must update the app on the stack to propagate the changes: cozy-stack apps update ", "title": "Install your app"}, {"location": "howTos/dev/services/#env-variables", "text": "When executing a service, cozy-stack injects some environment variables, listed here , so you can use them in your service, typically through process.env. .", "title": "Env variables"}, {"location": "howTos/dev/services/#execution", "text": "The service will be run each time the trigger condition is met, e.g. a bank operation. However, you can force its execution thanks to the cozy-konnector-dev CLI, which can be useful for developement. Be aware, that in that case, you can\u2019t rely on any of the stack provided variables To install locally: yarn add --dev cozy-jobs-cli To run: yarn run cozy-konnector-dev -m Be carefull the mybuiltservice.js must be the built file of your service, not the source. If your mybuiltservice.js is not executable and not recognize by node, you may need this script in your app folder to fix that. Just change the target path. #!/bin/bash target = \"build/services/sync-index-displayName/contacts.js\" firstChar = $( head -c 1 $target ) chmod +x $target if [[ $firstChar ! = \\# * ]] ; then sed -i '' '1i\\ #!/usr/bin/env node ' $target fi cozy-konnector-dev -m manifest.webapp $target", "title": "Execution"}, {"location": "howTos/sync/linux/", "text": "Install the desktop client on your GNU/Linux system \u00b6 To ease the use of Cozy Drive on any distribution, we distribute the application using the AppImage format. This way, you have nothing to install, just download the application and run it. We provide packages for 64 bits systems. All you have to do is download the file, move it to some dedicated folder, make it executable and run it. List of known to work distributions If you are using a recent version of Ubuntu, you may need to install the libfuse2 library. This library used to be available by default on Ubuntu, but has been removed in the 22.04 release. To install this library, use your favorite package manager or sudo apt install libfuse2 . This may also apply to other Ubuntu based distributions. Detailed instructions on Gnome \u00b6 Click on this link to download Cozy Drive for GNU/Linux 64 bits . Once the binary file downloaded, go to the folder where your browser has stored it. For example, if you use Firefox, click on the folder icon in the download list. To be able to run the application, you have to edit its properties to make it executable. Just right click on the application and select Properties inside the context menu: Then go to the Permissions tab and check the box to make the application executable: There\u2019s no need to install the application, you can just run it from the folder you have downloaded it, but we recommend to move it to a dedicated folder to be able to find it easily. You can create an Applications folder inside your home directory and move the application there: Tip: you can add this folder to your bookmarks to find it easily: From 3.26 onwards, GNOME removed the systray (that little bar with some icons) which is the interface for Cozy Drive . You will need to install an extension such as TopIcons in order to see the cozy-desktop application and launch it. That\u2019s all. You can now double-click on the application to launch it and connect it to your server. Have fun! More \u00b6 More in deep insights on the GNU/Linux client . If your distribution is not supported, you can try the manual build guide .", "title": "Install Cozy Drive on GNU/Linux"}, {"location": "howTos/sync/linux/#install-the-desktop-client-on-your-gnulinux-system", "text": "To ease the use of Cozy Drive on any distribution, we distribute the application using the AppImage format. This way, you have nothing to install, just download the application and run it. We provide packages for 64 bits systems. All you have to do is download the file, move it to some dedicated folder, make it executable and run it. List of known to work distributions If you are using a recent version of Ubuntu, you may need to install the libfuse2 library. This library used to be available by default on Ubuntu, but has been removed in the 22.04 release. To install this library, use your favorite package manager or sudo apt install libfuse2 . This may also apply to other Ubuntu based distributions.", "title": "Install the desktop client on your GNU/Linux system"}, {"location": "howTos/sync/linux/#detailed-instructions-on-gnome", "text": "Click on this link to download Cozy Drive for GNU/Linux 64 bits . Once the binary file downloaded, go to the folder where your browser has stored it. For example, if you use Firefox, click on the folder icon in the download list. To be able to run the application, you have to edit its properties to make it executable. Just right click on the application and select Properties inside the context menu: Then go to the Permissions tab and check the box to make the application executable: There\u2019s no need to install the application, you can just run it from the folder you have downloaded it, but we recommend to move it to a dedicated folder to be able to find it easily. You can create an Applications folder inside your home directory and move the application there: Tip: you can add this folder to your bookmarks to find it easily: From 3.26 onwards, GNOME removed the systray (that little bar with some icons) which is the interface for Cozy Drive . You will need to install an extension such as TopIcons in order to see the cozy-desktop application and launch it. That\u2019s all. You can now double-click on the application to launch it and connect it to your server. Have fun!", "title": "Detailed instructions on Gnome"}, {"location": "howTos/sync/linux/#more", "text": "More in deep insights on the GNU/Linux client . If your distribution is not supported, you can try the manual build guide .", "title": "More"}, {"location": "projects/", "text": "Projects \u00b6 Cozy App Publish Cozy App Registry Cozy Banks Cozy Flags Cozy Stack Cozy UI Cozy Desktop", "title": "Documentations"}, {"location": "projects/#projects", "text": "Cozy App Publish Cozy App Registry Cozy Banks Cozy Flags Cozy Stack Cozy UI Cozy Desktop", "title": "Projects"}, {"location": "references/auth/", "text": "Authentication Sequence \u00b6 The User opens up a browser to check his cozy, using his cozy app domain ( user-home.mycozy.cloud/ , or user-drive.mycozy.cloud/ , or \u2026) (s)he\u2019s redirected to his cozy user domain ( user.mycozy.cloud ) The browser requests the stack through cozy user domain , which sends back the authentication form. The user fills his password, sending it back to the cozy user domain The server cozy user domain sets an auth cookie for cozy user domain ONLY. This cookie is restricted to this sub-domain (and httpOnly). It will not be seen by the app domain. This is by design, so that an app could not use the cookie and authenticate with another app permission. A redirect status response code (302) for the requested app domain ( user-home.mycozy.cloud/ , or user-drive.mycozy.cloud/ , or \u2026) is sent to the browser. (The 302 redirection from cozy user domain to the requested app domain adds a ?code=xxxxx to the URL where xxxx is a random code, used to create a new cookie on the cozy app domain 6.The new cookie is created on requested app domain . The app can now fetch its index.html page with a JWT token inside it, and extracts it in JS The jwt token is sent back to the stack, on the cozy user domain as a bearer token in the Authorization header of HTTP requests. cozy app domain uses the bearer token to communicate with the stack through XHR request cozy app domain sends back the authenticated UI to the browser, and a new cookie for the cozy app domain ( user-home.mycozy.cloud/ , or user-drive.mycozy.cloud/ , or \u2026) For each new app requested by the user, repeat steps (Steps 3 & 4 only happens when the user is not authenticated at all: meaning there is no auth cookie for cozy user domain ) Mermaid source Authentication types \u00b6 Password \u00b6 Used by the user on the authentication form on the cozy user domain ( user.mycozy.cloud ) It can be changed through the setting apps It can be reset on the authentication form or in the setting app, by sending an email to the user When the password changes, all the old cookies are invalidated, and a new one is created for the current session. Meaning the user will need to login again in their other browsers/clients. Cookies \u00b6 For each app, there is a specific cookie, meaning there is a new cookie for each new domain/sub-domain The \u201cRemember me\u201d check box only affect the expiration date of the cozy user domain cookie !!! warning \u201c\u201d For this documentation we use the domain and the configuration pattern of our production servers: user.mycozy.cloud for the user and user-app.mycozy.cloud for apps. This is only an example and you will have another domain if you are hosted elsewhere or if you are in a development environment. You may also have a different configuration pattern where the app is on a subdomain of the user domain (like app.user.mydomain ). If so, cookies set on the user domain may be readable by the app domain. 2FA \u00b6 Can be activated by the user Only works through emails right now Once 2FA activated, and the user authenticated, a new checkbox \u201cTrust this machine\u201d creates a new cookie (if checked) !!! warning \u201c\u201d There are a few timing issues with 2FA, as the code validation time is quite short, and some emails may be delayed. Usecases and their authentication methods \u00b6 User: password and Cookies App (drive, photo, home\u2026): Cookie and Authorization Bearer Token Client (desktop, mobile\u2026): OAuth and Authorization Bearer Token Connectors: Authorization Bearer Token Share: OAuth and Authorization Bearer Token (just like the desktop client)", "title": "Authentication"}, {"location": "references/auth/#authentication-sequence", "text": "The User opens up a browser to check his cozy, using his cozy app domain ( user-home.mycozy.cloud/ , or user-drive.mycozy.cloud/ , or \u2026) (s)he\u2019s redirected to his cozy user domain ( user.mycozy.cloud ) The browser requests the stack through cozy user domain , which sends back the authentication form. The user fills his password, sending it back to the cozy user domain The server cozy user domain sets an auth cookie for cozy user domain ONLY. This cookie is restricted to this sub-domain (and httpOnly). It will not be seen by the app domain. This is by design, so that an app could not use the cookie and authenticate with another app permission. A redirect status response code (302) for the requested app domain ( user-home.mycozy.cloud/ , or user-drive.mycozy.cloud/ , or \u2026) is sent to the browser. (The 302 redirection from cozy user domain to the requested app domain adds a ?code=xxxxx to the URL where xxxx is a random code, used to create a new cookie on the cozy app domain 6.The new cookie is created on requested app domain . The app can now fetch its index.html page with a JWT token inside it, and extracts it in JS The jwt token is sent back to the stack, on the cozy user domain as a bearer token in the Authorization header of HTTP requests. cozy app domain uses the bearer token to communicate with the stack through XHR request cozy app domain sends back the authenticated UI to the browser, and a new cookie for the cozy app domain ( user-home.mycozy.cloud/ , or user-drive.mycozy.cloud/ , or \u2026) For each new app requested by the user, repeat steps (Steps 3 & 4 only happens when the user is not authenticated at all: meaning there is no auth cookie for cozy user domain ) Mermaid source", "title": "Authentication Sequence"}, {"location": "references/auth/#authentication-types", "text": "", "title": "Authentication types"}, {"location": "references/auth/#password", "text": "Used by the user on the authentication form on the cozy user domain ( user.mycozy.cloud ) It can be changed through the setting apps It can be reset on the authentication form or in the setting app, by sending an email to the user When the password changes, all the old cookies are invalidated, and a new one is created for the current session. Meaning the user will need to login again in their other browsers/clients.", "title": "Password"}, {"location": "references/auth/#cookies", "text": "For each app, there is a specific cookie, meaning there is a new cookie for each new domain/sub-domain The \u201cRemember me\u201d check box only affect the expiration date of the cozy user domain cookie !!! warning \u201c\u201d For this documentation we use the domain and the configuration pattern of our production servers: user.mycozy.cloud for the user and user-app.mycozy.cloud for apps. This is only an example and you will have another domain if you are hosted elsewhere or if you are in a development environment. You may also have a different configuration pattern where the app is on a subdomain of the user domain (like app.user.mydomain ). If so, cookies set on the user domain may be readable by the app domain.", "title": "Cookies"}, {"location": "references/auth/#2fa", "text": "Can be activated by the user Only works through emails right now Once 2FA activated, and the user authenticated, a new checkbox \u201cTrust this machine\u201d creates a new cookie (if checked) !!! warning \u201c\u201d There are a few timing issues with 2FA, as the code validation time is quite short, and some emails may be delayed.", "title": "2FA"}, {"location": "references/auth/#usecases-and-their-authentication-methods", "text": "User: password and Cookies App (drive, photo, home\u2026): Cookie and Authorization Bearer Token Client (desktop, mobile\u2026): OAuth and Authorization Bearer Token Connectors: Authorization Bearer Token Share: OAuth and Authorization Bearer Token (just like the desktop client)", "title": "Usecases and their authentication methods"}, {"location": "references/git-flow/", "text": "We recommand to use the following git flow for our applications and konnectors. Development \u00b6 master is the current state of the development. Every commit must: provide a working application without introducing blocking regressions validate lint and unit tests Every feature, improvement or fix is merged via a pull request. For large features with huge impacts on the whole codebase, use feature branches, for example feature/something-new . A feature branch is merged into master when it\u2019s totally functional and validated. Releases \u00b6 TL;DR Create release branch Bump master version Tag beta versions from release branch until it passes all tests Tag stable version from release branch Delete release branch The goal of a release is to have a new stable version of an application or a konnector. A new release is always based on the current state of master , so it consists in creating a new branch release-0.0.0 (with the correct version). Right after starting a new release, master \u2018s version must be bumped, as the previous version is now \u201cfrozen\u201d into the release branch. It is done now to not forget to do it later, or to not have a new unexpected commit before the next version. Example with master being versionned to 1.4.0 , origin being the remote Cozy repository: git checkout master git checkout -b release-1.4.0 git push --set-upstream-to = origin/release-1.4.0 release-1.4.0 git checkout master # Update app version to 1.5.0 in package.json and manifest.webapp git add package.json manifest.webapp git commit -m \"chore: Bump version to 1.5.0\" git push origin HEAD # Go back to work on our release, we will next tag a first beta git checkout release-1.4.0 Once the release branch is created, i.e. the release has started, it must be validated, so a first beta tag is created. Following the previous example: git tag 1 .4.0-beta.1 git push origin 1 .4.0-beta.1 NB: Version number in package.json and manifest.webapp is still 1.4.0 If this beta version is ok, it can be tagged as stable git tag 1 .4.0 git push origin 1 .4.0 But if the beta is not ok, fixes are committed into the release branch and a new beta version is tagged. git tag 1 .4.0-beta.2 git push origin 1 .4.0-beta.2 This process is repeated until a beta version is validated and ready to be tagged as stable. During the release, development continues in master without impacting release-1.4.0 . Once a stable version has been tagged, the release branch must then be merged into master to retrieve all the fixes it contains. Then the release branch can be deleted. git checkout master git pull git merge release-1.0.4 git branch -D release-1.0.4 git push origin :release-1.0.4 git push origin HEAD NB: We take care to get only one release branch at a time. Patches \u00b6 TL;DR Create a patch branch from a stable tag Bump to new patch version Fixes issues and tag new beta versions until everything is ok Tag stable version Cherry-pick fixes into master Delete patch branch If a bug is detected on a stable version, we address it with a patch branch. For example for the version 1.1.0 : git checkout 1 .0.0 -b patch-1.1.1 # Update app version to 1.1.1 in package.json and manifest.webapp git add package.json manifest.webapp git commit -m \"chore: Bump version to 1.1.1\" git push --set-upstream-to = origin/patch-1.1.0 patch-1.1.0 After this checkout a patch branch is managed the same way as a release branch, except that: A beta version tag is not created right after checkout but once fixes have been made (otherwise the beta version would be exactly the same as the version which need to be patched) After the stable version has been tagged, the commits are cherry-picked instead of merging the whole branch. A merge is still possible, but it implies to manage conflicts in package.json and manifest.webapp about version number (remember, we bumped the version so it will conflict with master current\u2019s one).", "title": "Our Front-End Git Flow"}, {"location": "references/git-flow/#development", "text": "master is the current state of the development. Every commit must: provide a working application without introducing blocking regressions validate lint and unit tests Every feature, improvement or fix is merged via a pull request. For large features with huge impacts on the whole codebase, use feature branches, for example feature/something-new . A feature branch is merged into master when it\u2019s totally functional and validated.", "title": "Development"}, {"location": "references/git-flow/#releases", "text": "TL;DR Create release branch Bump master version Tag beta versions from release branch until it passes all tests Tag stable version from release branch Delete release branch The goal of a release is to have a new stable version of an application or a konnector. A new release is always based on the current state of master , so it consists in creating a new branch release-0.0.0 (with the correct version). Right after starting a new release, master \u2018s version must be bumped, as the previous version is now \u201cfrozen\u201d into the release branch. It is done now to not forget to do it later, or to not have a new unexpected commit before the next version. Example with master being versionned to 1.4.0 , origin being the remote Cozy repository: git checkout master git checkout -b release-1.4.0 git push --set-upstream-to = origin/release-1.4.0 release-1.4.0 git checkout master # Update app version to 1.5.0 in package.json and manifest.webapp git add package.json manifest.webapp git commit -m \"chore: Bump version to 1.5.0\" git push origin HEAD # Go back to work on our release, we will next tag a first beta git checkout release-1.4.0 Once the release branch is created, i.e. the release has started, it must be validated, so a first beta tag is created. Following the previous example: git tag 1 .4.0-beta.1 git push origin 1 .4.0-beta.1 NB: Version number in package.json and manifest.webapp is still 1.4.0 If this beta version is ok, it can be tagged as stable git tag 1 .4.0 git push origin 1 .4.0 But if the beta is not ok, fixes are committed into the release branch and a new beta version is tagged. git tag 1 .4.0-beta.2 git push origin 1 .4.0-beta.2 This process is repeated until a beta version is validated and ready to be tagged as stable. During the release, development continues in master without impacting release-1.4.0 . Once a stable version has been tagged, the release branch must then be merged into master to retrieve all the fixes it contains. Then the release branch can be deleted. git checkout master git pull git merge release-1.0.4 git branch -D release-1.0.4 git push origin :release-1.0.4 git push origin HEAD NB: We take care to get only one release branch at a time.", "title": "Releases"}, {"location": "references/git-flow/#patches", "text": "TL;DR Create a patch branch from a stable tag Bump to new patch version Fixes issues and tag new beta versions until everything is ok Tag stable version Cherry-pick fixes into master Delete patch branch If a bug is detected on a stable version, we address it with a patch branch. For example for the version 1.1.0 : git checkout 1 .0.0 -b patch-1.1.1 # Update app version to 1.1.1 in package.json and manifest.webapp git add package.json manifest.webapp git commit -m \"chore: Bump version to 1.1.1\" git push --set-upstream-to = origin/patch-1.1.0 patch-1.1.0 After this checkout a patch branch is managed the same way as a release branch, except that: A beta version tag is not created right after checkout but once fixes have been made (otherwise the beta version would be exactly the same as the version which need to be patched) After the stable version has been tagged, the commits are cherry-picked instead of merging the whole branch. A merge is still possible, but it implies to manage conflicts in package.json and manifest.webapp about version number (remember, we bumped the version so it will conflict with master current\u2019s one).", "title": "Patches"}, {"location": "references/tech-intro/", "text": "What is Cozy? \u00b6 Cozy is a personal server hosting applications that allow collect and manipulate all your personal data. Depending on your point of view, Cozy can be seen as : A place to keep your personal data A core API to handle the data Your web apps, and also the mobile & desktop clients A coherent User Experience. The whole platform is designed around 3 key values : Simple , Versatile , Yours . These values have a lot of meaning for Cozy in all aspects. From an architectural point of view, they are declined like this: simple and easy to understand and deploy. Cozy doesn\u2019t require to setup and manage a lot of micro-services; versatile : your server is comfortable anywhere. You can host a single instance on a small Raspberry \u03c0 at home, or a cluster of thousands instances on dedicated servers inside a datacenter; yours : the users are the owners of their data, they keep the control. They can migrate their data from one server to another, and are not dependant from a single hosting provider. As we say: \u201cyou will stay because you can leave\u201d; Architecture overview \u00b6 Several layers can be distinguished. From inside to outside: the core is a database that store all user data; the database is accessible through a layer that control accesses and expose a REST API; Web applications and other clients offer nice user interfaces to interact with the data. The server (Cozy-stack - documentation ) \u00b6 The server consist of a single process. We call it the Cozy stack . The server is in charge of serving the Web applications users have installed from the application store. It provides its services through a REST API that allows to: create, update, delete documents inside the database; authenticate users and client applications; send emails; launch jobs on the server. Connectors that import data from remote websites are some sort of jobs. Jobs can be one time tasks (sending a message) or periodic tasks. Some jobs, like the connectors, that require executing third party code on the server side, are sandboxed (we use nsjail for now). \u2026 The server also allow to access the database replication API, allowing to sync documents between the server and local databases, for example in mobile clients. Two authentication methods are available: Web applications running on the server get a session token when the user log in; OAuth2 for other applications. The database \u00b6 CouchDB is a document database. Everything, from user data to server settings, is stored inside typed documents, identified by an unique id. Two request methods are allowed: map-reduce or Mango , a specific query language. Every document has a doctype , and we keep an index of the definition of every doctype. Binary data are stored outside the database. Depending on the server configuration, they may be stored on a file system or a dedicated object storage like swift . The datasystem layer inside the Cozy stack is in charge of controlling access rights on documents and binaries. It allows fine gained access control, on a whole doctype or on a set of documents. The applications \u00b6 There are two kind of applications: web applications : Single Page Applications (SPA) written in HTML and JavaScript that run inside the user\u2019s browser. They interact with the server through its API. This API allows to manipulate data and files and to perform miscellaneous tasks, like send emails connectors : Small application written in JavaScript, running on the server, that import your data from remote sources. The server provides services to applications: real time notifications of events; methods allowing applications to communicate and share data; interapps : applications can expose \u201ccapabilities\u201d that other apps can call. For instance an app can expose the capability to pick a photo or to create a contact. methods allowing sharing of documents between servers. This is a peer-to-peer protocol so that even users hosted on different infrastructure can share their data which are synchronized (the cozy stack propagates modifications between users servers). Application store \u00b6 An application registry lists every available applications, and their characteristics. Each application can: create its own doctypes; request permission to access documents; offer services to other applications; register publics routes; create jobs that will be run on server side. Application isolation \u00b6 Each application uses its own sub-domain, so it gets sandboxed inside the browser: other application are not able to steal its access token or access its data. We use Content Security Policy to control what the application is allowed to do. For example, Web applications running inside Cozy are not allowed to send requests to other websites. This allows a strict control over applications, preventing them to leak your data. Further reading \u00b6 Coding tutorials : Create a client application Develop a connector Selfhosting: How to to self-host a Cozy server The cozy server documentation (cozy-stack)", "title": "Technical introduction to the Cozy platform"}, {"location": "references/tech-intro/#what-is-cozy", "text": "Cozy is a personal server hosting applications that allow collect and manipulate all your personal data. Depending on your point of view, Cozy can be seen as : A place to keep your personal data A core API to handle the data Your web apps, and also the mobile & desktop clients A coherent User Experience. The whole platform is designed around 3 key values : Simple , Versatile , Yours . These values have a lot of meaning for Cozy in all aspects. From an architectural point of view, they are declined like this: simple and easy to understand and deploy. Cozy doesn\u2019t require to setup and manage a lot of micro-services; versatile : your server is comfortable anywhere. You can host a single instance on a small Raspberry \u03c0 at home, or a cluster of thousands instances on dedicated servers inside a datacenter; yours : the users are the owners of their data, they keep the control. They can migrate their data from one server to another, and are not dependant from a single hosting provider. As we say: \u201cyou will stay because you can leave\u201d;", "title": "What is Cozy?"}, {"location": "references/tech-intro/#architecture-overview", "text": "Several layers can be distinguished. From inside to outside: the core is a database that store all user data; the database is accessible through a layer that control accesses and expose a REST API; Web applications and other clients offer nice user interfaces to interact with the data.", "title": "Architecture overview"}, {"location": "references/tech-intro/#the-server-cozy-stack-documentation", "text": "The server consist of a single process. We call it the Cozy stack . The server is in charge of serving the Web applications users have installed from the application store. It provides its services through a REST API that allows to: create, update, delete documents inside the database; authenticate users and client applications; send emails; launch jobs on the server. Connectors that import data from remote websites are some sort of jobs. Jobs can be one time tasks (sending a message) or periodic tasks. Some jobs, like the connectors, that require executing third party code on the server side, are sandboxed (we use nsjail for now). \u2026 The server also allow to access the database replication API, allowing to sync documents between the server and local databases, for example in mobile clients. Two authentication methods are available: Web applications running on the server get a session token when the user log in; OAuth2 for other applications.", "title": "The server (Cozy-stack - documentation)"}, {"location": "references/tech-intro/#the-database", "text": "CouchDB is a document database. Everything, from user data to server settings, is stored inside typed documents, identified by an unique id. Two request methods are allowed: map-reduce or Mango , a specific query language. Every document has a doctype , and we keep an index of the definition of every doctype. Binary data are stored outside the database. Depending on the server configuration, they may be stored on a file system or a dedicated object storage like swift . The datasystem layer inside the Cozy stack is in charge of controlling access rights on documents and binaries. It allows fine gained access control, on a whole doctype or on a set of documents.", "title": "The database"}, {"location": "references/tech-intro/#the-applications", "text": "There are two kind of applications: web applications : Single Page Applications (SPA) written in HTML and JavaScript that run inside the user\u2019s browser. They interact with the server through its API. This API allows to manipulate data and files and to perform miscellaneous tasks, like send emails connectors : Small application written in JavaScript, running on the server, that import your data from remote sources. The server provides services to applications: real time notifications of events; methods allowing applications to communicate and share data; interapps : applications can expose \u201ccapabilities\u201d that other apps can call. For instance an app can expose the capability to pick a photo or to create a contact. methods allowing sharing of documents between servers. This is a peer-to-peer protocol so that even users hosted on different infrastructure can share their data which are synchronized (the cozy stack propagates modifications between users servers).", "title": "The applications"}, {"location": "references/tech-intro/#application-store", "text": "An application registry lists every available applications, and their characteristics. Each application can: create its own doctypes; request permission to access documents; offer services to other applications; register publics routes; create jobs that will be run on server side.", "title": "Application store"}, {"location": "references/tech-intro/#application-isolation", "text": "Each application uses its own sub-domain, so it gets sandboxed inside the browser: other application are not able to steal its access token or access its data. We use Content Security Policy to control what the application is allowed to do. For example, Web applications running inside Cozy are not allowed to send requests to other websites. This allows a strict control over applications, preventing them to leak your data.", "title": "Application isolation"}, {"location": "references/tech-intro/#further-reading", "text": "Coding tutorials : Create a client application Develop a connector Selfhosting: How to to self-host a Cozy server The cozy server documentation (cozy-stack)", "title": "Further reading"}, {"location": "tutorials/app/", "text": "Prerequisites \u00b6 Developing an application for Cozy is like developing a front-end JS application. All you need to have is: NodeJS 20 Yarn : a NodeJS package manager, like npm Docker to have a Cozy for dev Some basics about developing a single page application in HTML/JS or you just want to learn :) Install the development environment \u00b6 The only tool required to have a Cozy for development is Docker. Install Docker for OSX Install Docker for Windows (We have been told that installing Docker on some familial flavours of Windows may be a bit difficult. It has not been tested yet for this documentation.) Install Docker for GNU/linux: Ubuntu / Fedora / Debian / CentOs On GNU/Linux, according to the documentation : \u00ab The docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. If you don\u2019t want to use sudo when you use the docker command, create a Unix group called docker and add users to it. Be warned that the docker group grants privileges equivalent to the root user. You should have a look at Docker\u2019s documentation on security . Every application running inside Cozy is a client-side HTML5 application interacting with your data through the API of the server. To develop an application, you\u2019ll require a running Cozy server. The easiest way is to use the Docker image for developers we provide. Download it for now: docker pull cozy/cozy-app-dev Note We update this image on a regular basis with the latest version of the server and our library. Don\u2019t forget to update the image by running docker pull cozy/cozy-app-dev from time to time to keep your Cozy dev up to date. Create your application \u00b6 You can boostrap your application from scratch if you want, but we highly recommand to use our dedicated community tool create-cozy-app to bootstrap very easily a Cozy application for you. This tool will generate an application using React, the framework we internally use in the Cozy Front team. But options are available if you want to use other frameworks. To do so, run directly create-cozy-app without installing it globally by using the yarn create cozy-app command to bootstrap your application: yarn create cozy-app mycozyapp The script will download some dependencies (may take a while) and ask you a few questions, then create an application skeleton inside mycozyapp . Here is a quick demo of what\u2019s happening: If the yarn create cozy-app command fails with the There should only be one folder in a package cache [...] error, then run yarn cache clean and try again You\u2019ll also need a running cozy-stack server as a backend server. You can use the docker image you downloaded earlier. Note: We disable CSP since we\u2019re using a wepback-dev-server by defaut to get HMR that runs on localhost and not on cozy.localhost . This should not be used in production ! Please check the behavior of your application once you built it on production mode and have enabled CSP back. touch ~/cozy.yaml # You can edit this file to configure the stack docker run -ti --rm -p 8080 :8080 -p 5984 :5984 -p 8025 :8025 -e COZY_DISABLE_CSP = 1 -v $( pwd ) /mycozyapp/build:/data/cozy-app/mycozyapp -v ~/cozy.yaml:/etc/cozy/cozy.yaml cozy/cozy-app-dev Alternatively, you can build cozy-stack locally. You can follow the install instructions here . Once it is installed, you can run it with cozy-stack serve --appdir :// --disable-csp . For instance: cozy-stack serve --appdir mycozyapp://home/claude/dev/mycozyapp/build --disable-csp That\u2019s it! You can start developing: cd mycozyapp yarn start This command will run webpack in a watching mode with a server (webpack-dev-server) to serve application assets. Your application will be available at http://mycozyapp.cozy.localhost:8080 . Password is cozy . In this mode HMR (Hot Module Replacement) is available. Going Further \u00b6 How the application works? \u00b6 The minimal application consist of only two files: an HTML file, index.html , with the markup and the code of your application a manifest describing the application. It\u2019s a JSON file named manifest.webapp with the name of the application, the permissions it requires\u2026 We\u2019ll have a deeper look to its content later. Your application requires some informations to interact with the server API, for example the URL of its entrypoint, and an auth token. This data will be dynamically injected into index.html when it serves the page. So the index.html file has to contain some string that will be replaced by the server. The general syntax of this variables is {{\u2026}} , so don\u2019t use this syntax for other purpose in the page, for example inside comments. You can use the following variables: {{.Domain}} : will be substituted by the URL of the API entrypoint {{.Token}} : will be replaced by a token that authenticate your application when accessing the API {{.Locale}} : the lang of the instance {{.AppName}} : the name of the application {{.AppNamePrefix}} : the name prefix of the application {{.AppSlug}} : the slug of the application {{.AppEditor}} : the editor of the application {{.IconPath}} : will be replaced by HTML code to display the favicon {{.CozyClientJS}} : will be replaced with HTML code to inject the Cozy client library (old Cozy client) {{.CozyBar}} : will be replaced with HTML code to inject the upper menu bar {{.ThemeCSS}} : will be replaced by the theme.css . It is empty by default, but can be overrided by using contexts . {{.Favicon}} : will be replaced by the favicon served by the stack. This allows to get this kind of index.html : < html lang = \"{{.Locale}}\" > < head > < meta charset = \"utf-8\" > < title > My Awesome App for Cozy < meta name = \"viewport\" content = \"width=device-width, initial-scale=1\" > < link rel = \"stylesheet\" src = \"my-app.css\" > {{.ThemeCSS}} {{.CozyClientJS}} {{.CozyBar}} < body > < div role = \"application\" data-cozy-token = \"{{.Token}}\" data-cozy-stack = \"{{.Domain}}\" > < script src = \"my-app.js\" > Read the application manifest \u00b6 Each application must have a \u201cmanifest\u201d. It\u2019s a JSON file named manifest.webapp stored at the root of the application directory. It describes the application, the type of documents it uses, the permissions it requires\u2026 Here\u2019s a sample manifest: { \"name\" : \"My Awesome application\" , \"name_prefix\" : \"\" , \"slug\" : \"myapp\" , \"permissions\" : { \"apps\" : { \"type\" : \"io.cozy.apps\" }, \"permissions\" : { \"type\" : \"io.cozy.permissions\" }, \"settings\" : { \"type\" : \"io.cozy.settings\" }, \"sample\" : { \"type\" : \"io.cozy.dev.sample\" , \"verbs\" : [ \"GET\" , \"POST\" , \"PUT\" , \"PATCH\" , \"DELETE\" ] }, \"jobs\" : { \"type\" : \"io.cozy.jobs\" } }, \"routes\" : { \"/\" : { \"folder\" : \"/\" , \"index\" : \"index.html\" , \"public\" : false }, \"/public\" : { \"folder\" : \"/public\" , \"index\" : \"index.html\" , \"public\" : true } } } Permissions \u00b6 Applications require permissions to use most of the APIs. Permissions can be described inside the manifest, so the server can ask the user to grant them during installation. Applications can also request permissions at run time. A permission must at least contain a target, the type of objects the application want to interact with. Can be a document type, or an action on the server. By default, all permissions on this object are granted, but we can also request fine grained permissions, for example limiting to read access. We can also limit the scope to a subset of the documents. In the manifest, each permission is an object, with a random name and some properties: type : mandatory the document type or action name description : a text that will be displayed to the user to explain why the application require this permission verbs : an array of HTTP verbs. For example, to limit permissions to read access, use [\"GET\"] selector : a document attribute to limit access to a subset of documents values : array of allowed values for this attribute. An application can request a token that grant access to a subset of its own permissions. For example if the application has full access to the files, it can obtain a token that give only read access on a file. Thus, the application can make some documents publicly available. The public page of the application will use this token asauthentication token when accessing the API. Samples \u00b6 Application requiring full access to files: { \"permissions\" : { \"files\" : { \"description\" : \"\u2026\" , \"type\" : \"io.cozy.files\" }, } } Application wanting to be able to read the contact information of cozy@cozycloud.cc { \"permissions\" : { \"contact\" : { \"type\" : \"io.cozy.contacts\" , \"verbs\" : [ \"GET\" ], \"selector\" : \"email\" , \"values\" : [ \"cozy@cozycloud.cc\" ] } } } Routing \u00b6 The application must declare all of its URLs (routes) inside the manifest. A route is an object associating an URL to a HTML file. Each route has the following properties: folder : the base folder of the route index : the name of the file inside this folder public : a boolean specifying whether the route is public or private (default). Sample: \"routes\" : { \"/admin\" : { \"folder\" : \"/\" , \"index\" : \"admin.html\" , \"public\" : false }, \"/public\" : { \"folder\" : \"/public\" , \"index\" : \"index.html\" , \"public\" : true }, \"/assets\" : { \"folder\" : \"/assets\" , \"public\" : true } } Behind the magic \u00b6 Some server APIs may not be available right now through the library. If you want to use one of this method, you\u2019ll have to call it manually. We\u2019ll describe here how to access the API without using the Cozy Client library. Connecting to the API requires three things: its URL, injected into the page through the {{.Domain}} variable the application auth token, injected into the page through the {{.Token}} variable. Each request sent to the server must include this token in the Authorization header the session cookie, created when you connect to your server. This is an HttpOnly cookie , meaning that JavaScript applications can\u2019t read it. This prevent a malicious script to steal the cookie. Here\u2019s a sample code that get API informations provided by the server and query the API: < div data-cozy-token = \"{{.Token}}\" data-cozy-domain = \"{{.Domain}}\" /> document . addEventListener ( 'DOMContentLoaded' , () => { \"use strict\" ; const app = document . querySelector ( '[data-cozy-token]' ); fetch ( `// ${ app . dataset . cozyDomain } /apps` , { method : 'GET' , headers : { Authorization : `Bearer ${ app . dataset . cozyToken } ` // Here we use the auth token }, credentials : 'include' // Don\u2019t forget to include the session cookie }) . then (( response ) => { if ( response . ok ) { response . json (). then (( result ) => { console . log ( result ); }); } else { throw new Error ( 'Network response was not ok.' ); } }) . catch (( error ) => { console . log ( 'There has been a problem with your fetch operation: ' + error . message ); }); }); Handle data with cozy-client \u00b6 cozy-client is a simple and declarative way of managing cozy-stack API calls and resulting data. It is a convenient and powerful way to bind cozy-stack queries to your components. Getting started React integration API docs Discover the Cozy Bar \u00b6 The Cozy Bar is a component that displays the Cozy menu on the top of your application and allows inter-apps features like content sharing. Your application interacts with this component through cozy-bar.js , a library injected into your pages by the server when you add {{.CozyBar}} in the header. It exposes an API behind the window.cozy.bar namespace. Before using it, you have to initialize the library: window.cozy.bar.init({appName: \"Mon application\"}) . Style with Cozy UI \u00b6 If you plan to build a webapp to run on Cozy, you\u2019ll probably want to use a simple and elegant solution to build your interfaces without the mess of dealing with complex markup and CSS. Then Cozy UI is here for you! It relies on Stylus as preprocessor. You can add it as a library in your project to use it out-of-the-box.", "title": "Create Your Application"}, {"location": "tutorials/app/#prerequisites", "text": "Developing an application for Cozy is like developing a front-end JS application. All you need to have is: NodeJS 20 Yarn : a NodeJS package manager, like npm Docker to have a Cozy for dev Some basics about developing a single page application in HTML/JS or you just want to learn :)", "title": "Prerequisites"}, {"location": "tutorials/app/#install-the-development-environment", "text": "The only tool required to have a Cozy for development is Docker. Install Docker for OSX Install Docker for Windows (We have been told that installing Docker on some familial flavours of Windows may be a bit difficult. It has not been tested yet for this documentation.) Install Docker for GNU/linux: Ubuntu / Fedora / Debian / CentOs On GNU/Linux, according to the documentation : \u00ab The docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. If you don\u2019t want to use sudo when you use the docker command, create a Unix group called docker and add users to it. Be warned that the docker group grants privileges equivalent to the root user. You should have a look at Docker\u2019s documentation on security . Every application running inside Cozy is a client-side HTML5 application interacting with your data through the API of the server. To develop an application, you\u2019ll require a running Cozy server. The easiest way is to use the Docker image for developers we provide. Download it for now: docker pull cozy/cozy-app-dev Note We update this image on a regular basis with the latest version of the server and our library. Don\u2019t forget to update the image by running docker pull cozy/cozy-app-dev from time to time to keep your Cozy dev up to date.", "title": "Install the development environment"}, {"location": "tutorials/app/#create-your-application", "text": "You can boostrap your application from scratch if you want, but we highly recommand to use our dedicated community tool create-cozy-app to bootstrap very easily a Cozy application for you. This tool will generate an application using React, the framework we internally use in the Cozy Front team. But options are available if you want to use other frameworks. To do so, run directly create-cozy-app without installing it globally by using the yarn create cozy-app command to bootstrap your application: yarn create cozy-app mycozyapp The script will download some dependencies (may take a while) and ask you a few questions, then create an application skeleton inside mycozyapp . Here is a quick demo of what\u2019s happening: If the yarn create cozy-app command fails with the There should only be one folder in a package cache [...] error, then run yarn cache clean and try again You\u2019ll also need a running cozy-stack server as a backend server. You can use the docker image you downloaded earlier. Note: We disable CSP since we\u2019re using a wepback-dev-server by defaut to get HMR that runs on localhost and not on cozy.localhost . This should not be used in production ! Please check the behavior of your application once you built it on production mode and have enabled CSP back. touch ~/cozy.yaml # You can edit this file to configure the stack docker run -ti --rm -p 8080 :8080 -p 5984 :5984 -p 8025 :8025 -e COZY_DISABLE_CSP = 1 -v $( pwd ) /mycozyapp/build:/data/cozy-app/mycozyapp -v ~/cozy.yaml:/etc/cozy/cozy.yaml cozy/cozy-app-dev Alternatively, you can build cozy-stack locally. You can follow the install instructions here . Once it is installed, you can run it with cozy-stack serve --appdir :// --disable-csp . For instance: cozy-stack serve --appdir mycozyapp://home/claude/dev/mycozyapp/build --disable-csp That\u2019s it! You can start developing: cd mycozyapp yarn start This command will run webpack in a watching mode with a server (webpack-dev-server) to serve application assets. Your application will be available at http://mycozyapp.cozy.localhost:8080 . Password is cozy . In this mode HMR (Hot Module Replacement) is available.", "title": "Create your application"}, {"location": "tutorials/app/#going-further", "text": "", "title": "Going Further"}, {"location": "tutorials/app/#how-the-application-works", "text": "The minimal application consist of only two files: an HTML file, index.html , with the markup and the code of your application a manifest describing the application. It\u2019s a JSON file named manifest.webapp with the name of the application, the permissions it requires\u2026 We\u2019ll have a deeper look to its content later. Your application requires some informations to interact with the server API, for example the URL of its entrypoint, and an auth token. This data will be dynamically injected into index.html when it serves the page. So the index.html file has to contain some string that will be replaced by the server. The general syntax of this variables is {{\u2026}} , so don\u2019t use this syntax for other purpose in the page, for example inside comments. You can use the following variables: {{.Domain}} : will be substituted by the URL of the API entrypoint {{.Token}} : will be replaced by a token that authenticate your application when accessing the API {{.Locale}} : the lang of the instance {{.AppName}} : the name of the application {{.AppNamePrefix}} : the name prefix of the application {{.AppSlug}} : the slug of the application {{.AppEditor}} : the editor of the application {{.IconPath}} : will be replaced by HTML code to display the favicon {{.CozyClientJS}} : will be replaced with HTML code to inject the Cozy client library (old Cozy client) {{.CozyBar}} : will be replaced with HTML code to inject the upper menu bar {{.ThemeCSS}} : will be replaced by the theme.css . It is empty by default, but can be overrided by using contexts . {{.Favicon}} : will be replaced by the favicon served by the stack. This allows to get this kind of index.html : < html lang = \"{{.Locale}}\" > < head > < meta charset = \"utf-8\" > < title > My Awesome App for Cozy < meta name = \"viewport\" content = \"width=device-width, initial-scale=1\" > < link rel = \"stylesheet\" src = \"my-app.css\" > {{.ThemeCSS}} {{.CozyClientJS}} {{.CozyBar}} < body > < div role = \"application\" data-cozy-token = \"{{.Token}}\" data-cozy-stack = \"{{.Domain}}\" > < script src = \"my-app.js\" > ", "title": "How the application works?"}, {"location": "tutorials/app/#read-the-application-manifest", "text": "Each application must have a \u201cmanifest\u201d. It\u2019s a JSON file named manifest.webapp stored at the root of the application directory. It describes the application, the type of documents it uses, the permissions it requires\u2026 Here\u2019s a sample manifest: { \"name\" : \"My Awesome application\" , \"name_prefix\" : \"\" , \"slug\" : \"myapp\" , \"permissions\" : { \"apps\" : { \"type\" : \"io.cozy.apps\" }, \"permissions\" : { \"type\" : \"io.cozy.permissions\" }, \"settings\" : { \"type\" : \"io.cozy.settings\" }, \"sample\" : { \"type\" : \"io.cozy.dev.sample\" , \"verbs\" : [ \"GET\" , \"POST\" , \"PUT\" , \"PATCH\" , \"DELETE\" ] }, \"jobs\" : { \"type\" : \"io.cozy.jobs\" } }, \"routes\" : { \"/\" : { \"folder\" : \"/\" , \"index\" : \"index.html\" , \"public\" : false }, \"/public\" : { \"folder\" : \"/public\" , \"index\" : \"index.html\" , \"public\" : true } } }", "title": "Read the application manifest"}, {"location": "tutorials/app/#permissions", "text": "Applications require permissions to use most of the APIs. Permissions can be described inside the manifest, so the server can ask the user to grant them during installation. Applications can also request permissions at run time. A permission must at least contain a target, the type of objects the application want to interact with. Can be a document type, or an action on the server. By default, all permissions on this object are granted, but we can also request fine grained permissions, for example limiting to read access. We can also limit the scope to a subset of the documents. In the manifest, each permission is an object, with a random name and some properties: type : mandatory the document type or action name description : a text that will be displayed to the user to explain why the application require this permission verbs : an array of HTTP verbs. For example, to limit permissions to read access, use [\"GET\"] selector : a document attribute to limit access to a subset of documents values : array of allowed values for this attribute. An application can request a token that grant access to a subset of its own permissions. For example if the application has full access to the files, it can obtain a token that give only read access on a file. Thus, the application can make some documents publicly available. The public page of the application will use this token asauthentication token when accessing the API.", "title": "Permissions"}, {"location": "tutorials/app/#samples", "text": "Application requiring full access to files: { \"permissions\" : { \"files\" : { \"description\" : \"\u2026\" , \"type\" : \"io.cozy.files\" }, } } Application wanting to be able to read the contact information of cozy@cozycloud.cc { \"permissions\" : { \"contact\" : { \"type\" : \"io.cozy.contacts\" , \"verbs\" : [ \"GET\" ], \"selector\" : \"email\" , \"values\" : [ \"cozy@cozycloud.cc\" ] } } }", "title": "Samples"}, {"location": "tutorials/app/#routing", "text": "The application must declare all of its URLs (routes) inside the manifest. A route is an object associating an URL to a HTML file. Each route has the following properties: folder : the base folder of the route index : the name of the file inside this folder public : a boolean specifying whether the route is public or private (default). Sample: \"routes\" : { \"/admin\" : { \"folder\" : \"/\" , \"index\" : \"admin.html\" , \"public\" : false }, \"/public\" : { \"folder\" : \"/public\" , \"index\" : \"index.html\" , \"public\" : true }, \"/assets\" : { \"folder\" : \"/assets\" , \"public\" : true } }", "title": "Routing"}, {"location": "tutorials/app/#behind-the-magic", "text": "Some server APIs may not be available right now through the library. If you want to use one of this method, you\u2019ll have to call it manually. We\u2019ll describe here how to access the API without using the Cozy Client library. Connecting to the API requires three things: its URL, injected into the page through the {{.Domain}} variable the application auth token, injected into the page through the {{.Token}} variable. Each request sent to the server must include this token in the Authorization header the session cookie, created when you connect to your server. This is an HttpOnly cookie , meaning that JavaScript applications can\u2019t read it. This prevent a malicious script to steal the cookie. Here\u2019s a sample code that get API informations provided by the server and query the API: < div data-cozy-token = \"{{.Token}}\" data-cozy-domain = \"{{.Domain}}\" /> document . addEventListener ( 'DOMContentLoaded' , () => { \"use strict\" ; const app = document . querySelector ( '[data-cozy-token]' ); fetch ( `// ${ app . dataset . cozyDomain } /apps` , { method : 'GET' , headers : { Authorization : `Bearer ${ app . dataset . cozyToken } ` // Here we use the auth token }, credentials : 'include' // Don\u2019t forget to include the session cookie }) . then (( response ) => { if ( response . ok ) { response . json (). then (( result ) => { console . log ( result ); }); } else { throw new Error ( 'Network response was not ok.' ); } }) . catch (( error ) => { console . log ( 'There has been a problem with your fetch operation: ' + error . message ); }); });", "title": "Behind the magic"}, {"location": "tutorials/app/#handle-data-with-cozy-client", "text": "cozy-client is a simple and declarative way of managing cozy-stack API calls and resulting data. It is a convenient and powerful way to bind cozy-stack queries to your components. Getting started React integration API docs", "title": "Handle data with cozy-client"}, {"location": "tutorials/app/#discover-the-cozy-bar", "text": "The Cozy Bar is a component that displays the Cozy menu on the top of your application and allows inter-apps features like content sharing. Your application interacts with this component through cozy-bar.js , a library injected into your pages by the server when you add {{.CozyBar}} in the header. It exposes an API behind the window.cozy.bar namespace. Before using it, you have to initialize the library: window.cozy.bar.init({appName: \"Mon application\"}) .", "title": "Discover the Cozy Bar"}, {"location": "tutorials/app/#style-with-cozy-ui", "text": "If you plan to build a webapp to run on Cozy, you\u2019ll probably want to use a simple and elegant solution to build your interfaces without the mess of dealing with complex markup and CSS. Then Cozy UI is here for you! It relies on Stylus as preprocessor. You can add it as a library in your project to use it out-of-the-box.", "title": "Style with Cozy UI"}, {"location": "tutorials/readme/", "text": "", "title": "Readme"}, {"location": "tutorials/client-side-konnector/", "text": "A client-side konnector (also know as CLISK ) is a script that imports data from another web service and put those data into your cozy. Each client-side konnector is an independent application, managed by the Cozy Home application. The specificity with the client-side konnectors in comparaison with a server-side konnector is that it\u2019s not only using requests to obtain the data, but it actually interacts with the targeted web service by navigating throught the website, clicking and scraping directly into the client, as a user would do in a web browser. To protect your data, each konnector runs inside a container in order to sandbox all their interactions. What will you need to start ? Node (20), follow the link to nodejs doc for proper installation. When it\u2019s done, you can check your version with node --version in your shell. Yarn , again follow the Yarn doc for proper install. Check the version with yarn --version in your shell. Android Studio , please follow the official AndroidStudio documentation for proper install. Chromium for the webview inspector, allowing you to inspect the device you are using. note: you can access the inspecter by typing chrome://inspect/#devices in the url of your chromium window In this tutorial you will learn how to: Create the basic structure for your konnector Scrape and save data from the service", "title": "Index"}, {"location": "tutorials/client-side-konnector/getting-started/", "text": "Let\u2019s create our first konnector \u00b6 Run the sample \u00b6 \u2757 Replace links when all had been set up The easiest way to create a new konnector is to use the clisk-template First of all, download or clone the repository: git clone https://github.com/konnectors/cozy-konnector-template/ [ newslug ] cd [ newslug ] rm -rf .git git init yarn install # or npm install note: we use yarn , but if you prefer npm , keep using it, everything should work. The konnector is ready to run with sample code. As a demo we will scrape a fictional website: books.toscrape.com , for which you do not need credentials . If you have arrived here, good job ! You are ready to implement your konnector .", "title": "Getting started"}, {"location": "tutorials/client-side-konnector/getting-started/#lets-create-our-first-konnector", "text": "", "title": "Let\u2019s create our first konnector"}, {"location": "tutorials/client-side-konnector/getting-started/#run-the-sample", "text": "\u2757 Replace links when all had been set up The easiest way to create a new konnector is to use the clisk-template First of all, download or clone the repository: git clone https://github.com/konnectors/cozy-konnector-template/ [ newslug ] cd [ newslug ] rm -rf .git git init yarn install # or npm install note: we use yarn , but if you prefer npm , keep using it, everything should work. The konnector is ready to run with sample code. As a demo we will scrape a fictional website: books.toscrape.com , for which you do not need credentials . If you have arrived here, good job ! You are ready to implement your konnector .", "title": "Run the sample"}, {"location": "tutorials/client-side-konnector/scrape-data/", "text": "In this part, we are going to see how to scrape data from the service you want to retrieve your data from. If not done yet, you want to check the getting started guide . Implement your konnector \u00b6 For the purpose of this guide, let\u2019s consider we are in the case of a full HTML webpage, like the service given as an example in the template: books to scrape . There are few steps for a konnector to save data to Cozy Stack : Authentication Scrap and/or request data Parse and format data Save data to cozy stack In a client-side connector those steps are mainly done by the following three functions called by the ContentScript.js each and every time the konnector is triggered. ///////// //PILOT// async ensureAuthenticated () { // First step } async getUserDataFromWebsite () { // Second step & // Third step } async fetch ( context ) { // Fourth step } As mentionned, those three fundamental functions are called every time the konnector is executing, but it is up to you to custom them regarding your needs and the service you are expecting to take the data from. The pilot/worker principle \u00b6 A very specific and important notion to keep in mind: We are using two webviews to make a konnector run - a Pilot - and a Worker As explicit as the name can be, the Pilot treats with the cozy-stack, the Worker interacts with the webservice and sends information to the Pilot . Both accesses the ContentScript.js methods, but some methods are designed to be restricted (like runInWorker , only usable in the Pilot ) but we\u2019ll come to that in details during this tutorial. Authentication \u00b6 Open the src/index.js file, there are comments to guide you through it. The very first step is to be able to define if the user is authenticated to the remote service. This is done with: async ensureAuthenticated () {} As books.toscrape.com does not have any login form, let\u2019s say the remote service exposes a simple classical form like trainline.eu : < form id = \"signin-form\" novalidate = \"\" class = \"signin__form\" data-ember-action = \"\" data-ember-action-680 = \"680\" > < input name = \"email\" autocomplete = \"on\" placeholder = \"Email Address\" id = \"ember691\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"email\" > < input name = \"password\" autocomplete = \"on\" placeholder = \"Password\" id = \"ember696\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"password\" > < div class = \"signin__forgot\" > < span data-ember-action = \"\" data-ember-action-697 = \"697\" > < a href = \"/password\" id = \"ember698\" class = \"ember-view\" > Forgot your password? < div class = \"signin__buttons \" > < div class = \"signin__buttons-block\" > < button type = \"submit\" class = \"signin__button\" > Sign In At this point, you got to tell the Pilot to set the Worker on the wanted web page (baseUrl). To be sure the page is loaded properly, you need to wait for an HTML element (here, let\u2019s say it is the button leading you to the quotes page). async ensureAuthenticated () { await this . goto ( baseUrl ) // Set the worker on the baseUrl await this . waitForElementInWorker ( defaultSelector ) // Wait for quotes link element in the worker } Once waitForElementInWorker will respond, you try to click on this button and wait for another element telling you the page is loaded. Here we are waiting for either a button to a login page or the logout button. async ensureAuthenticated () { await this . goto ( baseUrl ) await this . waitForElementInWorker ( defaultSelector ) await this . runInWorker ( 'click' , defaultSelector ) // Click on quotes link element in the worker await Promise . race ([ this . waitForElementInWorker ( loginLinkSelector ), this . waitForElementInWorker ( logoutLinkSelector ) ]) // Wait for both logout or login link to be sure to check authentication when ready } When one of them is true, you need to check if the user is already logged in or not. If not, we trigger the showLoginFormAndWaitForAuthentication function. async ensureAuthenticated () { await this . goto ( baseUrl ) await this . waitForElementInWorker ( defaultSelector ) await this . runInWorker ( 'click' , defaultSelector ) await Promise . race ([ this . waitForElementInWorker ( loginLinkSelector ), this . waitForElementInWorker ( logoutLinkSelector ) ]) const authenticated = await this . runInWorker ( 'checkAuthenticated' ) // Checking authentication if ( ! authenticated ) { this . log ( 'not authenticated' ) await this . showLoginFormAndWaitForAuthentication () // Triggering the user authentication process } return true // Return true to continue konnector execution } The showLoginFormAndWaitForAuthentication function will remain at least like this: async showLoginFormAndWaitForAuthentication () { await this . setWorkerState ({ visible : true }) // Show the webview to the user await this . runInWorkerUntilTrue ({ method : 'waitForAuthenticated' }) // Wait for user to connect await this . setWorkerState ({ visible : false }) // Hide the webview to the user } You can always add more actions to it if you need so, but those three are mandatory. First will show to the user the Worker webview. Second will actually wait for the user manual authentication. This will trigger waitForAuthenticated which wait for checkAuthenticated to return true from the worker (more about it in an instant). This allows us to bypass eventual captcha/2FA or anti-bot securities. Last will hide the Worker webview from the user before continuing execution. async showLoginFormAndWaitForAuthentication () { log . debug ( 'showLoginFormAndWaitForAuthentication start' ) // You can add some logs of course await this . clickAndWait ( loginLinkSelector , '#username' ) // Or an action before or after . Here we clicking on the loginPage element and wait for the username input of the form await this . setWorkerState ({ visible : true }) await this . runInWorkerUntilTrue ({ method : 'waitForAuthenticated' }) await this . setWorkerState ({ visible : false }) } checkAuthenticated is a ContentScript.js method that you need to customize and it needs to return true at some point. This is a check to determine if the user login had been successful or not and as it is launched with runInWorkerUntilTrue , it will run again and again until\u2026 Well, until it responds true ! async checkAuthenticated () { if ( document . querySelector ( logoutLinkSelector )){ this . log ( 'Auth Check succeeded' ) return true } return false } In the block example above, if we find the logoutLinkSelector , it means the user is actually connected, so the function might return true . Getting the data \u00b6 Once the user has been authenticated, the konnector is able to navigate on the web service to fetch data. The most common case is that the documents, e.g. invoices, we want to fetch are listed in a HTML page. So to fetch data, we navigate to the target webpage that contains the invoices, just like a user would. But sometimes, the webpage is a JavaScript page that uses a JSON API URL. We\u2019ll cover this case later in this tutorial. First you need to customize the getUserDataFromWebsite function. Remember, any required action to access the data you are looking for, must be executed in the Worker webview. Some functions are already foreseen in the ContentScript , but for more complex action, you will need to make your own. So, how does it works? In this example, we wanna scrap data of the user but also the Music section. Let\u2019s start with the books section async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) // Calling ContentScript method 'click' in the worker await this . waitForElementInWorker ( sectionHeaderSelector ) } Now we need to check if the landing page is what we expected. On this website, one of the way to do this is to see if the element with the class section-header is containing the string \u201cMusic\u201d. To do this, we\u2019ll need a more powerful function than the ones we have in the ContentScript . Let\u2019s do this. First, you will need to declare this function to the ContentScript , so it knows it exist and it can be triggered. At the very bottom of the index.js , you can find the connector.init function taking one argument with an array additionalExposedMethodsNames . Everytime you will need to build a new function for the pilot to give to the worker, you will need to declare it in this array like so: connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , ] }) Now it is done, we can give it to the Worker : async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) await this . runInWorker ( 'checkIfRightPage' ) } And define what the function will do. // Homemade function can be async too checkIfRightPage () { const selectorContent = document . querySelector ( sectionHeaderSelector ). textContent . trim () if ( selectorContent === \"Music\" ){ return true } return false } At this point, your new function should return true, so let\u2019s continue. Because you are checking and returning a value, you can now decide what to do depending on the response. async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ let await this . runInWorker ( 'getBooksData' ) // Another custom function, with an argument } else { throw new Error ( 'Something went wrong when accessing the Music section' ) } } Dont forget to declare it! connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , 'getBooksData' , ] }) And define what it will do. getBooksData () { const bookList = document . querySelectorAll ( musicBooksSelector ) allBooks = [] for ( const book of bookList ){ const aBook = book . children [ 0 ] const title = aBook . children [ 2 ]. children [ 0 ]. getAttribute ( 'title' ) const starRating = aBook . children [ 1 ]. getAttribute ( 'class' ). split ( ' ' )[ 1 ] const price = aBook . children [ 3 ]. children [ 0 ]. textContent const inStock = aBook . children [ 3 ]. children [ 1 ]. textContent . includes ( 'In stock' ) const fileurl = aBook . children [ 3 ]. children [ 2 ]. getAttribute ( 'href' ) const filename = ` ${ title . replace ( / /g , '-' ) } _ ${ starRating } -stars_ ${ price } .pdf` const newBook = { fileurl , filename , title , starRating , price , inStock } allBooks . push ( newBook ) } await this . sendToPilot ({ allBooks }) } Once you are at the Worker level, if you need more functions, these ones do not need to be declared in additionalExposedMethodsNames , just add it into the Class. Now the Music section has been scraped and the result of this scraping is returned and stored in the musicBooks variable, let\u2019s do the same for the user data. async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ await this . runInWorker ( 'getMusicBooksData' ) await this . clickAndWait ( personnalInfoSectionSelector , sectionHeaderSelector ) // Once again you can test the page, we won't do this here for clarity await this . runInWorker ( 'getUserData' ) // One more custom function } else { throw new Error ( 'Something went wrong when accessing the Music section' ) } } Never forget to declare it. connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , 'getMusicBooksData' , 'getUserData' , ] }) And define what it will do. In this website, there is no possible login so there is no user\u2019s information page. We\u2019ll just act like there is one. getUserData () { const userInfos = document . querySelector ( userInfosSelector ) const name = userInfos . children [ 0 ] const [ firstName , lastName ] = name . split ( ' ' ) const [ street , city , postCode , country ] = userInfos . children [ 1 ]. textContent . split ( ',' ) const mobilePhoneNumber = userInfos . children [ 2 ]. textContent const email = userInfos . children [ 3 ]. textContent // This is the standard format for a cozy identity const userIdentity = { email , name : { firstName , lastName , fullName = ` ${ firstName } ${ lastName } ` }, address : [ { formattedAddress : userInfos . address , street , city , postCode , country } ], phone : [ { type : 'mobile' , number : mobilePhoneNumber } ] } await this . sendToPilot ( userIdentity ) } There we have both wanted data, let\u2019s speak about the sendToPilot . As mentioned earlier, the Pilot do not see what\u2019s happening in the Worker . It cannot access the page like the Worker does so it cannot find and manipulate the data by itself. It is a way for us to ensure that there is no communication between the website and your cozy. The Pilot is the only one who can save data into your cozy, but the Worker is the only one who can access this data. The only way to access any type of data manipulation in the Pilot is to pass the data from the Worker to the Pilot . This is done with sendToPilot . This function will trigger a storeFromWorker function on the Pilot side and will save the data into the store . You will be able to access this data anywhere in the execution now, in the Pilot with this.store and in the Worker when passing the store as an argument of a function. To properly finish the getUserDataFromWebsite function, the stack is waiting for a sourceAccountIdentifier to get returned. If you found an email while scraping the user\u2019s data, it is usually what is used. If you don\u2019t end up with an email for some reason, you got to define at the beginning of the code a DEFAULT_SOURCE_ACCOUNT_IDENTIFIER with the vendor\u2019s name. const DEFAULT_SOURCE_ACCOUNT_IDENTIFIER = \"bookstoscrape\" async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ await this . runInWorker ( 'getMusicBooksData' ) await this . clickAndWait ( personnalInfoSectionSelector , sectionHeaderSelector ) await this . runInWorker ( 'getUserData' ) } if ( this . store . userIdentity . email ){ // getUserData is supposed to have sent the userIdentity to the pilot, so we check the store return { sourceAccountIdentifier : this . store . userIdentity . email } } else { this . log ( \"Couldn't get a sourceAccountIdentifier, using default\" ) return { sourceAccountIdentifier : DEFAULT_SOURCE_ACCOUNT_IDENTIFIER } } } Well done, you just finished the data part! Now let\u2019s save it with the fetch method, the last step in freeing your data with a client-side konnector. Saving the data \u00b6 Saving data is pretty easy after the work done above and it\u2019s done within fetch . async fetch ( context ) {} One thing you will need everytime when you save files in your cozy is the context . This allows the Pilot to use the same context as the Worker , meaning the download call will look like it is made from the same webview as the navigation was made. Next, you have some questions to ask to yourself before actually saving those data on your cozy. What kind of data is it? For now, we\u2019ll consider you are dealing with files. You need to define if the file you are about to save is either a bill or a file . The specificity of the bill is that it represents actual invoices. It could be linked to operations in your Cozy Banks, but it will need some data like an amount and a vendor added . Here we gonna save the books \u201cthemselves\u201d, as there is no actual file to download, we\u2019ll pretend we\u2019re saving the .pdf of the books so let\u2019s go with a saveFiles . What is the content-type of the file? Usually something you can find in headers, describing what type of content is supposed to be downloaded. For us it\u2019s a pdf , but it can be anything : zip, photos, excel sheets \u2026 What will be the attribute on which the deduplication will base its logic? The fileIdAttribute will use the given attribute to know if the file needed to be saved or if it had already been downloaded. The simpliest way to differentiate two files is by their name, but in some cases (like linked bills ) you will need something more revelant for the linking operation to hold all the bills for a same month and still save one file per month. What is the qualification label for these documents? Cozy follows certains conventions regarding the documents qualification. You can find the list of available qualifications and see if something is fitting your needs. Those qualification attributes are very useful to enrich the fetched documents with metadata and use them in apps. Here, let\u2019s use a fictive qualification label, named \u201cdigital_book\u201d. async fetch ( context ) { this . log ( \"fetch starts\" ) // Passing our scraping result containing all our books and their data to saveFiles // And options Object with the answers of our interrogations await this . saveFiles ( this . store . allBooks , { context , contentType : 'application/pdf' , fileIdAttributes : [ 'filename' ], qualificationLabel : 'digital_book' }) } If needed, you can add some actions in fetch before or after the saveFiles . Here we\u2019ll pretend we need to disconnect from the webservice after retrieving the data. For that, we can simply click on the logout button in the worker and wait for the button leading you to the login form. async fetch ( context ) { this . log ( \"fetch starts\" ) // Passing our scraping result containing all our books and their data to saveFiles // And options Object with the answers of our interrogations await this . saveFiles ( this . store . allBooks , { context , contentType : 'application/pdf' , fileIdAttributes : [ 'filename' ], qualificationLabel : 'digital_book' }) await this . clickAndWait ( logoutButtonSelector , loginButtonSelector ) } And that\u2019s all done! You successfully saved your data, you now have new books to read in your cozy! This is the basics of freeing your data with a client-side konnector. In the future, we will address a topic about more specific cases requiring other ContentScript methods and other technics to get back what you own (your data, right ?). To wrap up, this is what your konnector should look like all together: const DEFAULT_SOURCE_ACCOUNT_IDENTIFIER = \"bookstoscrape\" class TemplateContentScript extends ContentScript { ////////// //PILOT // ////////// async ensureAuthenticated () { await this . goto ( baseUrl ) await this . waitForElementInWorker ( defaultSelector ) await this . runInWorker ( 'click' , defaultSelector ) await Promise . race ([ this . waitForElementInWorker ( loginLinkSelector ), this . waitForElementInWorker ( logoutLinkSelector ) ]) const authenticated = await this . runInWorker ( 'checkAuthenticated' ) if ( ! authenticated ) { this . log ( 'not authenticated' ) await this . showLoginFormAndWaitForAuthentication () } return true } async showLoginFormAndWaitForAuthentication () { log . debug ( 'showLoginFormAndWaitForAuthentication start' ) await this . clickAndWait ( loginLinkSelector , '#username' ) await this . setWorkerState ({ visible : true }) await this . runInWorkerUntilTrue ({ method : 'waitForAuthenticated' }) await this . setWorkerState ({ visible : false }) } async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ await this . runInWorker ( 'getMusicBooksData' ) await this . clickAndWait ( personnalInfoSectionSelector , sectionHeaderSelector ) await this . runInWorker ( 'getUserData' ) } if ( this . store . userIdentity . email ){ return { sourceAccountIdentifier : this . store . userIdentity . email } } else { this . log ( \"Couldn't get a sourceAccountIdentifier, using default\" ) return { sourceAccountIdentifier : DEFAULT_SOURCE_ACCOUNT_IDENTIFIER } } } async fetch ( context ) { this . log ( \"fetch starts\" ) await this . saveFiles ( this . store . allBooks , { context , contentType : 'application/pdf' , fileIdAttributes : [ 'filename' ], qualificationLabel : 'digital_book' }) await this . clickAndWait ( logoutButtonSelector , loginButtonSelector ) } ////////// //WORKER// ////////// async checkAuthenticated () { if ( document . querySelector ( logoutLinkSelector )){ this . log ( 'Auth Check succeeded' ) return true } return false } checkIfRightPage () { const selectorContent = document . querySelector ( sectionHeaderSelector ). textContent . trim () if ( selectorContent === \"Music\" ){ return true } return false } getUserData () { const userInfos = document . querySelector ( userInfosSelector ) const name = userInfos . children [ 0 ] const [ firstName , lastName ] = name . split ( ' ' ) const [ street , city , postCode , country ] = userInfos . children [ 1 ]. textContent . split ( ',' ) const mobilePhoneNumber = userInfos . children [ 2 ]. textContent const email = userInfos . children [ 3 ]. textContent const userIdentity = { email , name : { firstName , lastName , fullName = ` ${ firstName } ${ lastName } ` }, address : [ { formattedAddress : userInfos . address , street , city , postCode , country } ], phone : [ { type : 'mobile' , number : mobilePhoneNumber } ] } await this . sendToPilot ( userIdentity ) } } connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , 'getMusicBooksData' , 'getUserData' , ] }). catch ( err => { console . warn ( err ) })", "title": "Scrape data"}, {"location": "tutorials/client-side-konnector/scrape-data/#implement-your-konnector", "text": "For the purpose of this guide, let\u2019s consider we are in the case of a full HTML webpage, like the service given as an example in the template: books to scrape . There are few steps for a konnector to save data to Cozy Stack : Authentication Scrap and/or request data Parse and format data Save data to cozy stack In a client-side connector those steps are mainly done by the following three functions called by the ContentScript.js each and every time the konnector is triggered. ///////// //PILOT// async ensureAuthenticated () { // First step } async getUserDataFromWebsite () { // Second step & // Third step } async fetch ( context ) { // Fourth step } As mentionned, those three fundamental functions are called every time the konnector is executing, but it is up to you to custom them regarding your needs and the service you are expecting to take the data from.", "title": "Implement your konnector"}, {"location": "tutorials/client-side-konnector/scrape-data/#the-pilotworker-principle", "text": "A very specific and important notion to keep in mind: We are using two webviews to make a konnector run - a Pilot - and a Worker As explicit as the name can be, the Pilot treats with the cozy-stack, the Worker interacts with the webservice and sends information to the Pilot . Both accesses the ContentScript.js methods, but some methods are designed to be restricted (like runInWorker , only usable in the Pilot ) but we\u2019ll come to that in details during this tutorial.", "title": "The pilot/worker principle"}, {"location": "tutorials/client-side-konnector/scrape-data/#authentication", "text": "Open the src/index.js file, there are comments to guide you through it. The very first step is to be able to define if the user is authenticated to the remote service. This is done with: async ensureAuthenticated () {} As books.toscrape.com does not have any login form, let\u2019s say the remote service exposes a simple classical form like trainline.eu : < form id = \"signin-form\" novalidate = \"\" class = \"signin__form\" data-ember-action = \"\" data-ember-action-680 = \"680\" > < input name = \"email\" autocomplete = \"on\" placeholder = \"Email Address\" id = \"ember691\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"email\" > < input name = \"password\" autocomplete = \"on\" placeholder = \"Password\" id = \"ember696\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"password\" > < div class = \"signin__forgot\" > < span data-ember-action = \"\" data-ember-action-697 = \"697\" > < a href = \"/password\" id = \"ember698\" class = \"ember-view\" > Forgot your password? < div class = \"signin__buttons \" > < div class = \"signin__buttons-block\" > < button type = \"submit\" class = \"signin__button\" > Sign In At this point, you got to tell the Pilot to set the Worker on the wanted web page (baseUrl). To be sure the page is loaded properly, you need to wait for an HTML element (here, let\u2019s say it is the button leading you to the quotes page). async ensureAuthenticated () { await this . goto ( baseUrl ) // Set the worker on the baseUrl await this . waitForElementInWorker ( defaultSelector ) // Wait for quotes link element in the worker } Once waitForElementInWorker will respond, you try to click on this button and wait for another element telling you the page is loaded. Here we are waiting for either a button to a login page or the logout button. async ensureAuthenticated () { await this . goto ( baseUrl ) await this . waitForElementInWorker ( defaultSelector ) await this . runInWorker ( 'click' , defaultSelector ) // Click on quotes link element in the worker await Promise . race ([ this . waitForElementInWorker ( loginLinkSelector ), this . waitForElementInWorker ( logoutLinkSelector ) ]) // Wait for both logout or login link to be sure to check authentication when ready } When one of them is true, you need to check if the user is already logged in or not. If not, we trigger the showLoginFormAndWaitForAuthentication function. async ensureAuthenticated () { await this . goto ( baseUrl ) await this . waitForElementInWorker ( defaultSelector ) await this . runInWorker ( 'click' , defaultSelector ) await Promise . race ([ this . waitForElementInWorker ( loginLinkSelector ), this . waitForElementInWorker ( logoutLinkSelector ) ]) const authenticated = await this . runInWorker ( 'checkAuthenticated' ) // Checking authentication if ( ! authenticated ) { this . log ( 'not authenticated' ) await this . showLoginFormAndWaitForAuthentication () // Triggering the user authentication process } return true // Return true to continue konnector execution } The showLoginFormAndWaitForAuthentication function will remain at least like this: async showLoginFormAndWaitForAuthentication () { await this . setWorkerState ({ visible : true }) // Show the webview to the user await this . runInWorkerUntilTrue ({ method : 'waitForAuthenticated' }) // Wait for user to connect await this . setWorkerState ({ visible : false }) // Hide the webview to the user } You can always add more actions to it if you need so, but those three are mandatory. First will show to the user the Worker webview. Second will actually wait for the user manual authentication. This will trigger waitForAuthenticated which wait for checkAuthenticated to return true from the worker (more about it in an instant). This allows us to bypass eventual captcha/2FA or anti-bot securities. Last will hide the Worker webview from the user before continuing execution. async showLoginFormAndWaitForAuthentication () { log . debug ( 'showLoginFormAndWaitForAuthentication start' ) // You can add some logs of course await this . clickAndWait ( loginLinkSelector , '#username' ) // Or an action before or after . Here we clicking on the loginPage element and wait for the username input of the form await this . setWorkerState ({ visible : true }) await this . runInWorkerUntilTrue ({ method : 'waitForAuthenticated' }) await this . setWorkerState ({ visible : false }) } checkAuthenticated is a ContentScript.js method that you need to customize and it needs to return true at some point. This is a check to determine if the user login had been successful or not and as it is launched with runInWorkerUntilTrue , it will run again and again until\u2026 Well, until it responds true ! async checkAuthenticated () { if ( document . querySelector ( logoutLinkSelector )){ this . log ( 'Auth Check succeeded' ) return true } return false } In the block example above, if we find the logoutLinkSelector , it means the user is actually connected, so the function might return true .", "title": "Authentication"}, {"location": "tutorials/client-side-konnector/scrape-data/#getting-the-data", "text": "Once the user has been authenticated, the konnector is able to navigate on the web service to fetch data. The most common case is that the documents, e.g. invoices, we want to fetch are listed in a HTML page. So to fetch data, we navigate to the target webpage that contains the invoices, just like a user would. But sometimes, the webpage is a JavaScript page that uses a JSON API URL. We\u2019ll cover this case later in this tutorial. First you need to customize the getUserDataFromWebsite function. Remember, any required action to access the data you are looking for, must be executed in the Worker webview. Some functions are already foreseen in the ContentScript , but for more complex action, you will need to make your own. So, how does it works? In this example, we wanna scrap data of the user but also the Music section. Let\u2019s start with the books section async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) // Calling ContentScript method 'click' in the worker await this . waitForElementInWorker ( sectionHeaderSelector ) } Now we need to check if the landing page is what we expected. On this website, one of the way to do this is to see if the element with the class section-header is containing the string \u201cMusic\u201d. To do this, we\u2019ll need a more powerful function than the ones we have in the ContentScript . Let\u2019s do this. First, you will need to declare this function to the ContentScript , so it knows it exist and it can be triggered. At the very bottom of the index.js , you can find the connector.init function taking one argument with an array additionalExposedMethodsNames . Everytime you will need to build a new function for the pilot to give to the worker, you will need to declare it in this array like so: connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , ] }) Now it is done, we can give it to the Worker : async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) await this . runInWorker ( 'checkIfRightPage' ) } And define what the function will do. // Homemade function can be async too checkIfRightPage () { const selectorContent = document . querySelector ( sectionHeaderSelector ). textContent . trim () if ( selectorContent === \"Music\" ){ return true } return false } At this point, your new function should return true, so let\u2019s continue. Because you are checking and returning a value, you can now decide what to do depending on the response. async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ let await this . runInWorker ( 'getBooksData' ) // Another custom function, with an argument } else { throw new Error ( 'Something went wrong when accessing the Music section' ) } } Dont forget to declare it! connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , 'getBooksData' , ] }) And define what it will do. getBooksData () { const bookList = document . querySelectorAll ( musicBooksSelector ) allBooks = [] for ( const book of bookList ){ const aBook = book . children [ 0 ] const title = aBook . children [ 2 ]. children [ 0 ]. getAttribute ( 'title' ) const starRating = aBook . children [ 1 ]. getAttribute ( 'class' ). split ( ' ' )[ 1 ] const price = aBook . children [ 3 ]. children [ 0 ]. textContent const inStock = aBook . children [ 3 ]. children [ 1 ]. textContent . includes ( 'In stock' ) const fileurl = aBook . children [ 3 ]. children [ 2 ]. getAttribute ( 'href' ) const filename = ` ${ title . replace ( / /g , '-' ) } _ ${ starRating } -stars_ ${ price } .pdf` const newBook = { fileurl , filename , title , starRating , price , inStock } allBooks . push ( newBook ) } await this . sendToPilot ({ allBooks }) } Once you are at the Worker level, if you need more functions, these ones do not need to be declared in additionalExposedMethodsNames , just add it into the Class. Now the Music section has been scraped and the result of this scraping is returned and stored in the musicBooks variable, let\u2019s do the same for the user data. async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ await this . runInWorker ( 'getMusicBooksData' ) await this . clickAndWait ( personnalInfoSectionSelector , sectionHeaderSelector ) // Once again you can test the page, we won't do this here for clarity await this . runInWorker ( 'getUserData' ) // One more custom function } else { throw new Error ( 'Something went wrong when accessing the Music section' ) } } Never forget to declare it. connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , 'getMusicBooksData' , 'getUserData' , ] }) And define what it will do. In this website, there is no possible login so there is no user\u2019s information page. We\u2019ll just act like there is one. getUserData () { const userInfos = document . querySelector ( userInfosSelector ) const name = userInfos . children [ 0 ] const [ firstName , lastName ] = name . split ( ' ' ) const [ street , city , postCode , country ] = userInfos . children [ 1 ]. textContent . split ( ',' ) const mobilePhoneNumber = userInfos . children [ 2 ]. textContent const email = userInfos . children [ 3 ]. textContent // This is the standard format for a cozy identity const userIdentity = { email , name : { firstName , lastName , fullName = ` ${ firstName } ${ lastName } ` }, address : [ { formattedAddress : userInfos . address , street , city , postCode , country } ], phone : [ { type : 'mobile' , number : mobilePhoneNumber } ] } await this . sendToPilot ( userIdentity ) } There we have both wanted data, let\u2019s speak about the sendToPilot . As mentioned earlier, the Pilot do not see what\u2019s happening in the Worker . It cannot access the page like the Worker does so it cannot find and manipulate the data by itself. It is a way for us to ensure that there is no communication between the website and your cozy. The Pilot is the only one who can save data into your cozy, but the Worker is the only one who can access this data. The only way to access any type of data manipulation in the Pilot is to pass the data from the Worker to the Pilot . This is done with sendToPilot . This function will trigger a storeFromWorker function on the Pilot side and will save the data into the store . You will be able to access this data anywhere in the execution now, in the Pilot with this.store and in the Worker when passing the store as an argument of a function. To properly finish the getUserDataFromWebsite function, the stack is waiting for a sourceAccountIdentifier to get returned. If you found an email while scraping the user\u2019s data, it is usually what is used. If you don\u2019t end up with an email for some reason, you got to define at the beginning of the code a DEFAULT_SOURCE_ACCOUNT_IDENTIFIER with the vendor\u2019s name. const DEFAULT_SOURCE_ACCOUNT_IDENTIFIER = \"bookstoscrape\" async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ await this . runInWorker ( 'getMusicBooksData' ) await this . clickAndWait ( personnalInfoSectionSelector , sectionHeaderSelector ) await this . runInWorker ( 'getUserData' ) } if ( this . store . userIdentity . email ){ // getUserData is supposed to have sent the userIdentity to the pilot, so we check the store return { sourceAccountIdentifier : this . store . userIdentity . email } } else { this . log ( \"Couldn't get a sourceAccountIdentifier, using default\" ) return { sourceAccountIdentifier : DEFAULT_SOURCE_ACCOUNT_IDENTIFIER } } } Well done, you just finished the data part! Now let\u2019s save it with the fetch method, the last step in freeing your data with a client-side konnector.", "title": "Getting the data"}, {"location": "tutorials/client-side-konnector/scrape-data/#saving-the-data", "text": "Saving data is pretty easy after the work done above and it\u2019s done within fetch . async fetch ( context ) {} One thing you will need everytime when you save files in your cozy is the context . This allows the Pilot to use the same context as the Worker , meaning the download call will look like it is made from the same webview as the navigation was made. Next, you have some questions to ask to yourself before actually saving those data on your cozy. What kind of data is it? For now, we\u2019ll consider you are dealing with files. You need to define if the file you are about to save is either a bill or a file . The specificity of the bill is that it represents actual invoices. It could be linked to operations in your Cozy Banks, but it will need some data like an amount and a vendor added . Here we gonna save the books \u201cthemselves\u201d, as there is no actual file to download, we\u2019ll pretend we\u2019re saving the .pdf of the books so let\u2019s go with a saveFiles . What is the content-type of the file? Usually something you can find in headers, describing what type of content is supposed to be downloaded. For us it\u2019s a pdf , but it can be anything : zip, photos, excel sheets \u2026 What will be the attribute on which the deduplication will base its logic? The fileIdAttribute will use the given attribute to know if the file needed to be saved or if it had already been downloaded. The simpliest way to differentiate two files is by their name, but in some cases (like linked bills ) you will need something more revelant for the linking operation to hold all the bills for a same month and still save one file per month. What is the qualification label for these documents? Cozy follows certains conventions regarding the documents qualification. You can find the list of available qualifications and see if something is fitting your needs. Those qualification attributes are very useful to enrich the fetched documents with metadata and use them in apps. Here, let\u2019s use a fictive qualification label, named \u201cdigital_book\u201d. async fetch ( context ) { this . log ( \"fetch starts\" ) // Passing our scraping result containing all our books and their data to saveFiles // And options Object with the answers of our interrogations await this . saveFiles ( this . store . allBooks , { context , contentType : 'application/pdf' , fileIdAttributes : [ 'filename' ], qualificationLabel : 'digital_book' }) } If needed, you can add some actions in fetch before or after the saveFiles . Here we\u2019ll pretend we need to disconnect from the webservice after retrieving the data. For that, we can simply click on the logout button in the worker and wait for the button leading you to the login form. async fetch ( context ) { this . log ( \"fetch starts\" ) // Passing our scraping result containing all our books and their data to saveFiles // And options Object with the answers of our interrogations await this . saveFiles ( this . store . allBooks , { context , contentType : 'application/pdf' , fileIdAttributes : [ 'filename' ], qualificationLabel : 'digital_book' }) await this . clickAndWait ( logoutButtonSelector , loginButtonSelector ) } And that\u2019s all done! You successfully saved your data, you now have new books to read in your cozy! This is the basics of freeing your data with a client-side konnector. In the future, we will address a topic about more specific cases requiring other ContentScript methods and other technics to get back what you own (your data, right ?). To wrap up, this is what your konnector should look like all together: const DEFAULT_SOURCE_ACCOUNT_IDENTIFIER = \"bookstoscrape\" class TemplateContentScript extends ContentScript { ////////// //PILOT // ////////// async ensureAuthenticated () { await this . goto ( baseUrl ) await this . waitForElementInWorker ( defaultSelector ) await this . runInWorker ( 'click' , defaultSelector ) await Promise . race ([ this . waitForElementInWorker ( loginLinkSelector ), this . waitForElementInWorker ( logoutLinkSelector ) ]) const authenticated = await this . runInWorker ( 'checkAuthenticated' ) if ( ! authenticated ) { this . log ( 'not authenticated' ) await this . showLoginFormAndWaitForAuthentication () } return true } async showLoginFormAndWaitForAuthentication () { log . debug ( 'showLoginFormAndWaitForAuthentication start' ) await this . clickAndWait ( loginLinkSelector , '#username' ) await this . setWorkerState ({ visible : true }) await this . runInWorkerUntilTrue ({ method : 'waitForAuthenticated' }) await this . setWorkerState ({ visible : false }) } async getUserDataFromWebsite () { await this . runInWorker ( 'click' , musicSectionSelector ) await this . waitForElementInWorker ( sectionHeaderSelector ) const isRight = await this . runInWorker ( 'checkIfRightPage' ) if ( isRight ){ await this . runInWorker ( 'getMusicBooksData' ) await this . clickAndWait ( personnalInfoSectionSelector , sectionHeaderSelector ) await this . runInWorker ( 'getUserData' ) } if ( this . store . userIdentity . email ){ return { sourceAccountIdentifier : this . store . userIdentity . email } } else { this . log ( \"Couldn't get a sourceAccountIdentifier, using default\" ) return { sourceAccountIdentifier : DEFAULT_SOURCE_ACCOUNT_IDENTIFIER } } } async fetch ( context ) { this . log ( \"fetch starts\" ) await this . saveFiles ( this . store . allBooks , { context , contentType : 'application/pdf' , fileIdAttributes : [ 'filename' ], qualificationLabel : 'digital_book' }) await this . clickAndWait ( logoutButtonSelector , loginButtonSelector ) } ////////// //WORKER// ////////// async checkAuthenticated () { if ( document . querySelector ( logoutLinkSelector )){ this . log ( 'Auth Check succeeded' ) return true } return false } checkIfRightPage () { const selectorContent = document . querySelector ( sectionHeaderSelector ). textContent . trim () if ( selectorContent === \"Music\" ){ return true } return false } getUserData () { const userInfos = document . querySelector ( userInfosSelector ) const name = userInfos . children [ 0 ] const [ firstName , lastName ] = name . split ( ' ' ) const [ street , city , postCode , country ] = userInfos . children [ 1 ]. textContent . split ( ',' ) const mobilePhoneNumber = userInfos . children [ 2 ]. textContent const email = userInfos . children [ 3 ]. textContent const userIdentity = { email , name : { firstName , lastName , fullName = ` ${ firstName } ${ lastName } ` }, address : [ { formattedAddress : userInfos . address , street , city , postCode , country } ], phone : [ { type : 'mobile' , number : mobilePhoneNumber } ] } await this . sendToPilot ( userIdentity ) } } connector . init ({ additionalExposedMethodsNames : [ 'checkIfRightPage' , 'getMusicBooksData' , 'getUserData' , ] }). catch ( err => { console . warn ( err ) })", "title": "Saving the data"}, {"location": "tutorials/cloudery/", "text": "Cloudery \u00b6 This documentation explain how to use our Cloudery API to create and manager your own Cozy. Code example is provided for Python language, but this can be easily ported to any other langage, there is no real dependency to the language by itself. Full API documentation is provided here and this documentation is only about some standard usages examples. Creating a Cozy \u00b6 From web \u00b6 Send your user on /v2/{partner}/onboard . You can customize some onboarding parameters with URL query, see the documentation . Our Cloudery will onboard the user throught differents steps to gather required informations and then create the instance. Your user will received an email at the end, with an activation link to click to go on the initial passphrase definition. From API called by a client app. \u00b6 You can create an instance directly from our API. Call the POST /api/public/instances route, then poll the GET /api/public/workflows/{id} til the end of the creation. You need to have a public token to authenticate you on those endpoints. import requests token = 'xxxx' headers = { 'Authorization' : 'Bearer ' + token } base_url = 'https://manager.cozycloud.cc/api' response = requests . post ( base_url + '/v1/instances' , headers = headers , json = { 'offer' : 'some_offer' , 'email' : 'foo@example.org' , 'slug' : 'foo' , 'domain' : 'example.org' }) response = response . json () workflow = response [ 'workflow' ] while True : response = requests . get ( base_url + '/v1/workflows/' + workflow , headers = headers ) response = response . json () status = response [ 'status' ] if status in [ 'succeeded' , 'failed' , 'stopped' ]: break In case of success, your user will receive an email to continue the onboarding after he clicks on the activation link on it to go on the initial passphrase definition. Special cases \u00b6 Mobile onboarding \u00b6 For mobile onboarding, you can use the redirect parameter of the web or API endpoint to specify an universal link. After mail activation, your user will be redirected to {universal_link}?fqdn={fqdn}®isterToken={registerToken} instead of to it instance (usually https://{fqdn}/?registerToken={registerToken} ). \u26a0\ufe0f This kind of activation will break if the user use a desktop mail client or webmail or more generally any environment not able to handle universal link. The link into the email is a standard web one but the final redirection after the cloudery activation will be an universal link redirection.", "title": "Cloudery"}, {"location": "tutorials/cloudery/#cloudery", "text": "This documentation explain how to use our Cloudery API to create and manager your own Cozy. Code example is provided for Python language, but this can be easily ported to any other langage, there is no real dependency to the language by itself. Full API documentation is provided here and this documentation is only about some standard usages examples.", "title": "Cloudery"}, {"location": "tutorials/cloudery/#creating-a-cozy", "text": "", "title": "Creating a Cozy"}, {"location": "tutorials/cloudery/#from-web", "text": "Send your user on /v2/{partner}/onboard . You can customize some onboarding parameters with URL query, see the documentation . Our Cloudery will onboard the user throught differents steps to gather required informations and then create the instance. Your user will received an email at the end, with an activation link to click to go on the initial passphrase definition.", "title": "From web"}, {"location": "tutorials/cloudery/#from-api-called-by-a-client-app", "text": "You can create an instance directly from our API. Call the POST /api/public/instances route, then poll the GET /api/public/workflows/{id} til the end of the creation. You need to have a public token to authenticate you on those endpoints. import requests token = 'xxxx' headers = { 'Authorization' : 'Bearer ' + token } base_url = 'https://manager.cozycloud.cc/api' response = requests . post ( base_url + '/v1/instances' , headers = headers , json = { 'offer' : 'some_offer' , 'email' : 'foo@example.org' , 'slug' : 'foo' , 'domain' : 'example.org' }) response = response . json () workflow = response [ 'workflow' ] while True : response = requests . get ( base_url + '/v1/workflows/' + workflow , headers = headers ) response = response . json () status = response [ 'status' ] if status in [ 'succeeded' , 'failed' , 'stopped' ]: break In case of success, your user will receive an email to continue the onboarding after he clicks on the activation link on it to go on the initial passphrase definition.", "title": "From API called by a client app."}, {"location": "tutorials/cloudery/#special-cases", "text": "", "title": "Special cases"}, {"location": "tutorials/cloudery/#mobile-onboarding", "text": "For mobile onboarding, you can use the redirect parameter of the web or API endpoint to specify an universal link. After mail activation, your user will be redirected to {universal_link}?fqdn={fqdn}®isterToken={registerToken} instead of to it instance (usually https://{fqdn}/?registerToken={registerToken} ). \u26a0\ufe0f This kind of activation will break if the user use a desktop mail client or webmail or more generally any environment not able to handle universal link. The link into the email is a standard web one but the final redirection after the cloudery activation will be an universal link redirection.", "title": "Mobile onboarding"}, {"location": "tutorials/data/", "text": "Introduction \u00b6 This documentation is for developers that want to learn how to manipulate data in Cozy. Both front-end and back-end developers might find interest in this section: manipulating data cover a broad scope of concepts and traps to avoid. This is organized as follows: Queries PouchDB Doctypes Qualification Advanced", "title": "Introduction"}, {"location": "tutorials/data/#introduction", "text": "This documentation is for developers that want to learn how to manipulate data in Cozy. Both front-end and back-end developers might find interest in this section: manipulating data cover a broad scope of concepts and traps to avoid. This is organized as follows: Queries PouchDB Doctypes Qualification Advanced", "title": "Introduction"}, {"location": "tutorials/data/advanced/", "text": "Advanced concepts \u00b6 Indexes: concepts \u00b6 But why, though? \u00b6 In order to efficiently filter documents through selectors and sort them, it is important to correctly index data. An index is a way to organize documents in order to retrieve them faster. To give a simple and non-database comparison, a recipe book might have an index listing all the recipes by their name with their page number. If the reader is looking for a particular recipe, this index avoids him to scan the full book to find it. The principle is the same for databases index: we want to avoid scanning the whole database each time we are looking for specific data expressed by a selector: even though computers are way faster than humans to scan data, this task can be very time-consuming when dealing with thousands or millions of documents. In more formal terms, time complexity of a query run on a database with n documents will be O(n) without index, as it requires to scan all documents. In CouchDB, the indexes are actually B+ Trees , a structure derived from the B-Trees , that perform in O(log(n)) in average, which guarantees a very fast access time even in large datasets. From a practical point of view, B-trees, therefore, guarantee an access time of less than 10 ms even for extremely large datasets. \u2014Dr. Rudolf Bayer, inventor of the B-tree B+ Tree \u00b6 CouchDB indexes are B+ Trees. It means that indexed fields, here keys , are organized as a tree, with the documents stored in the leafs nodes. So, finding a particular document means browsing the tree, from the root to the leaf. In each node, a key has two children: the left child has all its keys inferior to the parent, while the right child has all its keys superior to the parent. In the Figure below, borrowed from the CouchDB guide , you see that each node has three keys. In CouchDB implementation, a B+ Tree node can actually store more than 1600 keys. B+ Tree This design is very efficient for range queries: in the example above, a query looking for documents having an indexed field between 1 and 3 will browse the tree to find the first document position (with a key of 1) and then get the next two contiguous documents. \u2139\ufe0f CouchDB has an append-only design: it means that there is no in-place update. Each time a document is updated, its new version is appended to the database file, and the B+ Tree is updated to reflect the change. \u2139\ufe0f It is not necessary to master the B+ Tree logic to query data, but it is good to at least be aware of the main concepts to understand the indexing logic, especially when designing complex queries. \u2139\ufe0f When indexing several document fields in the same index, the key is actually an array of those fields, e.g. an index on [\"category\", \"created_at\"] would give keys such as [\"sport\", \"2019-01-01\"] . \u2139\ufe0f A key does not have to be unique. Actually, it is often useful to group document per key, e.g. a category key can return many document with the same key value, like sport , work , etc. Indexes: why is my document not being retrieved? \u00b6 At indexing time, CouchDB evaluates if a new document should be indexed by checking if its fields match an existing index. It means that all the indexed fields must exist in the document to index it. It can be problematic for queries that need to check if a particular field exists or not. For example, this query won\u2019t work: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : { $exists : false , }, }) . indexFields ([ \"category\" ]); Here, we want to get all the todos without a category field. However, those documents will never be indexed, precisely because the field is missing. Hence, think carefully about your data before hand and do not use queries with $exists: false whenever possible. If a field is missing, it might be better to add a null value so that your documents do not have any missing fields. If this is not possible for some reasons, here is another possible solution - yet not very efficient: \u26a0\ufe0f Not efficient workaround const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ _id : { $gt : null , }, category : { $exists : false , }, }) . indexFields ([ \"_id\" ]); Here, we force an index on the _id , which always exists in any CouchDB document, and ask all the documents with \"_id\": { \"$gt\": null } . The category is not indexed so the documents without this field will enter the index. This is not efficient as it implies that the \"category\": { \"$exists\": false } condition will be evaluated in memory by CouchDB for all the documents of the database, thus making a full index scan. Indexes: performances and design \u00b6 When designing indexes on several fields, one should keep in mind that they are actually B+ Tree, as explained in this section . This can be helpful to design efficient queries and avoid performance traps. To illustrate this, let\u2019s assume you have declared this query, to get all the \u201cwork\u201d todos created in 2019: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ created_at : { $ge : \"2019-01-01\" , $lt : \"2020-01-01\" , }, category : \"work\" , }) . indexFields ([ \"created_at\" , \"category\" ]); \u26a0\ufe0f This query is actually sub-optimal. To understand this, let\u2019s represent some sample data: created_at category 2019-01-01 family 2019-01-01 sport 2019-01-01 work 2019-01-01 work 2019-01-02 work 2019-01-03 sport 2019-01-04 work \u2026 \u2026 2020-01-01 family This shows how the data is organized in the index: it is primarily sorted by created_at and then by category . First, the query is looking for all the todos starting from \"2019-01-01\" and before \"2020-01-01\" . It easily finds this range in the B+ Tree; but now it must also filter all the results to only keep the rows with category: work . And this cannot be done through the B+ Tree, because matching rows are not contiguous, as shown in green in the table: this means that CouchDB is forced to perform the category condition in memory, leading to bad performances. \ud83d\udca1 Hopefully, this example can be easily be solved by switching the index fields order: .indexFields([\"category\", \"created_at\"]) The data is now organized as follow: category created_at family 2019-01-01 ... ... sport 2019-01-01 ... ... work 2019-01-01 work 2019-01-01 work 2019-01-02 work 2019-01-03 work 2019-01-04 \u2026 \u2026 work 2020-01-01 Now, the very same query can be efficiently processed: the category: work is first evaluated in the B+ Tree, which return all the relevant rows, sorted by created_at . Then, the range is easily found now that all the rows are contiguous. \ud83d\udca1 The main takeaway here is: when dealing with a query with both equality and range, you must first index the equality field. If you are interested about this, you can learn more here . Even though it is SQL-oriented, it also applies for CouchDB as the B-Tree indexing logic is the same. \ud83d\udca1 When creating an index, carefully think about how your data will be organized and which query will need to perfom. The performances can dramatically vary depending on your design, with several orders of magnitude. \ud83d\udca1 The problematic and consequences of the not contiguous rows is further explain in the partial indexes section . Partial indexes \u00b6 In CouchDB, a document is indexed only if its fields matches an existing index. As a consequence, it is not possible to perform efficient queries on non-existing fields. For instance, the query below does not work, because it searches for document without the category field, but the absence of this field will cause such documents to never be indexed, as previously explained here : const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : { $exists : false , }, }) . indexFields ([ \"category\" ]); In the same manner, queries implying non-contiguous rows in the B+ Tree are sub-optimal. Typically, queries with a non-egal operator, $ne : const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ title : \"Exercices\" , category : { $ne : \"sport\" , }, }) . indexFields ([ \"title\" , \"category\" ]); As the $ne operator cannot guarantee contiguous rows, it needs to scan all the index on documents with the \"title\": \"Exercices\" to find those that are not in the sport category . Partial indexes are a way to circumvent this issue. They allow to define a partial selector condition that will be evaluated at the indexing time, and will add the document in the index if it matches the condition. Thanks to this, it becomes possible to tell CouchDB at indexing time to exlude documents that do not match the condition, e.g. \"category\": { \"$exists\": false} or \"category\": { \"$ne\": \"sport\"} . Hence, the produced index will only include documents that already matched the partial filter selector, making it possible to query them, as this selector enforces contiguous rows or documents with missing fields. You can declare a partial index in cozy-client like this: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ title : \"Exercices\" , }) . partialIndex ({ category : { $ne : \"sport\" , }, }) . indexFields ([ \"title\" ]); partialIndex supports the same syntax than the where , so you can easily move inefficient selectors into partial indexes. Note in this example, it is no longer necessary to index the category field, as the field is now evaluated at indexing time, rather than during the query. Hence, a partial index is also useful to design less heavy indexes. Mango pagination: performances \u00b6 With mango queries, the recommanded method to paginate is through the bookmark parameter. However, one could also notice the skip parameter in the CouchDB API and be tempted to paginate with it. We detail here why you should never use skip to paginate and use bookmark instead. We explain it for exhaustiveness and to prevent developers to fall into this trap. This method consists of specifying a limit to the query, which is the maximum number of documents to return, and a skip parameter that is the number of documents returned so far. With cozy-client, its is expressed through limitBy and offset . \u26a0\ufe0f Do not use this: const docs = []; let resp = { next : true , data : [] }; while ( resp && resp . next ) { resp = await client . query ( Q ( \"io.cozy.todos\" ). limitBy ( 200 ). offset ( resp . data . length ) ); docs . push (... resp . data ); } This method is very bad for performances because it actually breaks the B+ Tree indexing logic: there is no way to efficiently skip a fixed number of data in such a tree, so skipping documents consists of normally running the query and then splitting the results starting from the skip number of documents. Thus, the performances quickly degrade when there are many documents to skip. On the contrary, the bookmark method is very efficient as it preserves the B+ Tree logic. One can see a bookmark as a pointer to start the query in the tree. \ud83d\udca1 Use this: const docs = []; let resp = { next : true }; while ( resp && resp . next ) { resp = await client . query ( Q ( \"io.cozy.todos\" ). limitBy ( 200 ). offsetBookmark ( resp . bookmark ) ); docs . push (... resp . data ); } Views: performances \u00b6 In Cozy, we disabled by default the possibility to create views from applications. This is because we experienced severe performances issues as soon as several views were used: building the views is very slow. This is mainly because CouchDB itself is written in Erlang, while views are JavaScript UDF and are executed in isolated JavaScript query processes to serialize the map-reduce functions. The communication between thoses processes and CouchDB is done through stdio , which is synchronous and thus require to process one doc at a time. For more details, see this great blog post from a CouchDB contributor. See also the CouchDB benchmark we performed. As quoted from the CouchDB documentation : Views with the JavaScript query server are extremely slow to generate when there are a non-trivial number of documents to process. A 10 million document database took about 4 hours to do view generation Let alone the very slow indexing time, this also requires a lot of server CPU to build views. Hence, applications cannot create views to ensure the scalability of Cozy. \u2139\ufe0f Mango queries are directly interpreted in Erlang and therefore do not suffer from the same limitations. \u274c It is possible to express views in Erlang and thus circumvent this performance issues. However, this is completely forbidden in Cozy, because of the security: doing so requires to enable the Erlang query server that needs root access to the CouchDB server, as explained in the CouchDB documentation . This would break the isolation system and let open the possibilty to define adversary UDF functions. Views: pagination \u00b6 The CouchDB views does not implement the Mango queries bookmark system. However, it is still possible to paginate results efficiently by using a cursor . This method, described in the CouchDB documentation , combines the startkey and startkey_docid parameters. For each query, get the last returned document and extract the searched key as well as the _id to respectively set the next startkey and startkey_docid query parameters. See this cursor pagination example in cozy-client. Revisions \u00b6 CouchDB keeps for each document a list of its revision (or more exactly a tree with replication and conflicts). It\u2019s possible to ask to the cozy-stack the list of the old revisions of a document with [GET /db/{docid}?revs_info=true](http://docs.couchdb.org/en/stable/api/document/common.html#get--db-docid) . It works only if the document has not been deleted. For a deleted document, a trick is to query the changes feed to know the last revision of the document, and to recreate the document from this revision. With an old revision, it\u2019s possible to get the content of the document at this revision with GET /db/{docid}?rev={rev} if the database was not compacted. On CouchDB 3.x, compaction happen automatically on all databases from times to times. A purge operation consists to remove the tombstone for the deleted documents. It is a manual operation, triggered by a [POST /db/_purge](http://docs.couchdb.org/en/stable/api/database/misc.html) . Conflicts \u00b6 It is possible to create a conflict on CouchDB like it does for the replication by using new_edits: false , but it is not well documented to say the least. The more accurate description was in the old wiki, that no longer exists . Here is a copy of what it said: The replicator uses a special mode of _bulk_docs. The documents it writes to the destination database already have revision IDs that need to be preserved for the two databases to be in sync (otherwise it would not be possible to tell that the two represent the same revision.) To prevent the database from assigning them new revision IDs, a \u201cnew_edits\u201d:false property is added to the JSON request body. Note that this changes the interpretation of the _rev parameter in each document: rather than being the parent revision ID to be matched against, it\u2019s the existing revision ID that will be saved as-is into the database. And since it\u2019s important to retain revision history when adding to the database, each document body in this mode should have a _revisions property that lists its revision history; the format of this property is described on the HTTP document API. For example: curl -X POST -d '{\"new_edits\":false,\"docs\":[{\"_id\":\"person\",\"_rev\":\"2-3595405\",\"_revisions\":{\"start\":2,\"ids\":[\"3595405\",\"877727288\"]},\"name\":\"jim\"}]}' \"$OTHER_DB/_bulk_docs\" This command will replicate one of the revisions created above, into a separate database OTHER_DB . It will have the same revision ID as in DB , 2-3595405 , and it will be known to have a parent revision with ID 1-877727288 . (Even though OTHER_DB will not have the body of that revision, the history will help it detect conflicts in future replications.) As with _all_or_nothing, this mode can create conflicts; in fact, this is where the conflicts created by replication come from. In short, it\u2019s a PUT /doc/{id}?new_edits=false with _rev the new revision of the document, and _revisions the parents of this revision in the revisions tree of this document. Conflict example Here is an example of a CouchDB conflict. Let\u2019s assume the following document with the revision history [1-abc, 2-def] saved in database: { \"_id\" : \"foo\" , \"_rev\" : \"2-def\" , \"bar\" : \"tender\" , \"_revisions\" : { \"ids\" : [ \"def\" , \"abc\" ] } } The _revisions block is returned when passing revs=true to the query and gives all the revision ids, which the revision part after the dash. For instance, in 2-def , 2 is called the \u201cgeneration\u201d and def the \u201cid\u201d. We update the document with a POST /bulk_docs query, with the following content: { \"docs\" : [ { \"_id\" : \"foo\" , \"_rev\" : \"3-ghi\" , \"_revisions\" : { \"start\" : 3 , \"ids\" : [ \"ghi\" , \"xyz\" , \"abc\" ] }, \"bar\" : \"racuda\" } ], \"new_edits\" : false } This produces a conflict bewteen 2-def and 2-xyz : the former was first saved in database, but we forced the latter to be a new child of 1-abc . Hence, this document will have two revisions branches: 1-abc, 2-def and 1-abc, 2-xyz, 3-ghi . Sharing In the sharing protocol , we implement this behaviour as we follow the CouchDB replication model. However, we prevent CouchDB conflicts for files and directories: see this explanation CouchDB performances \u00b6 Here is a benchmark performed on a CouchDB 2.3, running on a Thinkpad T480, i7-8550U , 16 Go RAM with 256Go SSD. The document insertion is performed in bulk, by batch of 100K documents maximum. Each doc has the following structure: { \"_id\" : \"xxx\" , \"_rev\" : \"yyy\" , \"count1\" : x , \"count2\" : x } count1 is indexed by a Mango index and a JavaScript view, while count2 is indexed by an Erlang view. Both of those fields are incremented at each document insertion. Each query is paginated to retrieve 100 documents at a time. We measured the time taken for each query, to see variations depending on the database volumetry. To measure the mango and views build time, we performed a single query just after their creation. \u2139\ufe0f The X and Y axis are logarithmic. CouchDB performances \u2139\ufe0f The code used to perfom this benchmark is available on Github .", "title": "Advanced"}, {"location": "tutorials/data/advanced/#advanced-concepts", "text": "", "title": "Advanced concepts"}, {"location": "tutorials/data/advanced/#indexes-concepts", "text": "", "title": "Indexes: concepts"}, {"location": "tutorials/data/advanced/#but-why-though", "text": "In order to efficiently filter documents through selectors and sort them, it is important to correctly index data. An index is a way to organize documents in order to retrieve them faster. To give a simple and non-database comparison, a recipe book might have an index listing all the recipes by their name with their page number. If the reader is looking for a particular recipe, this index avoids him to scan the full book to find it. The principle is the same for databases index: we want to avoid scanning the whole database each time we are looking for specific data expressed by a selector: even though computers are way faster than humans to scan data, this task can be very time-consuming when dealing with thousands or millions of documents. In more formal terms, time complexity of a query run on a database with n documents will be O(n) without index, as it requires to scan all documents. In CouchDB, the indexes are actually B+ Trees , a structure derived from the B-Trees , that perform in O(log(n)) in average, which guarantees a very fast access time even in large datasets. From a practical point of view, B-trees, therefore, guarantee an access time of less than 10 ms even for extremely large datasets. \u2014Dr. Rudolf Bayer, inventor of the B-tree", "title": "But why, though?"}, {"location": "tutorials/data/advanced/#b-tree", "text": "CouchDB indexes are B+ Trees. It means that indexed fields, here keys , are organized as a tree, with the documents stored in the leafs nodes. So, finding a particular document means browsing the tree, from the root to the leaf. In each node, a key has two children: the left child has all its keys inferior to the parent, while the right child has all its keys superior to the parent. In the Figure below, borrowed from the CouchDB guide , you see that each node has three keys. In CouchDB implementation, a B+ Tree node can actually store more than 1600 keys. B+ Tree This design is very efficient for range queries: in the example above, a query looking for documents having an indexed field between 1 and 3 will browse the tree to find the first document position (with a key of 1) and then get the next two contiguous documents. \u2139\ufe0f CouchDB has an append-only design: it means that there is no in-place update. Each time a document is updated, its new version is appended to the database file, and the B+ Tree is updated to reflect the change. \u2139\ufe0f It is not necessary to master the B+ Tree logic to query data, but it is good to at least be aware of the main concepts to understand the indexing logic, especially when designing complex queries. \u2139\ufe0f When indexing several document fields in the same index, the key is actually an array of those fields, e.g. an index on [\"category\", \"created_at\"] would give keys such as [\"sport\", \"2019-01-01\"] . \u2139\ufe0f A key does not have to be unique. Actually, it is often useful to group document per key, e.g. a category key can return many document with the same key value, like sport , work , etc.", "title": "B+ Tree"}, {"location": "tutorials/data/advanced/#indexes-why-is-my-document-not-being-retrieved", "text": "At indexing time, CouchDB evaluates if a new document should be indexed by checking if its fields match an existing index. It means that all the indexed fields must exist in the document to index it. It can be problematic for queries that need to check if a particular field exists or not. For example, this query won\u2019t work: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : { $exists : false , }, }) . indexFields ([ \"category\" ]); Here, we want to get all the todos without a category field. However, those documents will never be indexed, precisely because the field is missing. Hence, think carefully about your data before hand and do not use queries with $exists: false whenever possible. If a field is missing, it might be better to add a null value so that your documents do not have any missing fields. If this is not possible for some reasons, here is another possible solution - yet not very efficient: \u26a0\ufe0f Not efficient workaround const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ _id : { $gt : null , }, category : { $exists : false , }, }) . indexFields ([ \"_id\" ]); Here, we force an index on the _id , which always exists in any CouchDB document, and ask all the documents with \"_id\": { \"$gt\": null } . The category is not indexed so the documents without this field will enter the index. This is not efficient as it implies that the \"category\": { \"$exists\": false } condition will be evaluated in memory by CouchDB for all the documents of the database, thus making a full index scan.", "title": "Indexes: why is my document not being retrieved?"}, {"location": "tutorials/data/advanced/#indexes-performances-and-design", "text": "When designing indexes on several fields, one should keep in mind that they are actually B+ Tree, as explained in this section . This can be helpful to design efficient queries and avoid performance traps. To illustrate this, let\u2019s assume you have declared this query, to get all the \u201cwork\u201d todos created in 2019: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ created_at : { $ge : \"2019-01-01\" , $lt : \"2020-01-01\" , }, category : \"work\" , }) . indexFields ([ \"created_at\" , \"category\" ]); \u26a0\ufe0f This query is actually sub-optimal. To understand this, let\u2019s represent some sample data: created_at category 2019-01-01 family 2019-01-01 sport 2019-01-01 work 2019-01-01 work 2019-01-02 work 2019-01-03 sport 2019-01-04 work \u2026 \u2026 2020-01-01 family This shows how the data is organized in the index: it is primarily sorted by created_at and then by category . First, the query is looking for all the todos starting from \"2019-01-01\" and before \"2020-01-01\" . It easily finds this range in the B+ Tree; but now it must also filter all the results to only keep the rows with category: work . And this cannot be done through the B+ Tree, because matching rows are not contiguous, as shown in green in the table: this means that CouchDB is forced to perform the category condition in memory, leading to bad performances. \ud83d\udca1 Hopefully, this example can be easily be solved by switching the index fields order: .indexFields([\"category\", \"created_at\"]) The data is now organized as follow: category created_at family 2019-01-01 ... ... sport 2019-01-01 ... ... work 2019-01-01 work 2019-01-01 work 2019-01-02 work 2019-01-03 work 2019-01-04 \u2026 \u2026 work 2020-01-01 Now, the very same query can be efficiently processed: the category: work is first evaluated in the B+ Tree, which return all the relevant rows, sorted by created_at . Then, the range is easily found now that all the rows are contiguous. \ud83d\udca1 The main takeaway here is: when dealing with a query with both equality and range, you must first index the equality field. If you are interested about this, you can learn more here . Even though it is SQL-oriented, it also applies for CouchDB as the B-Tree indexing logic is the same. \ud83d\udca1 When creating an index, carefully think about how your data will be organized and which query will need to perfom. The performances can dramatically vary depending on your design, with several orders of magnitude. \ud83d\udca1 The problematic and consequences of the not contiguous rows is further explain in the partial indexes section .", "title": "Indexes: performances and design"}, {"location": "tutorials/data/advanced/#partial-indexes", "text": "In CouchDB, a document is indexed only if its fields matches an existing index. As a consequence, it is not possible to perform efficient queries on non-existing fields. For instance, the query below does not work, because it searches for document without the category field, but the absence of this field will cause such documents to never be indexed, as previously explained here : const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : { $exists : false , }, }) . indexFields ([ \"category\" ]); In the same manner, queries implying non-contiguous rows in the B+ Tree are sub-optimal. Typically, queries with a non-egal operator, $ne : const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ title : \"Exercices\" , category : { $ne : \"sport\" , }, }) . indexFields ([ \"title\" , \"category\" ]); As the $ne operator cannot guarantee contiguous rows, it needs to scan all the index on documents with the \"title\": \"Exercices\" to find those that are not in the sport category . Partial indexes are a way to circumvent this issue. They allow to define a partial selector condition that will be evaluated at the indexing time, and will add the document in the index if it matches the condition. Thanks to this, it becomes possible to tell CouchDB at indexing time to exlude documents that do not match the condition, e.g. \"category\": { \"$exists\": false} or \"category\": { \"$ne\": \"sport\"} . Hence, the produced index will only include documents that already matched the partial filter selector, making it possible to query them, as this selector enforces contiguous rows or documents with missing fields. You can declare a partial index in cozy-client like this: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ title : \"Exercices\" , }) . partialIndex ({ category : { $ne : \"sport\" , }, }) . indexFields ([ \"title\" ]); partialIndex supports the same syntax than the where , so you can easily move inefficient selectors into partial indexes. Note in this example, it is no longer necessary to index the category field, as the field is now evaluated at indexing time, rather than during the query. Hence, a partial index is also useful to design less heavy indexes.", "title": "Partial indexes"}, {"location": "tutorials/data/advanced/#mango-pagination-performances", "text": "With mango queries, the recommanded method to paginate is through the bookmark parameter. However, one could also notice the skip parameter in the CouchDB API and be tempted to paginate with it. We detail here why you should never use skip to paginate and use bookmark instead. We explain it for exhaustiveness and to prevent developers to fall into this trap. This method consists of specifying a limit to the query, which is the maximum number of documents to return, and a skip parameter that is the number of documents returned so far. With cozy-client, its is expressed through limitBy and offset . \u26a0\ufe0f Do not use this: const docs = []; let resp = { next : true , data : [] }; while ( resp && resp . next ) { resp = await client . query ( Q ( \"io.cozy.todos\" ). limitBy ( 200 ). offset ( resp . data . length ) ); docs . push (... resp . data ); } This method is very bad for performances because it actually breaks the B+ Tree indexing logic: there is no way to efficiently skip a fixed number of data in such a tree, so skipping documents consists of normally running the query and then splitting the results starting from the skip number of documents. Thus, the performances quickly degrade when there are many documents to skip. On the contrary, the bookmark method is very efficient as it preserves the B+ Tree logic. One can see a bookmark as a pointer to start the query in the tree. \ud83d\udca1 Use this: const docs = []; let resp = { next : true }; while ( resp && resp . next ) { resp = await client . query ( Q ( \"io.cozy.todos\" ). limitBy ( 200 ). offsetBookmark ( resp . bookmark ) ); docs . push (... resp . data ); }", "title": "Mango pagination: performances"}, {"location": "tutorials/data/advanced/#views-performances", "text": "In Cozy, we disabled by default the possibility to create views from applications. This is because we experienced severe performances issues as soon as several views were used: building the views is very slow. This is mainly because CouchDB itself is written in Erlang, while views are JavaScript UDF and are executed in isolated JavaScript query processes to serialize the map-reduce functions. The communication between thoses processes and CouchDB is done through stdio , which is synchronous and thus require to process one doc at a time. For more details, see this great blog post from a CouchDB contributor. See also the CouchDB benchmark we performed. As quoted from the CouchDB documentation : Views with the JavaScript query server are extremely slow to generate when there are a non-trivial number of documents to process. A 10 million document database took about 4 hours to do view generation Let alone the very slow indexing time, this also requires a lot of server CPU to build views. Hence, applications cannot create views to ensure the scalability of Cozy. \u2139\ufe0f Mango queries are directly interpreted in Erlang and therefore do not suffer from the same limitations. \u274c It is possible to express views in Erlang and thus circumvent this performance issues. However, this is completely forbidden in Cozy, because of the security: doing so requires to enable the Erlang query server that needs root access to the CouchDB server, as explained in the CouchDB documentation . This would break the isolation system and let open the possibilty to define adversary UDF functions.", "title": "Views: performances"}, {"location": "tutorials/data/advanced/#views-pagination", "text": "The CouchDB views does not implement the Mango queries bookmark system. However, it is still possible to paginate results efficiently by using a cursor . This method, described in the CouchDB documentation , combines the startkey and startkey_docid parameters. For each query, get the last returned document and extract the searched key as well as the _id to respectively set the next startkey and startkey_docid query parameters. See this cursor pagination example in cozy-client.", "title": "Views: pagination"}, {"location": "tutorials/data/advanced/#revisions", "text": "CouchDB keeps for each document a list of its revision (or more exactly a tree with replication and conflicts). It\u2019s possible to ask to the cozy-stack the list of the old revisions of a document with [GET /db/{docid}?revs_info=true](http://docs.couchdb.org/en/stable/api/document/common.html#get--db-docid) . It works only if the document has not been deleted. For a deleted document, a trick is to query the changes feed to know the last revision of the document, and to recreate the document from this revision. With an old revision, it\u2019s possible to get the content of the document at this revision with GET /db/{docid}?rev={rev} if the database was not compacted. On CouchDB 3.x, compaction happen automatically on all databases from times to times. A purge operation consists to remove the tombstone for the deleted documents. It is a manual operation, triggered by a [POST /db/_purge](http://docs.couchdb.org/en/stable/api/database/misc.html) .", "title": "Revisions"}, {"location": "tutorials/data/advanced/#conflicts", "text": "It is possible to create a conflict on CouchDB like it does for the replication by using new_edits: false , but it is not well documented to say the least. The more accurate description was in the old wiki, that no longer exists . Here is a copy of what it said: The replicator uses a special mode of _bulk_docs. The documents it writes to the destination database already have revision IDs that need to be preserved for the two databases to be in sync (otherwise it would not be possible to tell that the two represent the same revision.) To prevent the database from assigning them new revision IDs, a \u201cnew_edits\u201d:false property is added to the JSON request body. Note that this changes the interpretation of the _rev parameter in each document: rather than being the parent revision ID to be matched against, it\u2019s the existing revision ID that will be saved as-is into the database. And since it\u2019s important to retain revision history when adding to the database, each document body in this mode should have a _revisions property that lists its revision history; the format of this property is described on the HTTP document API. For example: curl -X POST -d '{\"new_edits\":false,\"docs\":[{\"_id\":\"person\",\"_rev\":\"2-3595405\",\"_revisions\":{\"start\":2,\"ids\":[\"3595405\",\"877727288\"]},\"name\":\"jim\"}]}' \"$OTHER_DB/_bulk_docs\" This command will replicate one of the revisions created above, into a separate database OTHER_DB . It will have the same revision ID as in DB , 2-3595405 , and it will be known to have a parent revision with ID 1-877727288 . (Even though OTHER_DB will not have the body of that revision, the history will help it detect conflicts in future replications.) As with _all_or_nothing, this mode can create conflicts; in fact, this is where the conflicts created by replication come from. In short, it\u2019s a PUT /doc/{id}?new_edits=false with _rev the new revision of the document, and _revisions the parents of this revision in the revisions tree of this document. Conflict example Here is an example of a CouchDB conflict. Let\u2019s assume the following document with the revision history [1-abc, 2-def] saved in database: { \"_id\" : \"foo\" , \"_rev\" : \"2-def\" , \"bar\" : \"tender\" , \"_revisions\" : { \"ids\" : [ \"def\" , \"abc\" ] } } The _revisions block is returned when passing revs=true to the query and gives all the revision ids, which the revision part after the dash. For instance, in 2-def , 2 is called the \u201cgeneration\u201d and def the \u201cid\u201d. We update the document with a POST /bulk_docs query, with the following content: { \"docs\" : [ { \"_id\" : \"foo\" , \"_rev\" : \"3-ghi\" , \"_revisions\" : { \"start\" : 3 , \"ids\" : [ \"ghi\" , \"xyz\" , \"abc\" ] }, \"bar\" : \"racuda\" } ], \"new_edits\" : false } This produces a conflict bewteen 2-def and 2-xyz : the former was first saved in database, but we forced the latter to be a new child of 1-abc . Hence, this document will have two revisions branches: 1-abc, 2-def and 1-abc, 2-xyz, 3-ghi . Sharing In the sharing protocol , we implement this behaviour as we follow the CouchDB replication model. However, we prevent CouchDB conflicts for files and directories: see this explanation", "title": "Conflicts"}, {"location": "tutorials/data/advanced/#couchdb-performances", "text": "Here is a benchmark performed on a CouchDB 2.3, running on a Thinkpad T480, i7-8550U , 16 Go RAM with 256Go SSD. The document insertion is performed in bulk, by batch of 100K documents maximum. Each doc has the following structure: { \"_id\" : \"xxx\" , \"_rev\" : \"yyy\" , \"count1\" : x , \"count2\" : x } count1 is indexed by a Mango index and a JavaScript view, while count2 is indexed by an Erlang view. Both of those fields are incremented at each document insertion. Each query is paginated to retrieve 100 documents at a time. We measured the time taken for each query, to see variations depending on the database volumetry. To measure the mango and views build time, we performed a single query just after their creation. \u2139\ufe0f The X and Y axis are logarithmic. CouchDB performances \u2139\ufe0f The code used to perfom this benchmark is available on Github .", "title": "CouchDB performances"}, {"location": "tutorials/data/doctypes/", "text": "DocTypes overview \u00b6 In Cozy, data is represented as CouchDB documents . Each document follows a specific structure, called a DocType, stored in its dedicated database. You can find here a list of all the DocTypes available in Cozy. Cozy is an open platform: if you need a DocType that does not exist yet, you can submit a new one by making a Pull Request in the Github repository .", "title": "DocTypes"}, {"location": "tutorials/data/doctypes/#doctypes-overview", "text": "In Cozy, data is represented as CouchDB documents . Each document follows a specific structure, called a DocType, stored in its dedicated database. You can find here a list of all the DocTypes available in Cozy. Cozy is an open platform: if you need a DocType that does not exist yet, you can submit a new one by making a Pull Request in the Github repository .", "title": "DocTypes overview"}, {"location": "tutorials/data/pouchdb/", "text": "PouchDB - Offline \u00b6 PouchDB is a JavaScript implementation of CouchDB. It is particulary well suited for client environments such as browsers or mobile. \u2139\ufe0f In Cozy, PouchDB is used in the desktop client and in mobile apps to synchronize data with the CouchDB server. Having a local database enables offline support and improves performances: the client can directly query local data to avoid network latency or unavailability. While it is meant to mimic most of the CouchDB API, there are specificities that are good to know when working with PouchDB. The findings below were obtained while working on sorting performance in Cozy Drive. For reference, the final PR can be seen here . Understanding what\u2019s going on \u00b6 Before diving into some of the quirks, it\u2019s important to understand some things when it comes to Pouchdb and especially Mango queries. First, you can add a plugin called pouchdb-debug and enable extra logs with PouchDB.debug.enable( \"pouchdb:find\" ); . This will add explanation about the queries you run in the console and it\u2019s very helpful to understand what\u2019s going on under the hood. You will realize that Pouchdb operates in 2 phases: first, it loads candidate documents in memory, and then it analyzes the candidates and only keeps the relevant ones. Long story short: the larger the number of candidates, the longer the operation will take. By default, all the documents in a database are candidates, but it is possible to have fewer candidates by using an index: by combining the query and the index, PouchDB can load only a subset of all the documents and may even skip the analyze phase if the index is really well suited to the query. A more detailed guide can be found here . About indexes \u00b6 Creating an index takes some time, but the first query will also take time \u2014 you are encouraged to warm up the indexes by firing a query that uses it before it is actually needed. CozyPouchLink provides a way to automatically fire those queries after replication. import fromPairs from 'lodash/fromPairs' import CozyClient , { Q } from 'cozy-client' import CozyStackClient from 'cozy-stack-client' import CozyPouchLink from 'cozy-pouch-link' const TRANSACTION_DOCTYPE = 'io.cozy.bank.operations' const makeWarmupQueryOptions = ( doctype , indexedFields ) => { return { definition : () => { const qdef = Q ( doctype ) . where ( fromPairs ( indexedFields . map ( fieldName => [ fieldName , { $gt : null }])) ) . indexFields ( indexedFields ) return qdef }, options : { as : ` ${ doctype } -by- ${ indexedFields . join ( '-' ) } ` } } } const pouchLink = new CozyPouchLink ({ doctypes : [ TRANSACTION_DOCTYPE ], doctypesReplicationOptions : { [ TRANSACTION_DOCTYPE ] : { warmupQueries : [ makeWarmupQueryOptions ( TRANSACTION_DOCTYPE , [ 'date' ]), makeWarmupQueryOptions ( TRANSACTION_DOCTYPE , [ 'account' ]), makeWarmupQueryOptions ( TRANSACTION_DOCTYPE , [ 'date' , 'account' ]) ] } }, initialSync : true }) const client = new CozyClient ({ links : [ pouchLink , new CozyStackClient ()] }) \u2139\ufe0f By default, Pouch will try to find the best index to use on your query. But for advanced queries, you generally want to force it with the use_index option to be sure it does not mess up. \u2139\ufe0f If the query and the index you force are not compatible, Pouch will emit an error and not run the query at all. \u2139\ufe0f If there is a change in the underlying documents, the index will be partially recalculated on the next query. Indexing more than one field \u00b6 Creating an index on several fields is not the same as creating multiple indexes on one field each. The effects of a single index on multiple fields is illustrated in the official docs and is important to understand. Furthermore, the order in which fields are indexed on a multi-index is significant, most notably when it comes to sorting. If you declare an index on the fields ['name', 'age'] , you should also sort them by ['name', 'age'] . Sorting them in a different order or using other fields will likely be done in memory and kill your performance. See this section for more details and understand how to efficiently design indexes. Avoiding full scan \u00b6 Filtering results with a selector on a field that has not been indexed is almost guaranteed to be done through a full scan and should be avoided. Since you can\u2019t have too many indexes, some filtering may have to be done in your own code \u2014 but if you can narrow down the results beforehand, that shouldn\u2019t be a problem. Note that even selectors on indexed field may end up being done in memory: see this section for more details and understand how to avoid memory selectors.", "title": "PouchDB"}, {"location": "tutorials/data/pouchdb/#pouchdb-offline", "text": "PouchDB is a JavaScript implementation of CouchDB. It is particulary well suited for client environments such as browsers or mobile. \u2139\ufe0f In Cozy, PouchDB is used in the desktop client and in mobile apps to synchronize data with the CouchDB server. Having a local database enables offline support and improves performances: the client can directly query local data to avoid network latency or unavailability. While it is meant to mimic most of the CouchDB API, there are specificities that are good to know when working with PouchDB. The findings below were obtained while working on sorting performance in Cozy Drive. For reference, the final PR can be seen here .", "title": "PouchDB - Offline"}, {"location": "tutorials/data/pouchdb/#understanding-whats-going-on", "text": "Before diving into some of the quirks, it\u2019s important to understand some things when it comes to Pouchdb and especially Mango queries. First, you can add a plugin called pouchdb-debug and enable extra logs with PouchDB.debug.enable( \"pouchdb:find\" ); . This will add explanation about the queries you run in the console and it\u2019s very helpful to understand what\u2019s going on under the hood. You will realize that Pouchdb operates in 2 phases: first, it loads candidate documents in memory, and then it analyzes the candidates and only keeps the relevant ones. Long story short: the larger the number of candidates, the longer the operation will take. By default, all the documents in a database are candidates, but it is possible to have fewer candidates by using an index: by combining the query and the index, PouchDB can load only a subset of all the documents and may even skip the analyze phase if the index is really well suited to the query. A more detailed guide can be found here .", "title": "Understanding what's going on"}, {"location": "tutorials/data/pouchdb/#about-indexes", "text": "Creating an index takes some time, but the first query will also take time \u2014 you are encouraged to warm up the indexes by firing a query that uses it before it is actually needed. CozyPouchLink provides a way to automatically fire those queries after replication. import fromPairs from 'lodash/fromPairs' import CozyClient , { Q } from 'cozy-client' import CozyStackClient from 'cozy-stack-client' import CozyPouchLink from 'cozy-pouch-link' const TRANSACTION_DOCTYPE = 'io.cozy.bank.operations' const makeWarmupQueryOptions = ( doctype , indexedFields ) => { return { definition : () => { const qdef = Q ( doctype ) . where ( fromPairs ( indexedFields . map ( fieldName => [ fieldName , { $gt : null }])) ) . indexFields ( indexedFields ) return qdef }, options : { as : ` ${ doctype } -by- ${ indexedFields . join ( '-' ) } ` } } } const pouchLink = new CozyPouchLink ({ doctypes : [ TRANSACTION_DOCTYPE ], doctypesReplicationOptions : { [ TRANSACTION_DOCTYPE ] : { warmupQueries : [ makeWarmupQueryOptions ( TRANSACTION_DOCTYPE , [ 'date' ]), makeWarmupQueryOptions ( TRANSACTION_DOCTYPE , [ 'account' ]), makeWarmupQueryOptions ( TRANSACTION_DOCTYPE , [ 'date' , 'account' ]) ] } }, initialSync : true }) const client = new CozyClient ({ links : [ pouchLink , new CozyStackClient ()] }) \u2139\ufe0f By default, Pouch will try to find the best index to use on your query. But for advanced queries, you generally want to force it with the use_index option to be sure it does not mess up. \u2139\ufe0f If the query and the index you force are not compatible, Pouch will emit an error and not run the query at all. \u2139\ufe0f If there is a change in the underlying documents, the index will be partially recalculated on the next query.", "title": "About indexes"}, {"location": "tutorials/data/pouchdb/#indexing-more-than-one-field", "text": "Creating an index on several fields is not the same as creating multiple indexes on one field each. The effects of a single index on multiple fields is illustrated in the official docs and is important to understand. Furthermore, the order in which fields are indexed on a multi-index is significant, most notably when it comes to sorting. If you declare an index on the fields ['name', 'age'] , you should also sort them by ['name', 'age'] . Sorting them in a different order or using other fields will likely be done in memory and kill your performance. See this section for more details and understand how to efficiently design indexes.", "title": "Indexing more than one field"}, {"location": "tutorials/data/pouchdb/#avoiding-full-scan", "text": "Filtering results with a selector on a field that has not been indexed is almost guaranteed to be done through a full scan and should be avoided. Since you can\u2019t have too many indexes, some filtering may have to be done in your own code \u2014 but if you can narrow down the results beforehand, that shouldn\u2019t be a problem. Note that even selectors on indexed field may end up being done in memory: see this section for more details and understand how to avoid memory selectors.", "title": "Avoiding full scan"}, {"location": "tutorials/data/qualification/", "text": "Document qualification \u00b6 A document can be qualified by adding attributes in its metadata meant to semantically describe the document. The objective is to maintain a transversal qualification structure between doctypes, so that files, banks, notes and so on could be qualified and retrieved. Currently, only the io.cozy.files doctype is supported. A qualification model is defined here : it is used to provide a set of qualifications based on documents labels, so developers don\u2019t have to worry about defining their own qualification and to ensure qualifications consistency. Note this is not an exhaustive nor closed model and contributions are welcomed. To know more about the qualification format and a description of the qualification attributes with examples, see the metadata documentation . Qualify with cozy-client \u00b6 This snippet shows how to qualify an health invoice with cozy-client : import { models } from 'cozy-client' const { Qualification } = models . document const { saveFileQualification } = models . file const qualification = Qualification . getByLabel ( 'health_invoice' ) await saveFileQualification ( client , file , qualification ) Then, then file metadata will include the following qualification: { \"metadata\" : { \"qualification\" : { \"label\" : \"health_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"health\" } } }", "title": "Qualification"}, {"location": "tutorials/data/qualification/#document-qualification", "text": "A document can be qualified by adding attributes in its metadata meant to semantically describe the document. The objective is to maintain a transversal qualification structure between doctypes, so that files, banks, notes and so on could be qualified and retrieved. Currently, only the io.cozy.files doctype is supported. A qualification model is defined here : it is used to provide a set of qualifications based on documents labels, so developers don\u2019t have to worry about defining their own qualification and to ensure qualifications consistency. Note this is not an exhaustive nor closed model and contributions are welcomed. To know more about the qualification format and a description of the qualification attributes with examples, see the metadata documentation .", "title": "Document qualification"}, {"location": "tutorials/data/qualification/#qualify-with-cozy-client", "text": "This snippet shows how to qualify an health invoice with cozy-client : import { models } from 'cozy-client' const { Qualification } = models . document const { saveFileQualification } = models . file const qualification = Qualification . getByLabel ( 'health_invoice' ) await saveFileQualification ( client , file , qualification ) Then, then file metadata will include the following qualification: { \"metadata\" : { \"qualification\" : { \"label\" : \"health_invoice\" , \"purpose\" : \"invoice\" , \"sourceCategory\" : \"health\" } } }", "title": "Qualify with cozy-client"}, {"location": "tutorials/data/queries/", "text": "Queries \u00b6 Basic concepts \u00b6 The database used in Cozy to store and manipulate data is CouchDB . This is a document-oriented NoSQL database, which means that data is represented as key-value JSON documents. A basic CouchDB document looks like this: { \"_id\" : \"6f978dbdc5e2424bfdec911f28005970\" , \"_rev\" : \"1-58b3a91cd89a6a2b607721f944bb6aeb\" , \"book\" : { \"name\" : \"The Greatest Book\" } } The _id and _rev fields are mandatory for each document and automatically handled by CouchDB, so the developers don\u2019t have to worry about them. _id is the unique identifier of the document while _rev is the version number, incremented for each update. See here to know more about the revision system. Any field can be specified in a CouchDB document (except for fields starting with a _ , that are reserved), as long as the JSON is valid and the type is supported , i.e. Array, Object, String, Number, Boolean. CouchDB comes with two query systems to retrieve documents: Mango queries , a declarative JSON syntax Views , to run arbitrary complex map-reduce functions In Cozy, we chose to support the simpler and more efficient Mango system by default, even though views are used in specific cases. \u2139\ufe0f CouchDB is an HTTP server. Therefore, all the requests made to the database must be expressed as HTTP requests. Any HTTP client can be used to directly query CouchDB ( curl , request , Insomnia to name a few). In Cozy, the back-end server, cozy-stack , communicates with CouchDB. \u2139\ufe0f In CouchDB, you organize data in DocTypes, a data structure meant to group documents together. All documents with the same DocType are stored in a dedicated database. Thus, each database has its own documents and indexes: when performing a query, one must indicates the target database; there is no cross-databases queries capability in CouchDB, altough there is a relationship query system to overcome this. See here for the DocTypes documentation. Mango queries \u00b6 The mango query system was introduced in CouchDB 2.0 and offers a declarative JSON syntax to perform queries on documents, inspired from MongoDB. There are several important concepts to grasp in order to efficiently use mango queries. Here, we give an overview of those concepts and detail common mistakes to avoid. Mango queries with cozy-client \u00b6 cozy-client is a JavaScript library developed by Cozy Cloud that helps to query data to the Cozy back-end, cozy-stack , without having to manually deal with authentication, index creation, pagination, etc. In the following, we provide cozy-client examples each time we introduce a new concept. If you are not familiar with it, this tutorial is a good starting place. However, if for some reasons you do not want to use cozy-client, it is possible to make queries on your own by directly requesting the cozy-stack data API . In cozy-client, each query is defined as a Query Definition . This API is helpful to easily chain Mango concepts (selectors, sorts, indexing, \u2026), as we will see in the following sections. In the following, we assume a DocType named io.cozy.todos describing Todo lists. Here is a basic example of a cozy-client query returning all the Todo lists in a Cozy: const docs = await client . queryAll ( Q ( \"io.cozy.todos\" )); In this example, the QueryDefinition defines the query to get all the documents stored in the Todos database, expressed through find(\"io.cozy.todos\") . Selectors \u00b6 To use the Mango query system, you define a selector , expressing criterias to filter the documents to return. Selectors with cozy-client \u00b6 With cozy-client, a selector is added to the query definition with the where method. It takes into input an object with the selector expression. For instance, this query means \u201cthe todos in \u2018sport\u2019 category AND a title \u2018Exercices\u2019\u201d: const queryDef = Q ( \"io.cozy.todos\" ). where ({ category : \"sport\" , title : \"Exercices\" , }); find targets the Todos database, while where filters the documents to return. \u2139\ufe0f When running this query, an index will automatically be created on the category and title fields. It is highly recommended to read the index section to avoid designing poorly efficient queries (see also the section on mango performances ). \u2139\ufe0f The $eq and $and operators are implicit by default. It allows to write concise queries. Here is the explicit version of the previous query: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ \"$and\" : [ { \"category\" : { \"$eq\" : \"sport\" }, { \"title\" : { \"$eq\" : \"Exercices\" } } ] }) Mango operators \u00b6 There are two kinds of mango operators: Condition operators ( $eq , $gt , $lt , \u2026) Combinaison operators ( $and , $or , $not , \u2026) For more details and examples of selectors, you can directly read the CouchDB documentation . Mango performances \u00b6 Depending on your queries and their complexity, performances can be dramatically impacted, by serveral orders of magnitude, especially for large databases, i.e. starting for thousands of documents. It is highly recommended to take some time to understand how to index fields and the related performances . Index fields \u00b6 In order to efficiently filter documents through selectors and sort them, it is important to correctly index data. An index is a way to organize documents in order to retrieve them faster. Most often, you will need to index fields to query data efficiently. Otherwise, the documents filtering will be processed by CouchDB through a full scan, i.e. fetching all the database documents and performing the selector in memory. This can be very time-consuming when the database grows. In some cases, it can even prevent the query to be run. Thus, when an index is required, any field involved in a selector should be indexed . \u2139\ufe0f It is not always necessary to index fields to filter data. For instance, let\u2019s assume you want all the folders inside a sub-folder, but not the trash (which is a special folder with a fixed _id ). You should index the type (to exclude files) and dir_id (to specifiy this specific sub-folder), but you should not index the _id (to exclude the trash): this can easily be done on the application level. Here, indexing _id would make the index grows unnecessarily and impact the database performances. \u26a0\ufe0f Maintaining a lot of indexes is costful for the database: you should think careful about your queries and re-use existing index when possible. \u26a0\ufe0f cozy-client automatically indexes fields declared in a where call. However, this currently only works for simple queries with implicit combinaison operators, i.e. where all the fields are declared at the first level of the object. For any query involving explicit operators, you can use the indexFields method, see below for an example. Here, we explain how you can index fields to efficiently query documents. If you are interested on why indexing is important and how your performances can dramatically vary, you can go to the advanced explanations here . With mango queries, it is required to index documents fields that are necessary to run the queries, either because they are involved in the selector or the sort. Index with cozy-client \u00b6 With cozy-client, you don\u2019t have to deal with the index creation: it is expressed through indexFields : const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : \"sport\" , }) . indexFields ([ \"category\" ]); Thanks to this, cozy-client automatically creates an index on category before running the query for the first time and explicity tell CouchDB to use it. \ud83d\udca1 In this example, the indexField method is not mandatory: cozy-client is smart enough to automatically index category as it is involved in the selector. However, this automatic indexing only works for simple queries, thus, it is encouraged to explicity declare which fields to index. \u26a0\ufe0f CouchDB evaluates if a new document should be indexed by checking if its fields match an existing index. It means that all the indexed fields must exist in the document to index it. It can be problematic for queries that needs to check if a particular field exists or not. We detail this behaviour and workarounds in the \u201cwhy is my document not retrieved\u201d section . \u2139\ufe0f If no index is used to run the query, the query response will include a warning: no matching index found, create an index to optimize query time . It means that your index is not properly defined, probably because some fields involved in the where selector are not indexed. Note that if you use a sortBy , you also need to index the fields involved, as explained in this section . Index update \u00b6 CouchDB updates the Mango indexes when the data is read, but not on writes. This implies that if one creates an index and inserts documents, the index will never be updated until a find query on these documents is performed. \u26a0\ufe0f This implies that a query performed after many writes can take a certain time to complete, as it will update the index before returning any result. Likewise, the first query after an index creation will include the index build. Hence, developers should keep this behaviour in mind when designing applications and typically might need to handle query latency. \u2139\ufe0f Starting from CouchDB 3.0.0, a background indexing is implemented. It aims to avoid this latency by forcing the index to update in background after writes. Index with several fields \u00b6 Here is how to declare a query asking for todos having a \u201cwork\u201d category and have been created since 1st January 2019: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ \"$and\" : [ { \"created_at\" : { \"$gt\" : \"2019-01-01\" }, { \"category\" : \"work\" } ] }) . indexFields ([ \"category\" , \"created_at\" ]) \u26a0\ufe0f The order in the indexFields array can be very important for performances, especially when there are both range and equality operators: you must always index the field involved in the equality operator first. This is further explained in this section . Sort data with Mango \u00b6 It is possible to express the order of the documents returned by a query, by using the sort array. The sort is always done on a document field, by ascending ( asc ) or descending ( desc ) order. It is possible to specify several fields to sort, by following this structure for each field: {\"fieldName\": \"asc\"|\"desc\"} For instance: [{\"category\": \"asc\"}, {\"created_at\": \"asc\"}] Here, the returned documents will be first sorted by category, and then by creation date. \u26a0\ufe0f It is not possible to mix the sort order on different fields, i.e. all the fields involved in the sort must be either asc , either desc but not a mix of both. See this section for more info about the sort order on data types. Sort with cozy-client \u00b6 With cozy-client, a sort is expressed through the sortBy method. It takes as argument an array containing the fields to sort and the direction. For instance: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : \"sport\" , }) . indexFields ([ \"category\" , \"created_at\" ]). sortBy ([ ({ category : \"asc\" }, { created_at : \"asc\" }) ]); \u26a0\ufe0f If the fields involved in the sortBy are not indexed, this will force CouchDB to make the sort in memory: this can be acceptable if the query returns few documents, but it is not efficient for large queries. \u26a0\ufe0f At least one of the sort fields must be included in the where selector. If you create an index on category and query it to sort on it, but with no where selector, the index won\u2019t be used. \u26a0\ufe0f If several fields are indexed, their order is important: the sort order must follow the indexed fields order. In this example, we index category and created_at in this order: by doing so, it is not possible to sort only on created_at . We would need to index created_at first to achieve this, but this is not recommended for performances, as explained in this section . See also the examples provided in the PouchDB documentation . \u26a0\ufe0f Be aware that cozy-client sort documents too after a query using sortBy but, for now, with a different sorting logic than couchDB. See this cozy-client issue for more informations Pagination \u00b6 When dealing with queries returning a lot of documents, e.g. thousands, it might be necessary to paginate the results to avoid huge network payloads and having to load everything in memory, both on the server and client sides. The pagination consists of splitting the results in \u201cpages\u201d: if a query matches 100.000 documents, one can paginate it, for example by actually running 1000 queries returning 100 documents each. By doing so, the server only keeps 100 documents in memory for each query, and the client can control the data flow, for example, by implementing a \u201cLoad more\u201d button that actually runs a paginated query and loads the 100 next documents. With mango queries, the recommended method to paginate is through the bookmark parameter, that works exactly as it name suggests: it consists of a string returned by CouchDB that corresponds to the page position in the index. Just like an actual bookmark is used to mark a particular page in a book. With cozy-client, we can use the offsetBookmark method to paginate: const docs = []; let resp = { next : true }; while ( resp && resp . next ) { resp = await client . query ( Q ( \"io.cozy.todos\" ). limitBy ( 200 ). offsetBookmark ( resp . bookmark ) ); docs . push (... resp . data ); } \u2139\ufe0f By default, cozy-client has a limit of 100 documents per query, you can calibrate it thanks to the limitBy method. \u2139\ufe0f There is a hard limit per query enforced in the cozy-stack to avoid memory leaks. Currently, this limit is set to 1000 . \u2139\ufe0f The next parameter provided in the query response is handled by cozy-client and is set to true when it detects that there are more pages to fetch. Get them all! \u00b6 When pagination is not required by the client, cozy-client offers the queryAll method: const docs = await client . queryAll ( Q ( \"io.cozy.todos\" )); Note that it will actually automatically paginate if the total number of documents to return is superior to the limit (100 by default): this avoids loading too many documents in memory on the server side. However, it is possible to overcome this pagination by passing limit: null : in this case, cozy-client will request the _all_docs endpoint and retrieve all the documents in one query. This endpoint is automatically created by CouchDB and is actually a view on the _id key. Thus, doing this will actually query the _all_docs endpoint and return all the documents in one request: const docs = await client . query ( Q ( \"io.cozy.todos\" ), { limit : null }); \u26a0\ufe0f When querying this endpoint, the response includes the design docs , which are the Mango indexes and views definitions. Those documents are automatically filtered for the paginated queries. \u26a0\ufe0f This method is faster than the pagination as it avoids to make several server requests. However, if there are many documents to return, _all_docs queries can take a lot of time to complete and even timeout. It also consumes server resources. Hence, you should be cautious when using this route. Sort in CouchDB \u00b6 When dealing with various types of data, the ascending sort order is the following: null booleans numbers strings: \u201ca\u201d < \u201cA\u201d < \u201daa\u201d < \u201cb\u201d \u2026 arrays objects See the CouchDB documentation for more details on the sort orders. \u2139\ufe0f The sort order is the same for Mango queries and views. Comparison of strings \u00b6 Comparison of strings is done using ICU which implements the Unicode Collation Algorithm, giving a dictionary sorting of keys. This can give surprising results if you were expecting ASCII ordering. Note that: All symbols sort before numbers and letters (even the \u201chigh\u201d symbols like tilde, 0x7e ) Differing sequences of letters are compared without regard to case, so a < aa but also A < aa and a < AA Identical sequences of letters are compared with regard to case, with lowercase before uppercase, so a < A . Views \u00b6 \u26a0\ufe0f In Cozy, we disabled by default the possibility to create views from applications. Consequently, cozy-client does not support view creation, because they are disabled for applications. See the view performances section to find out why. CouchDB views are another way to express queries in Cozy, used by the cozy-stack . It consists of creating map-reduce functions, where the map is used to qualify which documents should be indexed, and the optional reduce can be used to compute aggregate functions on them. Views are much more flexible than Mango queries, as the map is a user-defined function (UDF) that can be written in JavaScript. For example: function ( doc ) { if ( doc . category && doc . created_at ) { emit ( doc . category , doc . created_at ); } } A map function must always produce an emit , with the key and the value respectively in first and second argument. \u2139\ufe0f Behind the hoods, views are represented exactly like the Mango queries: both use B+ Tree , with values stored in the leafs. Query a view \u00b6 Just like Mango queries, views are particularly suited for equality and range queries. See the CouchDB documentation to know more about the API. To find a specific document, use the key parameter: key=\"sport\" To find a range, combine the startkey and endkey parameters: startkey=\"category0001\"&endkey=\"category0009\" \u2139\ufe0f Note these queries return the values associated to their keys, as expressed by the emit in the map function. If the whole document is required, one can emit a null value, e.g. emit(doc.category, null) in the view definition and pass a include_docs: true when querying the view. Usage example: references \u00b6 The flexibility of the views can be useful is some specific scenarios and are used in some use-cases in cozy-stack. Typically, the references system implemented for the io.cozy.files documents allows to link other documents to a file. For example, a file can be referenced by a photo album, a bank transaction, etc. A reference looks like this, here a file referenced by two photos albums: \"referenced_by\" : [ { \"type\" : \"io.cozy.photos.albums\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" }, { \"type\" : \"io.cozy.photos.albums\" , \"id\" : \"a7375980-cf29-0138-33fe-0c1645862fd7\" } ] This [n-n] relation is hard to express with a Mango query, so a view is defined: function ( doc ) { if ( isArray ( doc . referenced_by )) { for ( var i = 0 ; i < doc . referenced_by . length ; i ++ ) { emit ([ doc . referenced_by [ i ]. type , doc . referenced_by [ i ]. id ]); } } } Then, it is easy to get all the files referenced by a specific photo album: key=[\"io.cozy.photos.albums\", \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\"]", "title": "Queries"}, {"location": "tutorials/data/queries/#queries", "text": "", "title": "Queries"}, {"location": "tutorials/data/queries/#basic-concepts", "text": "The database used in Cozy to store and manipulate data is CouchDB . This is a document-oriented NoSQL database, which means that data is represented as key-value JSON documents. A basic CouchDB document looks like this: { \"_id\" : \"6f978dbdc5e2424bfdec911f28005970\" , \"_rev\" : \"1-58b3a91cd89a6a2b607721f944bb6aeb\" , \"book\" : { \"name\" : \"The Greatest Book\" } } The _id and _rev fields are mandatory for each document and automatically handled by CouchDB, so the developers don\u2019t have to worry about them. _id is the unique identifier of the document while _rev is the version number, incremented for each update. See here to know more about the revision system. Any field can be specified in a CouchDB document (except for fields starting with a _ , that are reserved), as long as the JSON is valid and the type is supported , i.e. Array, Object, String, Number, Boolean. CouchDB comes with two query systems to retrieve documents: Mango queries , a declarative JSON syntax Views , to run arbitrary complex map-reduce functions In Cozy, we chose to support the simpler and more efficient Mango system by default, even though views are used in specific cases. \u2139\ufe0f CouchDB is an HTTP server. Therefore, all the requests made to the database must be expressed as HTTP requests. Any HTTP client can be used to directly query CouchDB ( curl , request , Insomnia to name a few). In Cozy, the back-end server, cozy-stack , communicates with CouchDB. \u2139\ufe0f In CouchDB, you organize data in DocTypes, a data structure meant to group documents together. All documents with the same DocType are stored in a dedicated database. Thus, each database has its own documents and indexes: when performing a query, one must indicates the target database; there is no cross-databases queries capability in CouchDB, altough there is a relationship query system to overcome this. See here for the DocTypes documentation.", "title": "Basic concepts"}, {"location": "tutorials/data/queries/#mango-queries", "text": "The mango query system was introduced in CouchDB 2.0 and offers a declarative JSON syntax to perform queries on documents, inspired from MongoDB. There are several important concepts to grasp in order to efficiently use mango queries. Here, we give an overview of those concepts and detail common mistakes to avoid.", "title": "Mango queries"}, {"location": "tutorials/data/queries/#mango-queries-with-cozy-client", "text": "cozy-client is a JavaScript library developed by Cozy Cloud that helps to query data to the Cozy back-end, cozy-stack , without having to manually deal with authentication, index creation, pagination, etc. In the following, we provide cozy-client examples each time we introduce a new concept. If you are not familiar with it, this tutorial is a good starting place. However, if for some reasons you do not want to use cozy-client, it is possible to make queries on your own by directly requesting the cozy-stack data API . In cozy-client, each query is defined as a Query Definition . This API is helpful to easily chain Mango concepts (selectors, sorts, indexing, \u2026), as we will see in the following sections. In the following, we assume a DocType named io.cozy.todos describing Todo lists. Here is a basic example of a cozy-client query returning all the Todo lists in a Cozy: const docs = await client . queryAll ( Q ( \"io.cozy.todos\" )); In this example, the QueryDefinition defines the query to get all the documents stored in the Todos database, expressed through find(\"io.cozy.todos\") .", "title": "Mango queries with cozy-client"}, {"location": "tutorials/data/queries/#selectors", "text": "To use the Mango query system, you define a selector , expressing criterias to filter the documents to return.", "title": "Selectors"}, {"location": "tutorials/data/queries/#selectors-with-cozy-client", "text": "With cozy-client, a selector is added to the query definition with the where method. It takes into input an object with the selector expression. For instance, this query means \u201cthe todos in \u2018sport\u2019 category AND a title \u2018Exercices\u2019\u201d: const queryDef = Q ( \"io.cozy.todos\" ). where ({ category : \"sport\" , title : \"Exercices\" , }); find targets the Todos database, while where filters the documents to return. \u2139\ufe0f When running this query, an index will automatically be created on the category and title fields. It is highly recommended to read the index section to avoid designing poorly efficient queries (see also the section on mango performances ). \u2139\ufe0f The $eq and $and operators are implicit by default. It allows to write concise queries. Here is the explicit version of the previous query: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ \"$and\" : [ { \"category\" : { \"$eq\" : \"sport\" }, { \"title\" : { \"$eq\" : \"Exercices\" } } ] })", "title": "Selectors with cozy-client"}, {"location": "tutorials/data/queries/#mango-operators", "text": "There are two kinds of mango operators: Condition operators ( $eq , $gt , $lt , \u2026) Combinaison operators ( $and , $or , $not , \u2026) For more details and examples of selectors, you can directly read the CouchDB documentation .", "title": "Mango operators"}, {"location": "tutorials/data/queries/#mango-performances", "text": "Depending on your queries and their complexity, performances can be dramatically impacted, by serveral orders of magnitude, especially for large databases, i.e. starting for thousands of documents. It is highly recommended to take some time to understand how to index fields and the related performances .", "title": "Mango performances"}, {"location": "tutorials/data/queries/#index-fields", "text": "In order to efficiently filter documents through selectors and sort them, it is important to correctly index data. An index is a way to organize documents in order to retrieve them faster. Most often, you will need to index fields to query data efficiently. Otherwise, the documents filtering will be processed by CouchDB through a full scan, i.e. fetching all the database documents and performing the selector in memory. This can be very time-consuming when the database grows. In some cases, it can even prevent the query to be run. Thus, when an index is required, any field involved in a selector should be indexed . \u2139\ufe0f It is not always necessary to index fields to filter data. For instance, let\u2019s assume you want all the folders inside a sub-folder, but not the trash (which is a special folder with a fixed _id ). You should index the type (to exclude files) and dir_id (to specifiy this specific sub-folder), but you should not index the _id (to exclude the trash): this can easily be done on the application level. Here, indexing _id would make the index grows unnecessarily and impact the database performances. \u26a0\ufe0f Maintaining a lot of indexes is costful for the database: you should think careful about your queries and re-use existing index when possible. \u26a0\ufe0f cozy-client automatically indexes fields declared in a where call. However, this currently only works for simple queries with implicit combinaison operators, i.e. where all the fields are declared at the first level of the object. For any query involving explicit operators, you can use the indexFields method, see below for an example. Here, we explain how you can index fields to efficiently query documents. If you are interested on why indexing is important and how your performances can dramatically vary, you can go to the advanced explanations here . With mango queries, it is required to index documents fields that are necessary to run the queries, either because they are involved in the selector or the sort.", "title": "Index fields"}, {"location": "tutorials/data/queries/#index-with-cozy-client", "text": "With cozy-client, you don\u2019t have to deal with the index creation: it is expressed through indexFields : const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : \"sport\" , }) . indexFields ([ \"category\" ]); Thanks to this, cozy-client automatically creates an index on category before running the query for the first time and explicity tell CouchDB to use it. \ud83d\udca1 In this example, the indexField method is not mandatory: cozy-client is smart enough to automatically index category as it is involved in the selector. However, this automatic indexing only works for simple queries, thus, it is encouraged to explicity declare which fields to index. \u26a0\ufe0f CouchDB evaluates if a new document should be indexed by checking if its fields match an existing index. It means that all the indexed fields must exist in the document to index it. It can be problematic for queries that needs to check if a particular field exists or not. We detail this behaviour and workarounds in the \u201cwhy is my document not retrieved\u201d section . \u2139\ufe0f If no index is used to run the query, the query response will include a warning: no matching index found, create an index to optimize query time . It means that your index is not properly defined, probably because some fields involved in the where selector are not indexed. Note that if you use a sortBy , you also need to index the fields involved, as explained in this section .", "title": "Index with cozy-client"}, {"location": "tutorials/data/queries/#index-update", "text": "CouchDB updates the Mango indexes when the data is read, but not on writes. This implies that if one creates an index and inserts documents, the index will never be updated until a find query on these documents is performed. \u26a0\ufe0f This implies that a query performed after many writes can take a certain time to complete, as it will update the index before returning any result. Likewise, the first query after an index creation will include the index build. Hence, developers should keep this behaviour in mind when designing applications and typically might need to handle query latency. \u2139\ufe0f Starting from CouchDB 3.0.0, a background indexing is implemented. It aims to avoid this latency by forcing the index to update in background after writes.", "title": "Index update"}, {"location": "tutorials/data/queries/#index-with-several-fields", "text": "Here is how to declare a query asking for todos having a \u201cwork\u201d category and have been created since 1st January 2019: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ \"$and\" : [ { \"created_at\" : { \"$gt\" : \"2019-01-01\" }, { \"category\" : \"work\" } ] }) . indexFields ([ \"category\" , \"created_at\" ]) \u26a0\ufe0f The order in the indexFields array can be very important for performances, especially when there are both range and equality operators: you must always index the field involved in the equality operator first. This is further explained in this section .", "title": "Index with several fields"}, {"location": "tutorials/data/queries/#sort-data-with-mango", "text": "It is possible to express the order of the documents returned by a query, by using the sort array. The sort is always done on a document field, by ascending ( asc ) or descending ( desc ) order. It is possible to specify several fields to sort, by following this structure for each field: {\"fieldName\": \"asc\"|\"desc\"} For instance: [{\"category\": \"asc\"}, {\"created_at\": \"asc\"}] Here, the returned documents will be first sorted by category, and then by creation date. \u26a0\ufe0f It is not possible to mix the sort order on different fields, i.e. all the fields involved in the sort must be either asc , either desc but not a mix of both. See this section for more info about the sort order on data types.", "title": "Sort data with Mango"}, {"location": "tutorials/data/queries/#sort-with-cozy-client", "text": "With cozy-client, a sort is expressed through the sortBy method. It takes as argument an array containing the fields to sort and the direction. For instance: const queryDef = client . find ( \"io.cozy.todos\" ) . where ({ category : \"sport\" , }) . indexFields ([ \"category\" , \"created_at\" ]). sortBy ([ ({ category : \"asc\" }, { created_at : \"asc\" }) ]); \u26a0\ufe0f If the fields involved in the sortBy are not indexed, this will force CouchDB to make the sort in memory: this can be acceptable if the query returns few documents, but it is not efficient for large queries. \u26a0\ufe0f At least one of the sort fields must be included in the where selector. If you create an index on category and query it to sort on it, but with no where selector, the index won\u2019t be used. \u26a0\ufe0f If several fields are indexed, their order is important: the sort order must follow the indexed fields order. In this example, we index category and created_at in this order: by doing so, it is not possible to sort only on created_at . We would need to index created_at first to achieve this, but this is not recommended for performances, as explained in this section . See also the examples provided in the PouchDB documentation . \u26a0\ufe0f Be aware that cozy-client sort documents too after a query using sortBy but, for now, with a different sorting logic than couchDB. See this cozy-client issue for more informations", "title": "Sort with cozy-client"}, {"location": "tutorials/data/queries/#pagination", "text": "When dealing with queries returning a lot of documents, e.g. thousands, it might be necessary to paginate the results to avoid huge network payloads and having to load everything in memory, both on the server and client sides. The pagination consists of splitting the results in \u201cpages\u201d: if a query matches 100.000 documents, one can paginate it, for example by actually running 1000 queries returning 100 documents each. By doing so, the server only keeps 100 documents in memory for each query, and the client can control the data flow, for example, by implementing a \u201cLoad more\u201d button that actually runs a paginated query and loads the 100 next documents. With mango queries, the recommended method to paginate is through the bookmark parameter, that works exactly as it name suggests: it consists of a string returned by CouchDB that corresponds to the page position in the index. Just like an actual bookmark is used to mark a particular page in a book. With cozy-client, we can use the offsetBookmark method to paginate: const docs = []; let resp = { next : true }; while ( resp && resp . next ) { resp = await client . query ( Q ( \"io.cozy.todos\" ). limitBy ( 200 ). offsetBookmark ( resp . bookmark ) ); docs . push (... resp . data ); } \u2139\ufe0f By default, cozy-client has a limit of 100 documents per query, you can calibrate it thanks to the limitBy method. \u2139\ufe0f There is a hard limit per query enforced in the cozy-stack to avoid memory leaks. Currently, this limit is set to 1000 . \u2139\ufe0f The next parameter provided in the query response is handled by cozy-client and is set to true when it detects that there are more pages to fetch.", "title": "Pagination"}, {"location": "tutorials/data/queries/#get-them-all", "text": "When pagination is not required by the client, cozy-client offers the queryAll method: const docs = await client . queryAll ( Q ( \"io.cozy.todos\" )); Note that it will actually automatically paginate if the total number of documents to return is superior to the limit (100 by default): this avoids loading too many documents in memory on the server side. However, it is possible to overcome this pagination by passing limit: null : in this case, cozy-client will request the _all_docs endpoint and retrieve all the documents in one query. This endpoint is automatically created by CouchDB and is actually a view on the _id key. Thus, doing this will actually query the _all_docs endpoint and return all the documents in one request: const docs = await client . query ( Q ( \"io.cozy.todos\" ), { limit : null }); \u26a0\ufe0f When querying this endpoint, the response includes the design docs , which are the Mango indexes and views definitions. Those documents are automatically filtered for the paginated queries. \u26a0\ufe0f This method is faster than the pagination as it avoids to make several server requests. However, if there are many documents to return, _all_docs queries can take a lot of time to complete and even timeout. It also consumes server resources. Hence, you should be cautious when using this route.", "title": "Get them all!"}, {"location": "tutorials/data/queries/#sort-in-couchdb", "text": "When dealing with various types of data, the ascending sort order is the following: null booleans numbers strings: \u201ca\u201d < \u201cA\u201d < \u201daa\u201d < \u201cb\u201d \u2026 arrays objects See the CouchDB documentation for more details on the sort orders. \u2139\ufe0f The sort order is the same for Mango queries and views.", "title": "Sort in CouchDB"}, {"location": "tutorials/data/queries/#comparison-of-strings", "text": "Comparison of strings is done using ICU which implements the Unicode Collation Algorithm, giving a dictionary sorting of keys. This can give surprising results if you were expecting ASCII ordering. Note that: All symbols sort before numbers and letters (even the \u201chigh\u201d symbols like tilde, 0x7e ) Differing sequences of letters are compared without regard to case, so a < aa but also A < aa and a < AA Identical sequences of letters are compared with regard to case, with lowercase before uppercase, so a < A .", "title": "Comparison of strings"}, {"location": "tutorials/data/queries/#views", "text": "\u26a0\ufe0f In Cozy, we disabled by default the possibility to create views from applications. Consequently, cozy-client does not support view creation, because they are disabled for applications. See the view performances section to find out why. CouchDB views are another way to express queries in Cozy, used by the cozy-stack . It consists of creating map-reduce functions, where the map is used to qualify which documents should be indexed, and the optional reduce can be used to compute aggregate functions on them. Views are much more flexible than Mango queries, as the map is a user-defined function (UDF) that can be written in JavaScript. For example: function ( doc ) { if ( doc . category && doc . created_at ) { emit ( doc . category , doc . created_at ); } } A map function must always produce an emit , with the key and the value respectively in first and second argument. \u2139\ufe0f Behind the hoods, views are represented exactly like the Mango queries: both use B+ Tree , with values stored in the leafs.", "title": "Views"}, {"location": "tutorials/data/queries/#query-a-view", "text": "Just like Mango queries, views are particularly suited for equality and range queries. See the CouchDB documentation to know more about the API. To find a specific document, use the key parameter: key=\"sport\" To find a range, combine the startkey and endkey parameters: startkey=\"category0001\"&endkey=\"category0009\" \u2139\ufe0f Note these queries return the values associated to their keys, as expressed by the emit in the map function. If the whole document is required, one can emit a null value, e.g. emit(doc.category, null) in the view definition and pass a include_docs: true when querying the view.", "title": "Query a view"}, {"location": "tutorials/data/queries/#usage-example-references", "text": "The flexibility of the views can be useful is some specific scenarios and are used in some use-cases in cozy-stack. Typically, the references system implemented for the io.cozy.files documents allows to link other documents to a file. For example, a file can be referenced by a photo album, a bank transaction, etc. A reference looks like this, here a file referenced by two photos albums: \"referenced_by\" : [ { \"type\" : \"io.cozy.photos.albums\" , \"id\" : \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\" }, { \"type\" : \"io.cozy.photos.albums\" , \"id\" : \"a7375980-cf29-0138-33fe-0c1645862fd7\" } ] This [n-n] relation is hard to express with a Mango query, so a view is defined: function ( doc ) { if ( isArray ( doc . referenced_by )) { for ( var i = 0 ; i < doc . referenced_by . length ; i ++ ) { emit ([ doc . referenced_by [ i ]. type , doc . referenced_by [ i ]. id ]); } } } Then, it is easy to get all the files referenced by a specific photo album: key=[\"io.cozy.photos.albums\", \"94375086-e2e2-11e6-81b9-5bc0b9dd4aa4\"]", "title": "Usage example: references"}, {"location": "tutorials/konnector/", "text": "A connector (also known as konnector ) is a script that imports data from another web service and put those data into your cozy. Each connector is an independent application, managed by the Cozy Home application. To protect your data, each connector runs inside a container in order to sandbox all their interactions with your data. \u26a0\ufe0f For historical reasons, in the Cozy codebase, a cozy connector is named konnector, please follow this convention if modifying an existing application. What will you need to start ? Node (20), follow the link to nodejs doc for proper installation. When it\u2019s done, you can check your version with node --version in your shell. Yarn , again follow the Yarn doc for proper install. Check the version with yarn --version in your shell. In this tutorial you will learn how to: Create the basic structure for your connector Scrape data from the service Save data to your Cozy Package your connector and send it to the store If you want to go further: Learn how konnectors are run by the Cozy stack Add Two Factor Authentication to your connector Developing an OAuth connector Use a browser simulation to request the website ENV vars injected by the cozy-stack when running a konnector Going further", "title": "Introduction"}, {"location": "tutorials/konnector/2fa/", "text": "You have successfully developped your connector but you realize that some accounts need two factor authentication (2FA) to work. Here is how you can add this to your connector 2FA detection \u00b6 Every target website being different, you will have to develop it yourself. Some websites return a specific url, some others display a special html content. Take a look at the github connector for real life example. Home Automatic Successful Login deactivation \u00b6 By default, the \u201cHome\u201d application will suppose the connector\u2019s login is a success after 8s, which is bad when your connector needs to wait for the user to send his code. For this, call : await this . deactivateAutoSuccessfulLogin () where this is your connector instance. And when the 2FA process is finished, call : await this . notifySuccessfulLogin () To notify the \u201cHome\u201d application that the login process is a success. Request a 2FA code from the user \u00b6 const code = await this . waitForTwoFaCode () Will display this popup in \u201cHome\u201d application and return the 2FA code when ready. It will handle error messages on timeout and won\u2019t request a 2FA code if the connector is run in background and throw the USER_ACTION_NEEDED.TWOFA_EXPIRED error instead, which will automatically display an appropriate message in the \u201cHome\u201d application. You can get more information in the documentation Please take a look espacially at the type option wich allows the connector to specify which type of 2FA code is expected (sms or email at the moment). When you get your 2FA code, send it to the target website the way it wants. What is the point of handling 2FA code if my connector asks it every time it is run ? \u00b6 Most of the time, a website will request a 2FA code one time and keep you logged in with the cookie session for a long time. Your connector will have to maintain a session between each run. For this, you have the CookieKonnector which does most of the work. Sadly, it is possible that a webservice does not allow you to keep a session long enough between each run, and this is the only case where the connector must be run by the user manually each time. Did you check if the targeted service offers an api ? Technical details \u00b6 Some connectors using this feature: Amazon , Github", "title": "2fa"}, {"location": "tutorials/konnector/2fa/#2fa-detection", "text": "Every target website being different, you will have to develop it yourself. Some websites return a specific url, some others display a special html content. Take a look at the github connector for real life example.", "title": "2FA detection"}, {"location": "tutorials/konnector/2fa/#home-automatic-successful-login-deactivation", "text": "By default, the \u201cHome\u201d application will suppose the connector\u2019s login is a success after 8s, which is bad when your connector needs to wait for the user to send his code. For this, call : await this . deactivateAutoSuccessfulLogin () where this is your connector instance. And when the 2FA process is finished, call : await this . notifySuccessfulLogin () To notify the \u201cHome\u201d application that the login process is a success.", "title": "Home Automatic Successful Login deactivation"}, {"location": "tutorials/konnector/2fa/#request-a-2fa-code-from-the-user", "text": "const code = await this . waitForTwoFaCode () Will display this popup in \u201cHome\u201d application and return the 2FA code when ready. It will handle error messages on timeout and won\u2019t request a 2FA code if the connector is run in background and throw the USER_ACTION_NEEDED.TWOFA_EXPIRED error instead, which will automatically display an appropriate message in the \u201cHome\u201d application. You can get more information in the documentation Please take a look espacially at the type option wich allows the connector to specify which type of 2FA code is expected (sms or email at the moment). When you get your 2FA code, send it to the target website the way it wants.", "title": "Request a 2FA code from the user"}, {"location": "tutorials/konnector/2fa/#what-is-the-point-of-handling-2fa-code-if-my-connector-asks-it-every-time-it-is-run", "text": "Most of the time, a website will request a 2FA code one time and keep you logged in with the cookie session for a long time. Your connector will have to maintain a session between each run. For this, you have the CookieKonnector which does most of the work. Sadly, it is possible that a webservice does not allow you to keep a session long enough between each run, and this is the only case where the connector must be run by the user manually each time. Did you check if the targeted service offers an api ?", "title": "What is the point of handling 2FA code if my connector asks it every time it is run ?"}, {"location": "tutorials/konnector/2fa/#technical-details", "text": "Some connectors using this feature: Amazon , Github", "title": "Technical details"}, {"location": "tutorials/konnector/cozy-browser/", "text": "For some websites, a lot of computation is needed to have a correct authentication and this computation is done in javascript. It is possible to do some reverse engineering but there is another solution: running a browser simulation in your connector. Zombie \u00b6 We chose a specific JS browser implementation which is zombie . It is a wrapper around jsdom to make it easier for scraping. Initialisation \u00b6 Add the zombie npm package to your connector using : yarn add zombie And use our wrapper with proper defaults for connectors : const Browser = require ( 'cozy-konnector-libs/dist/CozyBrowser' ) const browser = new Browser () Then you can use the zombie API to run HTTP requests to the targeted website. browser will keep its own cookie session. There is an implementation of the connector template using the Cozy Browser available : https://github.com/konnectors/cozy-konnector-template/tree/feat/zombiejs What if I want to use the browser session for saveFiles ? \u00b6 browser has two handy methods to help you with cookie session : getCookieJar : can export the current cookie session in a cookie jar object loadCookieJar : can import a cookie jar object as the new cookie session of the browser const { requestFactory } = require ( 'cozy-konnector-libs' ) const j = browser . getCookieJar () const request = requestFactory ({ jar : j }) await saveFiles ( myBills , fields , { requestInstance : request , }) I prefer to use cheerio to parse data, even with zombie \u00b6 It is still possible to access the html of the current page with zombie and you can then load it in a cheerio object : const cheerio = require ( 'cheerio' ) const $ = cheerio ( await browser . html ())", "title": "Cozy browser"}, {"location": "tutorials/konnector/cozy-browser/#zombie", "text": "We chose a specific JS browser implementation which is zombie . It is a wrapper around jsdom to make it easier for scraping.", "title": "Zombie"}, {"location": "tutorials/konnector/cozy-browser/#initialisation", "text": "Add the zombie npm package to your connector using : yarn add zombie And use our wrapper with proper defaults for connectors : const Browser = require ( 'cozy-konnector-libs/dist/CozyBrowser' ) const browser = new Browser () Then you can use the zombie API to run HTTP requests to the targeted website. browser will keep its own cookie session. There is an implementation of the connector template using the Cozy Browser available : https://github.com/konnectors/cozy-konnector-template/tree/feat/zombiejs", "title": "Initialisation"}, {"location": "tutorials/konnector/cozy-browser/#what-if-i-want-to-use-the-browser-session-for-savefiles", "text": "browser has two handy methods to help you with cookie session : getCookieJar : can export the current cookie session in a cookie jar object loadCookieJar : can import a cookie jar object as the new cookie session of the browser const { requestFactory } = require ( 'cozy-konnector-libs' ) const j = browser . getCookieJar () const request = requestFactory ({ jar : j }) await saveFiles ( myBills , fields , { requestInstance : request , })", "title": "What if I want to use the browser session for saveFiles ?"}, {"location": "tutorials/konnector/cozy-browser/#i-prefer-to-use-cheerio-to-parse-data-even-with-zombie", "text": "It is still possible to access the html of the current page with zombie and you can then load it in a cheerio object : const cheerio = require ( 'cheerio' ) const $ = cheerio ( await browser . html ())", "title": "I prefer to use cheerio to parse data, even with zombie"}, {"location": "tutorials/konnector/faq/", "text": "FAQ \u00b6 When I run my connector, a ghost node process eats all my memory \u00b6 Cozy-konnector-libs uses cheerio which is great but causes some problems when you try to console.log a cheerio object. In standalone or dev mode, the BaseKonnector tries to catch errors and display a maximum of details about them. But when the error contains a cheerio object, the problem happens. If you get this problem, catch the error yourself and only display the message : . catch ( err ) { console . log ( err . message ) // good console . log ( err ) // bad } How do I scrap a website \u00b6 Use the request function from cozy-konnector-libs with the proper options. Here\u2019s a sample code that will fetch the login page to get the value of the anti-CSRF token, submit the login form, browse to the bills page and fetch a bill: const { BaseKonnector , requestFactory } = require ( 'cozy-konnector-libs' ) const rq = requestFactory ({ jar : true , // handle the cookies like a browser json : false , // do not try to parse the result as a json document cheerio : true // automatically parse the result with [cheerio](https://github.com/cheeriojs/cheerio) }) const moment = require ( 'moment' ) module . exports = new BaseKonnector ( function fetch ( fields ) { return rq ( \"https://login.remote.web\" ) . then ( $ => { // the result is automatically wrapped with cheerio and you can use it like jQuery const form = { form : { login : fields . login , password : fields . password , csrf_token : $ ( '[name=\"csrf_token\"]' ). val (), } } return rq ({ method : 'POST' , form }) }) . then ( $ => rq ( \"https://admin.remote.web/bills\" )) . then ( $ => { return [{ date : moment ( $ ( \"#bill_date\" )), value : $ ( \"#bill_value\" )}] }) . then ( entries => addData ( entries , 'io.cozy.bills' )) })", "title": "Faq"}, {"location": "tutorials/konnector/faq/#faq", "text": "", "title": "FAQ"}, {"location": "tutorials/konnector/faq/#when-i-run-my-connector-a-ghost-node-process-eats-all-my-memory", "text": "Cozy-konnector-libs uses cheerio which is great but causes some problems when you try to console.log a cheerio object. In standalone or dev mode, the BaseKonnector tries to catch errors and display a maximum of details about them. But when the error contains a cheerio object, the problem happens. If you get this problem, catch the error yourself and only display the message : . catch ( err ) { console . log ( err . message ) // good console . log ( err ) // bad }", "title": "When I run my connector, a ghost node process eats all my memory"}, {"location": "tutorials/konnector/faq/#how-do-i-scrap-a-website", "text": "Use the request function from cozy-konnector-libs with the proper options. Here\u2019s a sample code that will fetch the login page to get the value of the anti-CSRF token, submit the login form, browse to the bills page and fetch a bill: const { BaseKonnector , requestFactory } = require ( 'cozy-konnector-libs' ) const rq = requestFactory ({ jar : true , // handle the cookies like a browser json : false , // do not try to parse the result as a json document cheerio : true // automatically parse the result with [cheerio](https://github.com/cheeriojs/cheerio) }) const moment = require ( 'moment' ) module . exports = new BaseKonnector ( function fetch ( fields ) { return rq ( \"https://login.remote.web\" ) . then ( $ => { // the result is automatically wrapped with cheerio and you can use it like jQuery const form = { form : { login : fields . login , password : fields . password , csrf_token : $ ( '[name=\"csrf_token\"]' ). val (), } } return rq ({ method : 'POST' , form }) }) . then ( $ => rq ( \"https://admin.remote.web/bills\" )) . then ( $ => { return [{ date : moment ( $ ( \"#bill_date\" )), value : $ ( \"#bill_value\" )}] }) . then ( entries => addData ( entries , 'io.cozy.bills' )) })", "title": "How do I scrap a website"}, {"location": "tutorials/konnector/getting-started/", "text": "Let\u2019s create our first connector \u00b6 Note A video tutorial to create your first connector is available \ud83c\udfac Run the sample \u00b6 The easiest way to create a new connector is to use cozy-konnector-template . First of all, download or clone the repository: git clone https://github.com/konnectors/cozy-konnector-template cozy-konnector-newservice cd cozy-konnector-newservice rm -rf .git git init yarn install # or npm install note: we use yarn , but if you prefer npm , keep using it, everything should work. The connector is ready to run with sample code. As a demo we will scrape a fictional website: books.toscrape.com , for which you do not need credentials . As indicated in the README.md file, just run: yarn standalone # or npm run standalone The very first run will create a konnector-dev-config.json file that allows you to configure the connector input when executing it with the CLI. This configuration comes from Cozy Home when deployed. { \"COZY_URL\" : \"http://cozy.tools:8080\" , \"fields\" : { // configuration injected to the start function } } The fields property allows you to set credentials for the targeted web service, such as login and password as if they come from Cozy Stack (so from a real Cozy Cloud instance). You can add as many fields as the targeted service needs. The COZY_URL property will be used later. You do not need to change it for now. As explained earlier, the demo website books.toscrape.com does not need any credentials. But for the code to run without error, you need to register a fake login and a fake password: { \"COZY_URL\" : \"http://cozy.tools:8080\" , \"fields\" : { \"login\" : \"zuck.m@rk.fb\" , \"password\" : \"123456\" } } In the template, this configuration file is already added to .gitignore file to be sure your credentials stay private. Now you can run the connector again in standalone mode to see how jpg and related data are downloaded. In this mode, cozy-client-js is stubbed and all data meant to be saved in a cozy are displayed in the standard output and files are saved in the ./data directory of the connector. This is useful to start developing your connector without handling the state of a real cozy stack. Please check CLI section of the documentation for more information. If you have arrived here, good job ! You are ready to implement your connector .", "title": "Basic structure"}, {"location": "tutorials/konnector/getting-started/#lets-create-our-first-connector", "text": "Note A video tutorial to create your first connector is available \ud83c\udfac", "title": "Let\u2019s create our first connector"}, {"location": "tutorials/konnector/getting-started/#run-the-sample", "text": "The easiest way to create a new connector is to use cozy-konnector-template . First of all, download or clone the repository: git clone https://github.com/konnectors/cozy-konnector-template cozy-konnector-newservice cd cozy-konnector-newservice rm -rf .git git init yarn install # or npm install note: we use yarn , but if you prefer npm , keep using it, everything should work. The connector is ready to run with sample code. As a demo we will scrape a fictional website: books.toscrape.com , for which you do not need credentials . As indicated in the README.md file, just run: yarn standalone # or npm run standalone The very first run will create a konnector-dev-config.json file that allows you to configure the connector input when executing it with the CLI. This configuration comes from Cozy Home when deployed. { \"COZY_URL\" : \"http://cozy.tools:8080\" , \"fields\" : { // configuration injected to the start function } } The fields property allows you to set credentials for the targeted web service, such as login and password as if they come from Cozy Stack (so from a real Cozy Cloud instance). You can add as many fields as the targeted service needs. The COZY_URL property will be used later. You do not need to change it for now. As explained earlier, the demo website books.toscrape.com does not need any credentials. But for the code to run without error, you need to register a fake login and a fake password: { \"COZY_URL\" : \"http://cozy.tools:8080\" , \"fields\" : { \"login\" : \"zuck.m@rk.fb\" , \"password\" : \"123456\" } } In the template, this configuration file is already added to .gitignore file to be sure your credentials stay private. Now you can run the connector again in standalone mode to see how jpg and related data are downloaded. In this mode, cozy-client-js is stubbed and all data meant to be saved in a cozy are displayed in the standard output and files are saved in the ./data directory of the connector. This is useful to start developing your connector without handling the state of a real cozy stack. Please check CLI section of the documentation for more information. If you have arrived here, good job ! You are ready to implement your connector .", "title": "Run the sample"}, {"location": "tutorials/konnector/going-further/", "text": "Going further \u00b6 Connector structure \u00b6 Basically, a connector is just a function passed to the BaseKonnector constructor, and which eventually returns a promise: To create the connector, just create a new instance of BaseKonnector with a function as argument: const { BaseKonnector } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( fields => { // use fields to get user credentials and choices console . log ( fields , 'fields' ) }) Typical workflow \u00b6 Everytime the connector is run, it will call the function and wait for the resolution of the returned promise. This function can then: log into the target website, fetch data, and save them as an array of objects with specific attributes expected by the save function ( saveFiles , addData , hydrateAndFilter , saveBills ). A basic connector workflow involves: authenticate on the website or API. Might be tricky, but that\u2019s the fun :-) getting data from the online service. You can get the data by calling an API or scraping the webpage. Check if the webpage itself is not using an API to retrieve data, might speed up our job. Mobile phones applications usually connects to an API that might be a reliable source of data. A quick exemple of a scraper here . filtering data to remove the ones already present inside the database using hydrateAndFilter save the filtered data into the database ( addData ) save the related files using ( saveFiles ) Error handling \u00b6 If your connector hits an issue fetching or saving the data, it can return an error code by throwing it as an error. The error codes are defined inside cozy-konnector-libs and Cozy Harvest Lib will display an explicit error to the user: LOGIN_FAILED : the connector could not login NOT_EXISTING_DIRECTORY : the folder specified as folder_to_save does not exist (checked automatically by the BaseKonnector) UNKNOWN_ERROR : there was an unexpected error, please take a look at the logs to know what happened VENDOR_DOWN : the target web site is down now USER_ACTION_NEEDED : The user needs to login to the service to do manual actions (could be Terms Of Service to validate) You can get the list of error codes in require('cozy-konnector-libs').errors ( source ) const { BaseKonnector , errors } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( fields => { // Here, the following message will be displayed in cozy-home : \"Bad credentials. Check the konnector fields and run the connection again.\" throw new Error ( errors . LOGIN_FAILED ) }) I want to pass secret variables to my connector without hardcoding it in the source code \u00b6 COZY_PARAMETERS environment variable will help you. In standalone mode or dev mode, you can init it in konnector-dev-config.json : \"COZY_PARAMETERS\" : { \"secret\" : { \"mySecretKey\" : \"s3cr3tk3y\" } } In your connector, you will get these secrets as a second parameter in your main function. module . exports = new BaseKonnector ( start ) async function start ( fields , cozyParameters ) { log ( 'info' , cozyParameters . secret . mySecretKey ) } // -> \"s3cr3tk3y\" If you want to know how this works in a real cozy, you can find more information on Stack documentation cozy-konnector-libs \u00b6 The Cozy Konnector Libs provide several useful methods for common tasks: BaseKonnector : creates the connector and fetches from the stack the connector\u2019s parameters (COZY_FIELDS\u2026) cozyClient gives an instance of cozy-client-js already initialized according to COZY_URL , and COZY_CREDENTIALS . Your code can immediately interact with the server thanks to this client. requestFactory a function which returns an instance of request-promise initialized with defaults often used in connector development. log allows to log messages with different levels hydrateAndFilter to filter data addData to store the retrieved data into the cozy linkBankOperations to link a bill to a bank operation saveBills which uses hydrateAndFilter, addData, saveFiles and linkBankOperations and which is specific to bills updateOrCreate create or update documents inside database htmlToPDF to convert HTML code to PDF content to insert into a PDF file created with the createCozyPDFDocument function createCozyPDFDocument to create a new PDF file to pass to htmlToPDF", "title": "Going further"}, {"location": "tutorials/konnector/going-further/#going-further", "text": "", "title": "Going further"}, {"location": "tutorials/konnector/going-further/#connector-structure", "text": "Basically, a connector is just a function passed to the BaseKonnector constructor, and which eventually returns a promise: To create the connector, just create a new instance of BaseKonnector with a function as argument: const { BaseKonnector } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( fields => { // use fields to get user credentials and choices console . log ( fields , 'fields' ) })", "title": "Connector structure"}, {"location": "tutorials/konnector/going-further/#typical-workflow", "text": "Everytime the connector is run, it will call the function and wait for the resolution of the returned promise. This function can then: log into the target website, fetch data, and save them as an array of objects with specific attributes expected by the save function ( saveFiles , addData , hydrateAndFilter , saveBills ). A basic connector workflow involves: authenticate on the website or API. Might be tricky, but that\u2019s the fun :-) getting data from the online service. You can get the data by calling an API or scraping the webpage. Check if the webpage itself is not using an API to retrieve data, might speed up our job. Mobile phones applications usually connects to an API that might be a reliable source of data. A quick exemple of a scraper here . filtering data to remove the ones already present inside the database using hydrateAndFilter save the filtered data into the database ( addData ) save the related files using ( saveFiles )", "title": "Typical workflow"}, {"location": "tutorials/konnector/going-further/#error-handling", "text": "If your connector hits an issue fetching or saving the data, it can return an error code by throwing it as an error. The error codes are defined inside cozy-konnector-libs and Cozy Harvest Lib will display an explicit error to the user: LOGIN_FAILED : the connector could not login NOT_EXISTING_DIRECTORY : the folder specified as folder_to_save does not exist (checked automatically by the BaseKonnector) UNKNOWN_ERROR : there was an unexpected error, please take a look at the logs to know what happened VENDOR_DOWN : the target web site is down now USER_ACTION_NEEDED : The user needs to login to the service to do manual actions (could be Terms Of Service to validate) You can get the list of error codes in require('cozy-konnector-libs').errors ( source ) const { BaseKonnector , errors } = require ( 'cozy-konnector-libs' ) module . exports = new BaseKonnector ( fields => { // Here, the following message will be displayed in cozy-home : \"Bad credentials. Check the konnector fields and run the connection again.\" throw new Error ( errors . LOGIN_FAILED ) })", "title": "Error handling"}, {"location": "tutorials/konnector/going-further/#i-want-to-pass-secret-variables-to-my-connector-without-hardcoding-it-in-the-source-code", "text": "COZY_PARAMETERS environment variable will help you. In standalone mode or dev mode, you can init it in konnector-dev-config.json : \"COZY_PARAMETERS\" : { \"secret\" : { \"mySecretKey\" : \"s3cr3tk3y\" } } In your connector, you will get these secrets as a second parameter in your main function. module . exports = new BaseKonnector ( start ) async function start ( fields , cozyParameters ) { log ( 'info' , cozyParameters . secret . mySecretKey ) } // -> \"s3cr3tk3y\" If you want to know how this works in a real cozy, you can find more information on Stack documentation", "title": "I want to pass secret variables to my connector without hardcoding it in the source code"}, {"location": "tutorials/konnector/going-further/#cozy-konnector-libs", "text": "The Cozy Konnector Libs provide several useful methods for common tasks: BaseKonnector : creates the connector and fetches from the stack the connector\u2019s parameters (COZY_FIELDS\u2026) cozyClient gives an instance of cozy-client-js already initialized according to COZY_URL , and COZY_CREDENTIALS . Your code can immediately interact with the server thanks to this client. requestFactory a function which returns an instance of request-promise initialized with defaults often used in connector development. log allows to log messages with different levels hydrateAndFilter to filter data addData to store the retrieved data into the cozy linkBankOperations to link a bill to a bank operation saveBills which uses hydrateAndFilter, addData, saveFiles and linkBankOperations and which is specific to bills updateOrCreate create or update documents inside database htmlToPDF to convert HTML code to PDF content to insert into a PDF file created with the createCozyPDFDocument function createCozyPDFDocument to create a new PDF file to pass to htmlToPDF", "title": "cozy-konnector-libs"}, {"location": "tutorials/konnector/how-does-it-work/", "text": "How does it work? \u00b6 A connector is a NodeJS script. +The target node version used to run your connector is the version 8. Like client side apps, connectors communicate with the Cozy Stack using its HTTP API, and get a unique auth token every time they start. They need to register with a manifest , and ask the user for permissions. To facilitate connector development, a npm package, cozy-konnector-libs , provides some shared libraries that are adapted to be used for a connector: cheerio to easily query a HTML page request-promise : request with Promise support request-debug that displays all the requests and responses in the standard output. Toggle debug option in requestFactory options Besides, you\u2019ll probably need some other npm packages to help you run your connector: momentjs or date-fns to manage dates bluebird to get enhanced promises When the connector is started, it also receives some data via environment variables: COZY_CREDENTIALS : an auth token used by cozy-client-js to communicate with the server COZY_URL : the Cozy Stack API entry point COZY_FIELDS : settings coming from Cozy Home and filled by the user (login, password, directory path). These variables are used by the connector and the cozy-client to configure the connection to the Cozy Stack with the right permissions as defined in the connector manifest . They are simulated in standalone mode so that you do not need a real Cozy Stack to develop a connector. [ More about BaseKonnector ] From the server point of view, each connector is a job which is executed periodically via a trigger . [ More about Cozy Stack jobs ]", "title": "How does it work"}, {"location": "tutorials/konnector/how-does-it-work/#how-does-it-work", "text": "A connector is a NodeJS script. +The target node version used to run your connector is the version 8. Like client side apps, connectors communicate with the Cozy Stack using its HTTP API, and get a unique auth token every time they start. They need to register with a manifest , and ask the user for permissions. To facilitate connector development, a npm package, cozy-konnector-libs , provides some shared libraries that are adapted to be used for a connector: cheerio to easily query a HTML page request-promise : request with Promise support request-debug that displays all the requests and responses in the standard output. Toggle debug option in requestFactory options Besides, you\u2019ll probably need some other npm packages to help you run your connector: momentjs or date-fns to manage dates bluebird to get enhanced promises When the connector is started, it also receives some data via environment variables: COZY_CREDENTIALS : an auth token used by cozy-client-js to communicate with the server COZY_URL : the Cozy Stack API entry point COZY_FIELDS : settings coming from Cozy Home and filled by the user (login, password, directory path). These variables are used by the connector and the cozy-client to configure the connection to the Cozy Stack with the right permissions as defined in the connector manifest . They are simulated in standalone mode so that you do not need a real Cozy Stack to develop a connector. [ More about BaseKonnector ] From the server point of view, each connector is a job which is executed periodically via a trigger . [ More about Cozy Stack jobs ]", "title": "How does it work?"}, {"location": "tutorials/konnector/oauth/", "text": "Developping an OAuth connector \u00b6 Connectors with OAuth are a special case. The OAuth protocol needs a secret key most of the time and getting the token to access the api takes different forms depending on the targeted api. And you do not want your secret api key to be available in the connector source code. That is why the stack will handle the OAuth protocol for you. You can have more details on how this is done and deployed in the cozy-stack documentation Connector development \u00b6 It is possible to develop an OAuth connector in standalone or dev mode but there will be no stack to handle the protocol. You will have to do it manually (with curl for example). Most apis have extended documentations for this. Once you have got your access token, simply add it your konnector-dev-config.json file like this : { \"fields\" : { \"access_token\" : \"\" , } } This access_token will be accessible in your connector exactly like it would when the connector is run by the cozy stack. module . exports = new BaseKonnector ( start ) async function start ( fields ) { // you can use fields.access_token to request your api } If your access_token becomes outdated, you will have to refresh it yourself and replace it in konnector-dev-config.json Here is a list of existing OAuth connectors : google , facebook Packaging for a real cozy \u00b6 When your connector is ready and works in standalone mode, it is time to package it to run in a real cozy. Here is what is needed. 1) OAuth configuration in the \u201csecrets/io-cozy-account_types\u201d database 2) scope configuration in the connector manifest if needed 1) OAuth is implemented in some different ways depending on the targetted service and the stack needs to know some details about the api : grant_mode : \u201cauthorization_code\u201d or \u201crefresh_token\u201d client_id : the client id given by the api provider client_secret : the client secret given by the provider auth_endpoint: the url which will be used to authenticate token_endpoint: the url which will be used to fetch a token token_mode: (optionnal: \u201cbasic\u201d, \u201cget\u201d) specify the way the client id and secret will be given to the api. If not specified, a the HTTP post method will be used redirect_uri: standard OAuth redirect uri it take the following form : \u201c https://oauthcallback. /accounts/ /redirect These parameters will be saved in the \u201csecrets/io-cozy-account_types\u201d database in the following form for facebook : { \"_id\" : \"facebook\" , \"grant_mode\" : \"authorization_code\" , \"redirect_uri\" : \"https://oauthcallback.cozy.tools:8080/accounts/facebook/redirect\" , \"token_mode\" : \"get\" , \"token_endpoint\" : \"https://graph.facebook.com/v2.12/oauth/access_token\" , \"auth_endpoint\" : \"https://www.facebook.com/v2.12/dialog/oauth\" , \"client_id\" : \"...\" , \"client_secret\" : \"...\" } To provision this configuration in your own local cozy, you can use curl for example : curl -X PUT localhost:5984/secrets%2Fio-cozy-account_types/facebook -d '{ \"grant_mode\": \"authorization_code\", \"client_id\": \"...\", \"client_secret\": \"...\", \"auth_endpoint\": \"https://www.facebook.com/v2.12/dialog/oauth\", \"token_endpoint\": \"https://graph.facebook.com/v2.12/oauth/access_token\", \"token_mode\": \"get\", \"redirect_url\": \"https://oauthcallback.cozy.tools:8080/accounts/facebook/redirect\" }' And if you want this to be provisioned in production cozies in mycozy.cloud domain, please contact us. 2) Most Oauth apis need scope configuration. To be more versatile, this scope configuration in done in the connector manifest in the \u201coauth.scope\u201d attribute : \"oauth\" : { \"scope\" : [ \"scope1 scope2\" ] } Once the manifest and the account_types databases are setup, you can build and deploy your connector normally and the home application will handle the display of OAuth page automatically on account creation.", "title": "Developping an OAuth connector"}, {"location": "tutorials/konnector/oauth/#developping-an-oauth-connector", "text": "Connectors with OAuth are a special case. The OAuth protocol needs a secret key most of the time and getting the token to access the api takes different forms depending on the targeted api. And you do not want your secret api key to be available in the connector source code. That is why the stack will handle the OAuth protocol for you. You can have more details on how this is done and deployed in the cozy-stack documentation", "title": "Developping an OAuth connector"}, {"location": "tutorials/konnector/oauth/#connector-development", "text": "It is possible to develop an OAuth connector in standalone or dev mode but there will be no stack to handle the protocol. You will have to do it manually (with curl for example). Most apis have extended documentations for this. Once you have got your access token, simply add it your konnector-dev-config.json file like this : { \"fields\" : { \"access_token\" : \"\" , } } This access_token will be accessible in your connector exactly like it would when the connector is run by the cozy stack. module . exports = new BaseKonnector ( start ) async function start ( fields ) { // you can use fields.access_token to request your api } If your access_token becomes outdated, you will have to refresh it yourself and replace it in konnector-dev-config.json Here is a list of existing OAuth connectors : google , facebook", "title": "Connector development"}, {"location": "tutorials/konnector/oauth/#packaging-for-a-real-cozy", "text": "When your connector is ready and works in standalone mode, it is time to package it to run in a real cozy. Here is what is needed. 1) OAuth configuration in the \u201csecrets/io-cozy-account_types\u201d database 2) scope configuration in the connector manifest if needed 1) OAuth is implemented in some different ways depending on the targetted service and the stack needs to know some details about the api : grant_mode : \u201cauthorization_code\u201d or \u201crefresh_token\u201d client_id : the client id given by the api provider client_secret : the client secret given by the provider auth_endpoint: the url which will be used to authenticate token_endpoint: the url which will be used to fetch a token token_mode: (optionnal: \u201cbasic\u201d, \u201cget\u201d) specify the way the client id and secret will be given to the api. If not specified, a the HTTP post method will be used redirect_uri: standard OAuth redirect uri it take the following form : \u201c https://oauthcallback. /accounts/ /redirect These parameters will be saved in the \u201csecrets/io-cozy-account_types\u201d database in the following form for facebook : { \"_id\" : \"facebook\" , \"grant_mode\" : \"authorization_code\" , \"redirect_uri\" : \"https://oauthcallback.cozy.tools:8080/accounts/facebook/redirect\" , \"token_mode\" : \"get\" , \"token_endpoint\" : \"https://graph.facebook.com/v2.12/oauth/access_token\" , \"auth_endpoint\" : \"https://www.facebook.com/v2.12/dialog/oauth\" , \"client_id\" : \"...\" , \"client_secret\" : \"...\" } To provision this configuration in your own local cozy, you can use curl for example : curl -X PUT localhost:5984/secrets%2Fio-cozy-account_types/facebook -d '{ \"grant_mode\": \"authorization_code\", \"client_id\": \"...\", \"client_secret\": \"...\", \"auth_endpoint\": \"https://www.facebook.com/v2.12/dialog/oauth\", \"token_endpoint\": \"https://graph.facebook.com/v2.12/oauth/access_token\", \"token_mode\": \"get\", \"redirect_url\": \"https://oauthcallback.cozy.tools:8080/accounts/facebook/redirect\" }' And if you want this to be provisioned in production cozies in mycozy.cloud domain, please contact us. 2) Most Oauth apis need scope configuration. To be more versatile, this scope configuration in done in the connector manifest in the \u201coauth.scope\u201d attribute : \"oauth\" : { \"scope\" : [ \"scope1 scope2\" ] } Once the manifest and the account_types databases are setup, you can build and deploy your connector normally and the home application will handle the display of OAuth page automatically on account creation.", "title": "Packaging for a real cozy"}, {"location": "tutorials/konnector/packaging/", "text": "You\u2019ve successfully created your connector and saved your personal data a service you\u2019re using. Now, you want to help others free their data, it\u2019s great ! To allow other users to use your connector, it must be packaged and sent to the store. Integration in the store for all the users \u00b6 To run a connector, we do not want the cozy to install all dependencies of the connector each time it installs it. To avoid this, the connectors need to be compiled into one file in a dedicated branch of the repository and the repository needs to be a public git repository. The package.json file from cozy-konnector-template gives you the commands to do this : yarn build and yarn deploy but the last one needs to be configured in package.json Once your public git repository is configured, you only have to declare it. Cozy will soon have a store for connectors and you will be able to publish connectors yourself. But at the moment, you need to declare your new connector on the cozy forum . The Cozy team will review your code and add your connector to the Cozy Home application. To make the connector available more quickly for all cozys, you can follow this few steps of packaging: Icon \u00b6 You need to push an icon in assets/ . Please respect this rules : Square icon, possibly a png or svg Try the Apple app store icon if needed Package.json \u00b6 Edit the name to be cozy-konnector- Edit the repository URL Edit the command deploy with the correct repository URL Manifest.konnector \u00b6 Edit the name with a nice name (Capitals and spaces allowed here) Edit icon as needed Edit slug (no capitals and no spaces here) Edit source with the correct repository URL Add a correct vendor link Choose one or more categories (used to sort connectors in Cozy Store) in this list : banking, shopping, insurance, isp, telecom, energy, public_service, other . If needed, change the input type the target website use to login the user: text , email or phone for instance, this will enforce pre-checking Edit for both locales en and fr the short description and long description See all the properties of the manifest Deploy command \u00b6 This will deploy a compiled version of your connector in a dedicated branch of your git repository using git-directory-deploy . This deployed version can then be referenced to cozy-app-publish to deploy your connector to the registry.", "title": "Package your connector"}, {"location": "tutorials/konnector/packaging/#integration-in-the-store-for-all-the-users", "text": "To run a connector, we do not want the cozy to install all dependencies of the connector each time it installs it. To avoid this, the connectors need to be compiled into one file in a dedicated branch of the repository and the repository needs to be a public git repository. The package.json file from cozy-konnector-template gives you the commands to do this : yarn build and yarn deploy but the last one needs to be configured in package.json Once your public git repository is configured, you only have to declare it. Cozy will soon have a store for connectors and you will be able to publish connectors yourself. But at the moment, you need to declare your new connector on the cozy forum . The Cozy team will review your code and add your connector to the Cozy Home application. To make the connector available more quickly for all cozys, you can follow this few steps of packaging:", "title": "Integration in the store for all the users"}, {"location": "tutorials/konnector/packaging/#icon", "text": "You need to push an icon in assets/ . Please respect this rules : Square icon, possibly a png or svg Try the Apple app store icon if needed", "title": "Icon"}, {"location": "tutorials/konnector/packaging/#packagejson", "text": "Edit the name to be cozy-konnector- Edit the repository URL Edit the command deploy with the correct repository URL", "title": "Package.json"}, {"location": "tutorials/konnector/packaging/#manifestkonnector", "text": "Edit the name with a nice name (Capitals and spaces allowed here) Edit icon as needed Edit slug (no capitals and no spaces here) Edit source with the correct repository URL Add a correct vendor link Choose one or more categories (used to sort connectors in Cozy Store) in this list : banking, shopping, insurance, isp, telecom, energy, public_service, other . If needed, change the input type the target website use to login the user: text , email or phone for instance, this will enforce pre-checking Edit for both locales en and fr the short description and long description See all the properties of the manifest", "title": "Manifest.konnector"}, {"location": "tutorials/konnector/packaging/#deploy-command", "text": "This will deploy a compiled version of your connector in a dedicated branch of your git repository using git-directory-deploy . This deployed version can then be referenced to cozy-app-publish to deploy your connector to the registry.", "title": "Deploy command"}, {"location": "tutorials/konnector/save-data/", "text": "In the previous sections, we have Created the boilerplate for our connector Scraped data from our Cozy We haven\u2019t yet inserted the data in our Cozy since we have used the standalone mode. Here it comes ;) Linking your connector to a cozy : dev mode The manifest konnector-dev-config.json Run the dev mode Linking your connector to a cozy : dev mode \u00b6 After several yarn standalone , your connector is able to automatically gather data from the targeted web service. It\u2019s time now to put this data in a real cozy. Here comes the dev mode . For that your connector needs more setup : a manifest.konnector file a COZY_URL section in konnector-dev-config.json The manifest \u00b6 Each connector is described by a manifest. This is a JSON file named manifest.konnector at the root of your code folder. It should include the following minimal information: { \"name\" : \"konnector name\" , \"type\" : \"node\" , \"slug\" : \"konnectorslug\" , \"description\" : \"description\" , \"source\" : \"git://github.com/cozy/cozy-konnector-thename.git\" , \"permissions\" : { \"accounts\" : { \"description\" : \"Required to get the account's data\" , \"type\" : \"io.cozy.accounts\" , \"verbs\" : [ \"GET\" ] } } } cozy-konnector-template already has a manifest which you can customize. You may add some permissions for your own doctype. Here is the detailed list of fields for a connector manifest file. konnector-dev-config.json \u00b6 If you want to put data from your connector to a real cozy, you must define where to find this cozy, and this must be a cozy for which you have the credentials. Here is an example konnector-dev-config.json : { \"COZY_URL\": \"https://lukeskywalker.mycozy.cloud\", \"fields\": { \"login\": \"luke@skywalker.org\", \"password\": \"daddyissues\" } } \u26a0\ufe0f It\u2019s a common mistake to put a URL with the app, for example https://lukeskywalker-home.mycozy.cloud . It won\u2019t work, you must removed the -home part. Run the dev mode \u00b6 Then you just have to run: yarn dev For the first run, the CLI will open a tab in your browser asking you to grant permissions to the connector. The connector will then save data directly into your cozy. This will validate that your manifest has the needed permissions on the data you want to save. Now that we have successfully scraped and saved our data, the next step is to build the connector and send it to Cozy store !", "title": "Save data"}, {"location": "tutorials/konnector/save-data/#linking-your-connector-to-a-cozy-dev-mode", "text": "After several yarn standalone , your connector is able to automatically gather data from the targeted web service. It\u2019s time now to put this data in a real cozy. Here comes the dev mode . For that your connector needs more setup : a manifest.konnector file a COZY_URL section in konnector-dev-config.json", "title": "Linking your connector to a cozy : dev mode"}, {"location": "tutorials/konnector/save-data/#the-manifest", "text": "Each connector is described by a manifest. This is a JSON file named manifest.konnector at the root of your code folder. It should include the following minimal information: { \"name\" : \"konnector name\" , \"type\" : \"node\" , \"slug\" : \"konnectorslug\" , \"description\" : \"description\" , \"source\" : \"git://github.com/cozy/cozy-konnector-thename.git\" , \"permissions\" : { \"accounts\" : { \"description\" : \"Required to get the account's data\" , \"type\" : \"io.cozy.accounts\" , \"verbs\" : [ \"GET\" ] } } } cozy-konnector-template already has a manifest which you can customize. You may add some permissions for your own doctype. Here is the detailed list of fields for a connector manifest file.", "title": "The manifest"}, {"location": "tutorials/konnector/save-data/#konnector-dev-configjson", "text": "If you want to put data from your connector to a real cozy, you must define where to find this cozy, and this must be a cozy for which you have the credentials. Here is an example konnector-dev-config.json : { \"COZY_URL\": \"https://lukeskywalker.mycozy.cloud\", \"fields\": { \"login\": \"luke@skywalker.org\", \"password\": \"daddyissues\" } } \u26a0\ufe0f It\u2019s a common mistake to put a URL with the app, for example https://lukeskywalker-home.mycozy.cloud . It won\u2019t work, you must removed the -home part.", "title": "konnector-dev-config.json"}, {"location": "tutorials/konnector/save-data/#run-the-dev-mode", "text": "Then you just have to run: yarn dev For the first run, the CLI will open a tab in your browser asking you to grant permissions to the connector. The connector will then save data directly into your cozy. This will validate that your manifest has the needed permissions on the data you want to save. Now that we have successfully scraped and saved our data, the next step is to build the connector and send it to Cozy store !", "title": "Run the dev mode"}, {"location": "tutorials/konnector/scrape-data/", "text": "In this part, we are going to see how to scrape data from the service you want to retrieve your data from. If not done yet, you want to check the getting started guide . Implement your connector \u00b6 There are four steps for a connector to save data to Cozy Stack : authentication request data parse and format data save data to cozy stack You can see these steps in the src/index.js in the konnectors/template : async function start ( fields ) { // step 1. log ( 'info' , 'Authenticating ...' ) await authenticate ( fields . login , fields . password ) log ( 'info' , 'Successfully logged in' ) // step 2. // The BaseKonnector instance expects a Promise as return of the function log ( 'info' , 'Fetching the list of documents' ) const $ = await request ( ` ${ baseUrl } /index.html` ) // step 3. log ( 'info' , 'Parsing list of documents' ) const documents = await parseDocuments ( $ ) // step 4. // here we use the saveBills function even if what we fetch are not bills, but this is the most // common case in connectors log ( 'info' , 'Saving data to Cozy' ) await saveBills ( documents , fields . folderPath , { // this is a bank identifier which will be used to link bills to bank operations. These // identifiers should be at least a word found in the title of a bank operation related to this // bill. It is not case sensitive. identifiers : [ 'books' ] }) } Authentication \u00b6 Open the src/index.js file, there are comments to guide you through it. The very first step is to be able to authenticate to the remote service, this is done with the line: note: don\u2019t forget to add your additional fields if you have some. await authenticate ( fields . login , fields . password ) There are many obstacles at this level: is there a captcha? If yes you can take a look at our solveCaptcha API is there a 2FA? how is the
    ? note: if the remote service exposes an API, you should use classical request call. Let\u2019s say the remote service exposes a simple classical form like https://www.trainline.eu/signin : < form id = \"signin-form\" novalidate = \"\" class = \"signin__form\" data-ember-action = \"\" data-ember-action-680 = \"680\" > < input name = \"email\" autocomplete = \"on\" placeholder = \"Email Address\" id = \"ember691\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"email\" > < input name = \"password\" autocomplete = \"on\" placeholder = \"Password\" id = \"ember696\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"password\" > < div class = \"signin__forgot\" > < span data-ember-action = \"\" data-ember-action-697 = \"697\" > < a href = \"/password\" id = \"ember698\" class = \"ember-view\" > Forgot your password? < div class = \"signin__buttons \" > < div class = \"signin__buttons-block\" > < button type = \"submit\" class = \"signin__button\" > Sign In Find a CSS selector for the form tag: form#signin-form . Find the name of the input tags used to host user\u2019s credentials: email and password . You are ready to complete the signin(options) object called in the authenticate(username, password) function: function authenticate ( username , password ) { return signin ({ url : `https://www.trainline.eu/signin` , formSelector : 'form#signin-form' , formData : { email : username , password }, validate : ( statusCode , $ ) => { // write some code to validate the form submission } }) } To implement the validate function, you need to check what is happening on a successful login and on an unsuccessful login. With the https://www.trainline.eu/signin example, fill the form with wrong credentials, open your browser\u2019s devtools (and check the network tab) and submit the form. Here it is clear, on incorrect credentials, the response have a status code 422 : HTTP/2.0 422 No Reason Phrase Do the same with valid credentials. HTTP/2.0 200 OK Then you can write a simple and straight forward validate code: function authenticate ( username , password ) { return signin ({ url : `https://www.trainline.eu/signin` , formSelector : 'form#signin-form' , formData : { email : username , password }, // \"email\" and \"password\" correspond to the `name` attribute of the HTML inputs validate : ( statusCode , $ ) => { return statusCode === 200 || log ( 'error' , 'Invalid credentials' ) } }) } However if the target website doesn\u2019t use statusCode correctly you can also use fullResponse.request.uri.href to check if there is a redirection to a page that requires to be logged in: validate : ( statusCode , $ , fullResponse ) => { return fullResponse . request . uri . href == 'https://example.com/account' || log ( 'error' , 'Invalid credentials' ) } It is also possible to use Cheerio to check if an HTML element is present in the web page or not : validate : ( statusCode , $ ) => { return $ ( 'a[href=\"https://example.com/logout\"]' ). length == 1 || log ( 'error' , $ ( '.error' ). text ()) } Request data \u00b6 Once the connector is able to be authenticated by the online service, the next step is to fetch data. The most common case is that the invoices we want to fetch are listed in a HTML page. So to request data, we fetch the target webpage that contains invoices list. But sometimes, the webpage is a JavaScript page that uses a JSON API URL. JSON is easier to parse than full HTML webpages. For the purpose of this guide, let\u2019s consider we are in the case of a full HTML webpage, like the service given as an example in the template: http://books.toscrape.com This is the easiest part, just fetch the webpage: const $ = await request ( 'http://books.toscrape.com/index.html' ) The $ variable is set to a cheerio object with useful API to crawl the webpage . You can name this variable as you want and create as many as you want Cheerio variables such as : $doc or $page . That object will be very useful for the next step. Parse the document \u00b6 We want to get every
    of the page in a JavaScript Array: const articles = []. map . call ( $ ( 'article' , node => node )) For every book, we want to catch the title attribute of this tag article h3 a . This is a CSS Selector that cheerio understands to select some part of the tree. In order to crawl a list of items to create an Array of JSON object, we can create our own function or use the function scrape from the connector libs : const docs = scrape ( $ , { title : { sel : 'h3 a' , attr : 'title' }, amount : { sel : '.price_color' , parse : normalizePrice }, url : { sel : 'h3 a' , attr : 'href' , parse : url => ` ${ baseUrl } / ${ url } ` }, fileurl : { sel : 'img' , attr : 'src' , parse : src => ` ${ baseUrl } / ${ src } ` }, filename : { sel : 'h3 a' , attr : 'title' , parse : title => ` ${ title } .jpg` } }, 'article' ) Keep in mind that there are many useful CSS Pseudo-classes and Combinators that you can use in your CSS selectors to help you select HTML elements. This code will loop on
    and for each item will create a JSON object with the selector sel and the value of attribute attr if specified, otherwise it takes the value of the child node, this value can be edited with the parse function. Here is a sample for the following markup from http://books.toscrape.com : < article class = \"product_pod\" > < div class = \"image_container\" > < a href = \"catalogue/a-light-in-the-attic_1000/index.html\" > < img src = \"media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg\" alt = \"A Light in the Attic\" class = \"thumbnail\" > < p class = \"star-rating Three\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < h3 > < a href = \"catalogue/a-light-in-the-attic_1000/index.html\" title = \"A Light in the Attic\" > A Light in the ... < div class = \"product_price\" > < p class = \"price_color\" > \u00a351.77 < p class = \"instock availability\" > < i class = \"icon-ok\" > In stock < form > < button type = \"submit\" class = \"btn btn-primary btn-block\" data-loading-text = \"Adding...\" > Add to basket And we will get the following JSON object: { \"title\" : \"A Light in the Attic\" , \"amount\" : 51.77 , \"url\" : \"http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html\" , \"fileurl\" : \"http://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg\" , \"filename\" : \"A Light in the Attic.jpg\" } The code sample includes some other function to manipulate the result object, but we have the idea. Once we build a correct object, we can save it to Cozy Stack. fileurl is used to tell Cozy where to find the file (here an image) to retreive. Then you can save it to Cozy Stack (see section below). There are many document types (Doctypes) you can store in your Cozy, such as: Bills Contacts Bank and so on\u2026 Save data to Cozy Stack \u00b6 In the example we use some built-in function to save a bill to the Cozy Stack. But there is a bunch of functions available depending on what you want: addData hydrateAndFilter saveBills to save invoices files (this function use saveFiles ) that can be linked to your bank transactions. saveFiles to upload files to Cozy Drive. and so on\u2026 For example, to save bills to Cozy you have to start by recovering all required fields for a data type io.cozy.bills using the scrape function, and then you can use the function saveBills to save your docs to Cozy Stack as shown below: await saveBills ( documents , fields , { idenditifiers: [ 'vendor' ], // name of the target website contentType: 'application/pdf' }) documents is the list of bills returned by the function parseDocuments after the page scraping . We can find more information in the libs repository . Now that we pass on every steps, it is time to test the connector with yarn standalone . For now, we have not inserted the data in the Cozy, in the next section , you will learn how to plug your connector to your Cozy.", "title": "Scrape data"}, {"location": "tutorials/konnector/scrape-data/#implement-your-connector", "text": "There are four steps for a connector to save data to Cozy Stack : authentication request data parse and format data save data to cozy stack You can see these steps in the src/index.js in the konnectors/template : async function start ( fields ) { // step 1. log ( 'info' , 'Authenticating ...' ) await authenticate ( fields . login , fields . password ) log ( 'info' , 'Successfully logged in' ) // step 2. // The BaseKonnector instance expects a Promise as return of the function log ( 'info' , 'Fetching the list of documents' ) const $ = await request ( ` ${ baseUrl } /index.html` ) // step 3. log ( 'info' , 'Parsing list of documents' ) const documents = await parseDocuments ( $ ) // step 4. // here we use the saveBills function even if what we fetch are not bills, but this is the most // common case in connectors log ( 'info' , 'Saving data to Cozy' ) await saveBills ( documents , fields . folderPath , { // this is a bank identifier which will be used to link bills to bank operations. These // identifiers should be at least a word found in the title of a bank operation related to this // bill. It is not case sensitive. identifiers : [ 'books' ] }) }", "title": "Implement your connector"}, {"location": "tutorials/konnector/scrape-data/#authentication", "text": "Open the src/index.js file, there are comments to guide you through it. The very first step is to be able to authenticate to the remote service, this is done with the line: note: don\u2019t forget to add your additional fields if you have some. await authenticate ( fields . login , fields . password ) There are many obstacles at this level: is there a captcha? If yes you can take a look at our solveCaptcha API is there a 2FA? how is the ? note: if the remote service exposes an API, you should use classical request call. Let\u2019s say the remote service exposes a simple classical form like https://www.trainline.eu/signin : < form id = \"signin-form\" novalidate = \"\" class = \"signin__form\" data-ember-action = \"\" data-ember-action-680 = \"680\" > < input name = \"email\" autocomplete = \"on\" placeholder = \"Email Address\" id = \"ember691\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"email\" > < input name = \"password\" autocomplete = \"on\" placeholder = \"Password\" id = \"ember696\" class = \"ember-text-field textfield ember-view\" data-enpass . usermodified = \"yes\" type = \"password\" > < div class = \"signin__forgot\" > < span data-ember-action = \"\" data-ember-action-697 = \"697\" > < a href = \"/password\" id = \"ember698\" class = \"ember-view\" > Forgot your password? < div class = \"signin__buttons \" > < div class = \"signin__buttons-block\" > < button type = \"submit\" class = \"signin__button\" > Sign In Find a CSS selector for the form tag: form#signin-form . Find the name of the input tags used to host user\u2019s credentials: email and password . You are ready to complete the signin(options) object called in the authenticate(username, password) function: function authenticate ( username , password ) { return signin ({ url : `https://www.trainline.eu/signin` , formSelector : 'form#signin-form' , formData : { email : username , password }, validate : ( statusCode , $ ) => { // write some code to validate the form submission } }) } To implement the validate function, you need to check what is happening on a successful login and on an unsuccessful login. With the https://www.trainline.eu/signin example, fill the form with wrong credentials, open your browser\u2019s devtools (and check the network tab) and submit the form. Here it is clear, on incorrect credentials, the response have a status code 422 : HTTP/2.0 422 No Reason Phrase Do the same with valid credentials. HTTP/2.0 200 OK Then you can write a simple and straight forward validate code: function authenticate ( username , password ) { return signin ({ url : `https://www.trainline.eu/signin` , formSelector : 'form#signin-form' , formData : { email : username , password }, // \"email\" and \"password\" correspond to the `name` attribute of the HTML inputs validate : ( statusCode , $ ) => { return statusCode === 200 || log ( 'error' , 'Invalid credentials' ) } }) } However if the target website doesn\u2019t use statusCode correctly you can also use fullResponse.request.uri.href to check if there is a redirection to a page that requires to be logged in: validate : ( statusCode , $ , fullResponse ) => { return fullResponse . request . uri . href == 'https://example.com/account' || log ( 'error' , 'Invalid credentials' ) } It is also possible to use Cheerio to check if an HTML element is present in the web page or not : validate : ( statusCode , $ ) => { return $ ( 'a[href=\"https://example.com/logout\"]' ). length == 1 || log ( 'error' , $ ( '.error' ). text ()) }", "title": "Authentication"}, {"location": "tutorials/konnector/scrape-data/#request-data", "text": "Once the connector is able to be authenticated by the online service, the next step is to fetch data. The most common case is that the invoices we want to fetch are listed in a HTML page. So to request data, we fetch the target webpage that contains invoices list. But sometimes, the webpage is a JavaScript page that uses a JSON API URL. JSON is easier to parse than full HTML webpages. For the purpose of this guide, let\u2019s consider we are in the case of a full HTML webpage, like the service given as an example in the template: http://books.toscrape.com This is the easiest part, just fetch the webpage: const $ = await request ( 'http://books.toscrape.com/index.html' ) The $ variable is set to a cheerio object with useful API to crawl the webpage . You can name this variable as you want and create as many as you want Cheerio variables such as : $doc or $page . That object will be very useful for the next step.", "title": "Request data"}, {"location": "tutorials/konnector/scrape-data/#parse-the-document", "text": "We want to get every
    of the page in a JavaScript Array: const articles = []. map . call ( $ ( 'article' , node => node )) For every book, we want to catch the title attribute of this tag article h3 a . This is a CSS Selector that cheerio understands to select some part of the tree. In order to crawl a list of items to create an Array of JSON object, we can create our own function or use the function scrape from the connector libs : const docs = scrape ( $ , { title : { sel : 'h3 a' , attr : 'title' }, amount : { sel : '.price_color' , parse : normalizePrice }, url : { sel : 'h3 a' , attr : 'href' , parse : url => ` ${ baseUrl } / ${ url } ` }, fileurl : { sel : 'img' , attr : 'src' , parse : src => ` ${ baseUrl } / ${ src } ` }, filename : { sel : 'h3 a' , attr : 'title' , parse : title => ` ${ title } .jpg` } }, 'article' ) Keep in mind that there are many useful CSS Pseudo-classes and Combinators that you can use in your CSS selectors to help you select HTML elements. This code will loop on
    and for each item will create a JSON object with the selector sel and the value of attribute attr if specified, otherwise it takes the value of the child node, this value can be edited with the parse function. Here is a sample for the following markup from http://books.toscrape.com : < article class = \"product_pod\" > < div class = \"image_container\" > < a href = \"catalogue/a-light-in-the-attic_1000/index.html\" > < img src = \"media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg\" alt = \"A Light in the Attic\" class = \"thumbnail\" > < p class = \"star-rating Three\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < i class = \"icon-star\" > < h3 > < a href = \"catalogue/a-light-in-the-attic_1000/index.html\" title = \"A Light in the Attic\" > A Light in the ... < div class = \"product_price\" > < p class = \"price_color\" > \u00a351.77 < p class = \"instock availability\" > < i class = \"icon-ok\" > In stock < form > < button type = \"submit\" class = \"btn btn-primary btn-block\" data-loading-text = \"Adding...\" > Add to basket And we will get the following JSON object: { \"title\" : \"A Light in the Attic\" , \"amount\" : 51.77 , \"url\" : \"http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html\" , \"fileurl\" : \"http://books.toscrape.com/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg\" , \"filename\" : \"A Light in the Attic.jpg\" } The code sample includes some other function to manipulate the result object, but we have the idea. Once we build a correct object, we can save it to Cozy Stack. fileurl is used to tell Cozy where to find the file (here an image) to retreive. Then you can save it to Cozy Stack (see section below). There are many document types (Doctypes) you can store in your Cozy, such as: Bills Contacts Bank and so on\u2026", "title": "Parse the document"}, {"location": "tutorials/konnector/scrape-data/#save-data-to-cozy-stack", "text": "In the example we use some built-in function to save a bill to the Cozy Stack. But there is a bunch of functions available depending on what you want: addData hydrateAndFilter saveBills to save invoices files (this function use saveFiles ) that can be linked to your bank transactions. saveFiles to upload files to Cozy Drive. and so on\u2026 For example, to save bills to Cozy you have to start by recovering all required fields for a data type io.cozy.bills using the scrape function, and then you can use the function saveBills to save your docs to Cozy Stack as shown below: await saveBills ( documents , fields , { idenditifiers: [ 'vendor' ], // name of the target website contentType: 'application/pdf' }) documents is the list of bills returned by the function parseDocuments after the page scraping . We can find more information in the libs repository . Now that we pass on every steps, it is time to test the connector with yarn standalone . For now, we have not inserted the data in the Cozy, in the next section , you will learn how to plug your connector to your Cozy.", "title": "Save data to Cozy Stack"}, {"location": "tutorials/selfhosting/", "text": "Self-Hosting \u00b6 Introduction \u00b6 Cozycloud offers an hosted service on a freemium model. You can discover it freely and upgrade your offer to suit your needs. We are commited to protect your data and respect your privacy and are convinced that \u201cYou Will Stay Because You Can Leave\u201d. The cozycloud source code is publicly available to be audited and you can decide to host it yourself or ask someone else you trust to host your cozy. This documentation explains how to self host your cozy instance on your own server. You can choose either a traditioinal install on your server or to host Cozy in a docker environment. Cozycloud provides precompiled packages for the last two major versions of Debian and Ubuntu LTS on the amd64 architecture, as well as installation instructions from source code for other architectures and operating systems. Note In this documentation, all code blocks are commands you will need to type. They can be copy/pasted at once using the small copy button that appears on hover If you need help when installing your self-hosted cozy-stack environment, please ask us on our online forum , somebody will surely be able to help you and provide some more information. Also please tell us if you find any inaccuracy in this documentation so that we can fix it. Table of content \u00b6 Self hosting with docker Traditional installation Requirements What you need CouchDB NodeJS Installing cozy-stack Introduction Installing from precompiled package Installing from source Finalize installation Nginx and certificates Using Apache instead of Nginx Create your first instance Administration Create more instances Upgrade cozy-stack Configure mail sending Online edition of office documents Next -->", "title": "Introduction"}, {"location": "tutorials/selfhosting/#self-hosting", "text": "", "title": "Self-Hosting"}, {"location": "tutorials/selfhosting/#introduction", "text": "Cozycloud offers an hosted service on a freemium model. You can discover it freely and upgrade your offer to suit your needs. We are commited to protect your data and respect your privacy and are convinced that \u201cYou Will Stay Because You Can Leave\u201d. The cozycloud source code is publicly available to be audited and you can decide to host it yourself or ask someone else you trust to host your cozy. This documentation explains how to self host your cozy instance on your own server. You can choose either a traditioinal install on your server or to host Cozy in a docker environment. Cozycloud provides precompiled packages for the last two major versions of Debian and Ubuntu LTS on the amd64 architecture, as well as installation instructions from source code for other architectures and operating systems. Note In this documentation, all code blocks are commands you will need to type. They can be copy/pasted at once using the small copy button that appears on hover If you need help when installing your self-hosted cozy-stack environment, please ask us on our online forum , somebody will surely be able to help you and provide some more information. Also please tell us if you find any inaccuracy in this documentation so that we can fix it.", "title": "Introduction"}, {"location": "tutorials/selfhosting/#table-of-content", "text": "Self hosting with docker Traditional installation Requirements What you need CouchDB NodeJS Installing cozy-stack Introduction Installing from precompiled package Installing from source Finalize installation Nginx and certificates Using Apache instead of Nginx Create your first instance Administration Create more instances Upgrade cozy-stack Configure mail sending Online edition of office documents Next -->", "title": "Table of content"}, {"location": "tutorials/selfhosting/administration/", "text": "Administration topics \u00b6 The following documentations explain some administration topics: Create more than one instance Upgrade cozy-stack Configure mail sending Install and activate online office document edition", "title": "Index"}, {"location": "tutorials/selfhosting/administration/#administration-topics", "text": "The following documentations explain some administration topics: Create more than one instance Upgrade cozy-stack Configure mail sending Install and activate online office document edition", "title": "Administration topics"}, {"location": "tutorials/selfhosting/administration/mail/", "text": "Configuring cozy-stack to send mail \u00b6 Sometimes, cozy-stack needs to send mail. For example, when you share documents to another cozy, the recipient of the sharing will be notified by email. For cozy-stack to be able to send email, it must be configured to know how to join a mail transport agent to send email. Mail transport agent (MTA) \u00b6 First, you need a mail transport agent (SMTP server) for sending mail. You can use either a local mail transport agent on the local server running cozy-stack, a remote mail transport agent on another server you manage or register for a mail sending service offering SMTP relay service. In all cases, you will need the following information: SMTP host SMTP port Encryption to use. Either plain SMTP (no encryption), STARTTLS over SMTP or SMTP over TLS/SSL In case you need authentication, you will also need username and password SMTP local name to use when talking to SMTP server (usually you server\u2019s Fully qualified domain name) Warning When using a local mail transport agent, be sure that your hosting provider let your server send outgoing emails. This is usually disabled by your hosting provider by default and should be enabled to let email get out of your server. Refer to your hosting provider documentation on how to allow outgoing email. Installing a local MTA \u00b6 When installing a local Mail Transport Agent, we recommand using postfix. Other mail transport agent software are suitable too, but we will let you handle their configuration. sudo apt update && sudo apt install postfix When installing postfix, choose the following answers when asked for an outgoing only mail transport agent: Configuration type: Internet site System mail name: The Fully Qualified Domain name of your server Then configure postfix to only listen incoming connexions from local server: postconf inet_interfaces = loopback-only postconf mydestination = '$myhostname, localhost.localdomain, localhost' systemctl restart postfix Configuring cozy-stack \u00b6 Mail sending configuration should ba added at the end of the /etc/cozy/cozy.yml.local configuration file. Its content depends on the encryption cozy-stack will use to talk to you mail transport agent. While encryption is not required when running cozy-stack and a local MTA on the same server, we recommend to encrypt communication between cozy-stack and a remote MTA. Below are some examples of mail configuration for cozy-stack. Choose one, copy it at the end of the /etc/cozy/.cozy.yml.local file and adapt it to your needs Local MTA on port 25 (SMTP), no encryption, no authentication \u00b6 This is the default configuration when no mail configuration has been done starting from cozy-stack version 1.6.15 mail : host : localhost port : 25 # No encryption disable_tls : true Remote MTA on submission port using STARTTLS and authentication \u00b6 mail : host : smtp.domain.example port : 587 # Authentication username : myusername password : P@ssword # Use STARTTLS, not native TLS/SSL disable_tls : false use_ssl : false skip_certificate_validation : false # Hostname sent to the SMTP server with the HELO command local_name : myserver.domain.example Remote MTA on submissions port using native TLS/SSL and authentication \u00b6 mail : host : smtp.domain.example port : 465 # Authentication username : myusername password : P@ssword # Use Native TLS/SSL disable_tls : false use_ssl : true skip_certificate_validation : false # Hostname sent to the SMTP server with the HELO command local_name : myserver.domain.example Restarting cozy-stack to use new configuration \u00b6 Don\u2019t forget to restart cozy-stack after having modified cozy.yml.local systemctl restart cozy-stack Index ^", "title": "Configure mail sending"}, {"location": "tutorials/selfhosting/administration/mail/#configuring-cozy-stack-to-send-mail", "text": "Sometimes, cozy-stack needs to send mail. For example, when you share documents to another cozy, the recipient of the sharing will be notified by email. For cozy-stack to be able to send email, it must be configured to know how to join a mail transport agent to send email.", "title": "Configuring cozy-stack to send mail"}, {"location": "tutorials/selfhosting/administration/mail/#mail-transport-agent-mta", "text": "First, you need a mail transport agent (SMTP server) for sending mail. You can use either a local mail transport agent on the local server running cozy-stack, a remote mail transport agent on another server you manage or register for a mail sending service offering SMTP relay service. In all cases, you will need the following information: SMTP host SMTP port Encryption to use. Either plain SMTP (no encryption), STARTTLS over SMTP or SMTP over TLS/SSL In case you need authentication, you will also need username and password SMTP local name to use when talking to SMTP server (usually you server\u2019s Fully qualified domain name) Warning When using a local mail transport agent, be sure that your hosting provider let your server send outgoing emails. This is usually disabled by your hosting provider by default and should be enabled to let email get out of your server. Refer to your hosting provider documentation on how to allow outgoing email.", "title": "Mail transport agent (MTA)"}, {"location": "tutorials/selfhosting/administration/mail/#installing-a-local-mta", "text": "When installing a local Mail Transport Agent, we recommand using postfix. Other mail transport agent software are suitable too, but we will let you handle their configuration. sudo apt update && sudo apt install postfix When installing postfix, choose the following answers when asked for an outgoing only mail transport agent: Configuration type: Internet site System mail name: The Fully Qualified Domain name of your server Then configure postfix to only listen incoming connexions from local server: postconf inet_interfaces = loopback-only postconf mydestination = '$myhostname, localhost.localdomain, localhost' systemctl restart postfix", "title": "Installing a local MTA"}, {"location": "tutorials/selfhosting/administration/mail/#configuring-cozy-stack", "text": "Mail sending configuration should ba added at the end of the /etc/cozy/cozy.yml.local configuration file. Its content depends on the encryption cozy-stack will use to talk to you mail transport agent. While encryption is not required when running cozy-stack and a local MTA on the same server, we recommend to encrypt communication between cozy-stack and a remote MTA. Below are some examples of mail configuration for cozy-stack. Choose one, copy it at the end of the /etc/cozy/.cozy.yml.local file and adapt it to your needs", "title": "Configuring cozy-stack"}, {"location": "tutorials/selfhosting/administration/mail/#local-mta-on-port-25-smtp-no-encryption-no-authentication", "text": "This is the default configuration when no mail configuration has been done starting from cozy-stack version 1.6.15 mail : host : localhost port : 25 # No encryption disable_tls : true", "title": "Local MTA on port 25 (SMTP), no encryption, no authentication"}, {"location": "tutorials/selfhosting/administration/mail/#remote-mta-on-submission-port-using-starttls-and-authentication", "text": "mail : host : smtp.domain.example port : 587 # Authentication username : myusername password : P@ssword # Use STARTTLS, not native TLS/SSL disable_tls : false use_ssl : false skip_certificate_validation : false # Hostname sent to the SMTP server with the HELO command local_name : myserver.domain.example", "title": "Remote MTA on submission port using STARTTLS and authentication"}, {"location": "tutorials/selfhosting/administration/mail/#remote-mta-on-submissions-port-using-native-tlsssl-and-authentication", "text": "mail : host : smtp.domain.example port : 465 # Authentication username : myusername password : P@ssword # Use Native TLS/SSL disable_tls : false use_ssl : true skip_certificate_validation : false # Hostname sent to the SMTP server with the HELO command local_name : myserver.domain.example", "title": "Remote MTA on submissions port using native TLS/SSL and authentication"}, {"location": "tutorials/selfhosting/administration/mail/#restarting-cozy-stack-to-use-new-configuration", "text": "Don\u2019t forget to restart cozy-stack after having modified cozy.yml.local systemctl restart cozy-stack Index ^", "title": "Restarting cozy-stack to use new configuration"}, {"location": "tutorials/selfhosting/administration/more_instances/", "text": "Hosting more than one Cozy instance on the same server \u00b6 Having its own selfhosted Cozy instance is nice but hosting Cozy instances for friends and family is a must! Here is how to add more Cozy instances on the same server. The first Cozy instance we added was https://cozy.domain.example . We will create a second Cozy instance for Mary with address https://mary.domain.example (Replace domain.example with your own domain name and mary with what you want to uniquely identify the Cozy instance. So we will need: Our domain name. We still use domain.example in this documentation The new Cozy instance\u2019s \u201cslug\u201d, which is its unique identifier. We will use mary here for example. The address for this new Cozy instance will the be in the form https://. , for example here https://mary.domain.example First, let\u2019s put all that important information in variables: DOMAIN=domain.example EMAIL= NEWSLUG=mary NEWEMAIL= Create DNS entries for this Cozy instance. For example: mary 1h IN A *.mary 1h IN CNAME mary Create Nginx base configuration for this Cozy instance: cat < /dev/null server { listen 80; listen [::]:80; root /var/www/html; server_name *. ${ NEWSLUG } . ${ DOMAIN } ${ NEWSLUG } . ${ DOMAIN } ; access_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .error.log; location /.well-known { alias /var/www/html/.well-known; } location / { return 301 https://\\ $host \\ $request_uri ; } } EOF sudo ln -s ../sites-available/ ${ NEWSLUG } . ${ DOMAIN } /etc/nginx/sites-enabled/ sudo systemctl reload nginx Generate SSL certificate using certbot: sudo certbot certonly --email \" ${ EMAIL } \" --non-interactive --agree-tos --webroot -w /var/www/html -d ${ NEWSLUG } . ${ DOMAIN } $(printf -- \" -d %s. ${ NEWSLUG } . ${ DOMAIN } \" home banks contacts drive notes passwords photos settings store mespapiers) Finalize Nginx configuration: cat < /dev/null server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/letsencrypt/live/ ${ NEWSLUG } . ${ DOMAIN } /fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ ${ NEWSLUG } . ${ DOMAIN } /privkey.pem; server_name *. ${ NEWSLUG } . ${ DOMAIN } ${ NEWSLUG } . ${ DOMAIN } ; access_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .error.log; add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains;\"; client_max_body_size 1g; location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade \\ $http_upgrade ; proxy_set_header Connection \"upgrade\"; proxy_set_header Host \\ $host ; proxy_set_header X-Forwarded-For \\ $remote_addr ; } } EOF sudo systemctl reload nginx Create Cozy instance: [[ -z \" ${ COZY_PASS } \" ]] && read -p \"Cozy stack admin password: \" -r -s COZY_PASS sudo COZY_ADMIN_PASSWORD=\" ${ COZY_PASS } \" cozy-stack instances add --apps home,banks,contacts,drive,notes,passwords,photos,settings,store --email \" ${ NEWEMAIL } \" --locale fr --tz \"Europe/Paris\" ${ NEWSLUG } . ${ DOMAIN } Note the \u201cRegistration token\u201d the last command gives you and send Mary the following url: https://mary.domain.example?registerToken= , substituting domain.example with your own domain name, mary with the slug you chose for this new instance and with the \u201cRegistration token\u201d returned by the last command. By visiting this address with her browser, Mary will be able to define its password and start using her Cozy. Index ^", "title": "Create more instances"}, {"location": "tutorials/selfhosting/administration/more_instances/#hosting-more-than-one-cozy-instance-on-the-same-server", "text": "Having its own selfhosted Cozy instance is nice but hosting Cozy instances for friends and family is a must! Here is how to add more Cozy instances on the same server. The first Cozy instance we added was https://cozy.domain.example . We will create a second Cozy instance for Mary with address https://mary.domain.example (Replace domain.example with your own domain name and mary with what you want to uniquely identify the Cozy instance. So we will need: Our domain name. We still use domain.example in this documentation The new Cozy instance\u2019s \u201cslug\u201d, which is its unique identifier. We will use mary here for example. The address for this new Cozy instance will the be in the form https://. , for example here https://mary.domain.example First, let\u2019s put all that important information in variables: DOMAIN=domain.example EMAIL= NEWSLUG=mary NEWEMAIL= Create DNS entries for this Cozy instance. For example: mary 1h IN A *.mary 1h IN CNAME mary Create Nginx base configuration for this Cozy instance: cat < /dev/null server { listen 80; listen [::]:80; root /var/www/html; server_name *. ${ NEWSLUG } . ${ DOMAIN } ${ NEWSLUG } . ${ DOMAIN } ; access_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .error.log; location /.well-known { alias /var/www/html/.well-known; } location / { return 301 https://\\ $host \\ $request_uri ; } } EOF sudo ln -s ../sites-available/ ${ NEWSLUG } . ${ DOMAIN } /etc/nginx/sites-enabled/ sudo systemctl reload nginx Generate SSL certificate using certbot: sudo certbot certonly --email \" ${ EMAIL } \" --non-interactive --agree-tos --webroot -w /var/www/html -d ${ NEWSLUG } . ${ DOMAIN } $(printf -- \" -d %s. ${ NEWSLUG } . ${ DOMAIN } \" home banks contacts drive notes passwords photos settings store mespapiers) Finalize Nginx configuration: cat < /dev/null server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/letsencrypt/live/ ${ NEWSLUG } . ${ DOMAIN } /fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ ${ NEWSLUG } . ${ DOMAIN } /privkey.pem; server_name *. ${ NEWSLUG } . ${ DOMAIN } ${ NEWSLUG } . ${ DOMAIN } ; access_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/ ${ NEWSLUG } . ${ DOMAIN } .error.log; add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains;\"; client_max_body_size 1g; location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade \\ $http_upgrade ; proxy_set_header Connection \"upgrade\"; proxy_set_header Host \\ $host ; proxy_set_header X-Forwarded-For \\ $remote_addr ; } } EOF sudo systemctl reload nginx Create Cozy instance: [[ -z \" ${ COZY_PASS } \" ]] && read -p \"Cozy stack admin password: \" -r -s COZY_PASS sudo COZY_ADMIN_PASSWORD=\" ${ COZY_PASS } \" cozy-stack instances add --apps home,banks,contacts,drive,notes,passwords,photos,settings,store --email \" ${ NEWEMAIL } \" --locale fr --tz \"Europe/Paris\" ${ NEWSLUG } . ${ DOMAIN } Note the \u201cRegistration token\u201d the last command gives you and send Mary the following url: https://mary.domain.example?registerToken= , substituting domain.example with your own domain name, mary with the slug you chose for this new instance and with the \u201cRegistration token\u201d returned by the last command. By visiting this address with her browser, Mary will be able to define its password and start using her Cozy. Index ^", "title": "Hosting more than one Cozy instance on the same server"}, {"location": "tutorials/selfhosting/administration/office/", "text": "Online edition of office documents \u00b6 Online office document edition functionality based on OnlyOffice is optional. You can use your Cozy without activating it. It let you edit your office documents online directly in your browser, however it requires more resources on your server. To activate this functionality, you need to install OnlyOffice document server and configure cozy-stack to access it. OnlyOffice document server can be installed on the same server or on another server at your convenience. This documentation explain how to install it on the same server. Define a password for PostgreSQL database \u00b6 Onlyoffice Documentserver uses a PostgreSQL database. You first need to define a password for onlyoffice to connect to PostgreSQL server database. Convenience variables \u00b6 We define here some convenience variables for all this page. They will be used below when installing and configuring Onlyoffice. First, we define a variable OO_DB_PASS which contain the password we just defined in last step. This password will be used when creating a database user for Onlyoffice. Replace OnlyOfficeDBP@ssw0rd below with the password you chose. OO_DB_PASS=OnlyOfficeDBP@ssw0rd Then we define the same variables we used when creating a cozy instance: The DOMAIN variable should contain your domain name, the one under which all cozy instances will be created The EMAIL variable should contain your email address (it will be used when generating the https certificate) DOMAIN=domain.example EMAIL=\"your.email@email.domain\" Onlyoffice \u00b6 Onlyoffice requires PostgreSQL and RabbitMQ so we will start by installing them. Install PostgreSQL and create database \u00b6 Install PostgreSQL database sudo apt update sudo apt install -y postgresql Create database and user for onlyoffice. sudo -i -u postgres psql -c \"CREATE DATABASE onlyoffice;\" sudo -i -u postgres psql -c \"CREATE USER onlyoffice WITH password ' ${ OO_DB_PASS } ';\" sudo -i -u postgres psql -c \"GRANT ALL privileges ON DATABASE onlyoffice TO onlyoffice;\" Check the version of PostgreSQL that is installed on your system. psql --version If you are using PostgreSQL 15 or above (on Debian 12 for example), you need to grant onlyoffice user the permission to create tables in the public schema sudo -i -u postgres psql -c \"GRANT CREATE ON SCHEMA public TO onlyoffice;\" onlyoffice Install RabbitMQ \u00b6 If you are installing onlyoffice on the same server as couchdb, stop couchdb before installing rabbitmq to avoid any interaction between CouchDB and rabbitMQ\u2019s installation scripts. Once rabbitMQ is installed, you can restart CouchDB without any problem. sudo systemctl stop couchdb.service || sudo snap stop couchdb sudo apt install -y rabbitmq-server sudo systemctl start couchdb.service || sudo snap start couchdb Install MS core fonts \u00b6 Note If using debian 12 and you didn\u2019t activate contrib sources already, activate contib sources cat < /dev/null Types: deb deb-src URIs: mirror+file:///etc/apt/mirrors/debian.list Suites: $(lsb_release -sc) $(lsb_release -sc)-updates $(lsb_release -sc)-backports Components: contrib EOF sudo apt update On all distribution, install Microsoft fonts sudo apt install -y ttf-mscorefonts-installer When asked, accept EULA Install Onlyoffice Documentserver \u00b6 Configure package repository curl -fsSL https://download.onlyoffice.com/GPG-KEY-ONLYOFFICE | sudo gpg --dearmor -o /usr/share/keyrings/onlyoffice.gpg echo \"deb [signed-by=/usr/share/keyrings/onlyoffice.gpg] https://download.onlyoffice.com/repo/debian squeeze main\" | sudo tee /etc/apt/sources.list.d/onlyoffice.list sudo apt update Install OnlyOffice Documentserver sudo apt install -y onlyoffice-documentserver jq When asked, enter the PostgreSQL database password we created in the first step of this page. Then restart Nginx sudo systemctl reload nginx Configure HTTPS for OnlyOffice \u00b6 Create a DNS entry for OnlyOffice targeting your server. This should be configured in the DNS server for your domain. For example: onlyoffice 1h IN A Generate SSL certificate: sudo bash /usr/bin/documentserver-letsencrypt.sh \" ${ EMAIL } \" \"onlyoffice. ${ DOMAIN } \" Configure onlyoffice: sudo cp -f /etc/onlyoffice/documentserver/nginx/ds-ssl.conf.tmpl /etc/onlyoffice/documentserver/nginx/ds.conf Add certificate path in file /etc/onlyoffice/documentserver/nginx/ds.conf sudo sed -ie 's,{{SSL_CERTIFICATE_PATH}},/etc/letsencrypt/live/onlyoffice.' ${ DOMAIN } '/fullchain.pem,' /etc/onlyoffice/documentserver/nginx/ds.conf sudo sed -ie 's,{{SSL_KEY_PATH}},/etc/letsencrypt/live/onlyoffice.' ${ DOMAIN } '/privkey.pem,' /etc/onlyoffice/documentserver/nginx/ds.conf Configure OnlyOffice for cozy-stack \u00b6 Then configure onlyoffice to work with cozy-stack sudo cat /etc/onlyoffice/documentserver/local.json | jq '. | .services.CoAuthoring.token.enable.browser=false | del(.storage) | .services.CoAuthoring.\"request-filtering-agent\".allowPrivateIPAddress=true | .services.CoAuthoring.\"request-filtering-agent\".allowMetaIPAddress=true' > /tmp/oolocal.json cat /tmp/oolocal.json | sudo tee /etc/onlyoffice/documentserver/local.json > /dev/null rm /tmp/oolocal.json Restart OnlyOffice and Nginx: sudo systemctl restart ds-converter.service ds-docservice.service ds-metrics.service nginx.service You can now test onlyoffice is accessible from your browser at https://onlyoffice.domain.example (replace domain.example with your domain name). Configure cozy-stack for OnlyOffice \u00b6 Update configuration file: cat < /dev/null office: default: onlyoffice_url: https://onlyoffice. ${ DOMAIN } / EOF INBOX_SECRET=\"$(sudo cat /etc/onlyoffice/documentserver/local.json | jq -r .services.CoAuthoring.secret.inbox.string)\" if [ \" ${ INBOX_SECRET } \" != \"null\" ]; then echo \" onlyoffice_inbox_secret: \\\" ${ INBOX_SECRET } \\\"\" | sudo tee -a /etc/cozy/cozy.yml.local > /dev/null; fi OUTBOX_SECRET=\"$(sudo cat /etc/onlyoffice/documentserver/local.json | jq -r .services.CoAuthoring.secret.outbox.string)\" if [ \" ${ OUTBOX_SECRET } \" != \"null\" ]; then echo \" onlyoffice_outbox_secret: \\\" ${ OUTBOX_SECRET } \\\"\" | sudo tee -a /etc/cozy/cozy.yml.local > /dev/null; fi Restart cozy-stack: sudo systemctl restart cozy-stack Activate functionality (give cozy-stack admin password when asked): read -p \"Cozy stack admin password: \" -r -s COZY_PASS sudo COZY_ADMIN_PASSWORD=\" ${ COZY_PASS } \" cozy-stack features defaults '{\"drive.office\": {\"enabled\": true, \"write\": true}}' You can now upload an office document in cozy-drive and start editing it online by clicking on it or start a new empty document from the \u201cNew document\u201d menu. Futher information \u00b6 The drive.office feature flag has other options for customising the experience with OnlyOffice: enabled : Enables OnlyOffice (OO) write : Gives the right to edit. Otherwise OO opens in read mode and a modal is displayed on editing actions to warn that the functionality is blocked defaultMode : By default, OO opens in read mode ( view ). It can be switched to edit with the edit value. touchScreen : Corresponds to Cozy mobile applications or a browser with a screen width of 1023px or less or a user-agent on an iOS or Android operating system enabled : Enable OnlyOffice (OO) readOnly : Disables edit mode. You can no longer create new documents, only open existing ones in read mode without an edit button mobile : Corresponds to the browser with a screen width of 768px or less defaultMode : By default, the opening mode is the same as the main defaultMode . It can be changed to either view reading or edit editing Example : { \"enabled\": true, \"write\": true, \"defaultMode\": \"view\" \"touchScreen\": { \"enabled\": true \"readOnly\": false }, \"mobile\": { \"defaultMode\": \"view\" } } Index ^", "title": "Online edition of office documents"}, {"location": "tutorials/selfhosting/administration/office/#online-edition-of-office-documents", "text": "Online office document edition functionality based on OnlyOffice is optional. You can use your Cozy without activating it. It let you edit your office documents online directly in your browser, however it requires more resources on your server. To activate this functionality, you need to install OnlyOffice document server and configure cozy-stack to access it. OnlyOffice document server can be installed on the same server or on another server at your convenience. This documentation explain how to install it on the same server.", "title": "Online edition of office documents"}, {"location": "tutorials/selfhosting/administration/office/#define-a-password-for-postgresql-database", "text": "Onlyoffice Documentserver uses a PostgreSQL database. You first need to define a password for onlyoffice to connect to PostgreSQL server database.", "title": "Define a password for PostgreSQL database"}, {"location": "tutorials/selfhosting/administration/office/#convenience-variables", "text": "We define here some convenience variables for all this page. They will be used below when installing and configuring Onlyoffice. First, we define a variable OO_DB_PASS which contain the password we just defined in last step. This password will be used when creating a database user for Onlyoffice. Replace OnlyOfficeDBP@ssw0rd below with the password you chose. OO_DB_PASS=OnlyOfficeDBP@ssw0rd Then we define the same variables we used when creating a cozy instance: The DOMAIN variable should contain your domain name, the one under which all cozy instances will be created The EMAIL variable should contain your email address (it will be used when generating the https certificate) DOMAIN=domain.example EMAIL=\"your.email@email.domain\"", "title": "Convenience variables"}, {"location": "tutorials/selfhosting/administration/office/#onlyoffice", "text": "Onlyoffice requires PostgreSQL and RabbitMQ so we will start by installing them.", "title": "Onlyoffice"}, {"location": "tutorials/selfhosting/administration/office/#install-postgresql-and-create-database", "text": "Install PostgreSQL database sudo apt update sudo apt install -y postgresql Create database and user for onlyoffice. sudo -i -u postgres psql -c \"CREATE DATABASE onlyoffice;\" sudo -i -u postgres psql -c \"CREATE USER onlyoffice WITH password ' ${ OO_DB_PASS } ';\" sudo -i -u postgres psql -c \"GRANT ALL privileges ON DATABASE onlyoffice TO onlyoffice;\" Check the version of PostgreSQL that is installed on your system. psql --version If you are using PostgreSQL 15 or above (on Debian 12 for example), you need to grant onlyoffice user the permission to create tables in the public schema sudo -i -u postgres psql -c \"GRANT CREATE ON SCHEMA public TO onlyoffice;\" onlyoffice", "title": "Install PostgreSQL and create database"}, {"location": "tutorials/selfhosting/administration/office/#install-rabbitmq", "text": "If you are installing onlyoffice on the same server as couchdb, stop couchdb before installing rabbitmq to avoid any interaction between CouchDB and rabbitMQ\u2019s installation scripts. Once rabbitMQ is installed, you can restart CouchDB without any problem. sudo systemctl stop couchdb.service || sudo snap stop couchdb sudo apt install -y rabbitmq-server sudo systemctl start couchdb.service || sudo snap start couchdb", "title": "Install RabbitMQ"}, {"location": "tutorials/selfhosting/administration/office/#install-ms-core-fonts", "text": "Note If using debian 12 and you didn\u2019t activate contrib sources already, activate contib sources cat < /dev/null Types: deb deb-src URIs: mirror+file:///etc/apt/mirrors/debian.list Suites: $(lsb_release -sc) $(lsb_release -sc)-updates $(lsb_release -sc)-backports Components: contrib EOF sudo apt update On all distribution, install Microsoft fonts sudo apt install -y ttf-mscorefonts-installer When asked, accept EULA", "title": "Install MS core fonts"}, {"location": "tutorials/selfhosting/administration/office/#install-onlyoffice-documentserver", "text": "Configure package repository curl -fsSL https://download.onlyoffice.com/GPG-KEY-ONLYOFFICE | sudo gpg --dearmor -o /usr/share/keyrings/onlyoffice.gpg echo \"deb [signed-by=/usr/share/keyrings/onlyoffice.gpg] https://download.onlyoffice.com/repo/debian squeeze main\" | sudo tee /etc/apt/sources.list.d/onlyoffice.list sudo apt update Install OnlyOffice Documentserver sudo apt install -y onlyoffice-documentserver jq When asked, enter the PostgreSQL database password we created in the first step of this page. Then restart Nginx sudo systemctl reload nginx", "title": "Install Onlyoffice Documentserver"}, {"location": "tutorials/selfhosting/administration/office/#configure-https-for-onlyoffice", "text": "Create a DNS entry for OnlyOffice targeting your server. This should be configured in the DNS server for your domain. For example: onlyoffice 1h IN A Generate SSL certificate: sudo bash /usr/bin/documentserver-letsencrypt.sh \" ${ EMAIL } \" \"onlyoffice. ${ DOMAIN } \" Configure onlyoffice: sudo cp -f /etc/onlyoffice/documentserver/nginx/ds-ssl.conf.tmpl /etc/onlyoffice/documentserver/nginx/ds.conf Add certificate path in file /etc/onlyoffice/documentserver/nginx/ds.conf sudo sed -ie 's,{{SSL_CERTIFICATE_PATH}},/etc/letsencrypt/live/onlyoffice.' ${ DOMAIN } '/fullchain.pem,' /etc/onlyoffice/documentserver/nginx/ds.conf sudo sed -ie 's,{{SSL_KEY_PATH}},/etc/letsencrypt/live/onlyoffice.' ${ DOMAIN } '/privkey.pem,' /etc/onlyoffice/documentserver/nginx/ds.conf", "title": "Configure HTTPS for OnlyOffice"}, {"location": "tutorials/selfhosting/administration/office/#configure-onlyoffice-for-cozy-stack", "text": "Then configure onlyoffice to work with cozy-stack sudo cat /etc/onlyoffice/documentserver/local.json | jq '. | .services.CoAuthoring.token.enable.browser=false | del(.storage) | .services.CoAuthoring.\"request-filtering-agent\".allowPrivateIPAddress=true | .services.CoAuthoring.\"request-filtering-agent\".allowMetaIPAddress=true' > /tmp/oolocal.json cat /tmp/oolocal.json | sudo tee /etc/onlyoffice/documentserver/local.json > /dev/null rm /tmp/oolocal.json Restart OnlyOffice and Nginx: sudo systemctl restart ds-converter.service ds-docservice.service ds-metrics.service nginx.service You can now test onlyoffice is accessible from your browser at https://onlyoffice.domain.example (replace domain.example with your domain name).", "title": "Configure OnlyOffice for cozy-stack"}, {"location": "tutorials/selfhosting/administration/office/#configure-cozy-stack-for-onlyoffice", "text": "Update configuration file: cat < /dev/null office: default: onlyoffice_url: https://onlyoffice. ${ DOMAIN } / EOF INBOX_SECRET=\"$(sudo cat /etc/onlyoffice/documentserver/local.json | jq -r .services.CoAuthoring.secret.inbox.string)\" if [ \" ${ INBOX_SECRET } \" != \"null\" ]; then echo \" onlyoffice_inbox_secret: \\\" ${ INBOX_SECRET } \\\"\" | sudo tee -a /etc/cozy/cozy.yml.local > /dev/null; fi OUTBOX_SECRET=\"$(sudo cat /etc/onlyoffice/documentserver/local.json | jq -r .services.CoAuthoring.secret.outbox.string)\" if [ \" ${ OUTBOX_SECRET } \" != \"null\" ]; then echo \" onlyoffice_outbox_secret: \\\" ${ OUTBOX_SECRET } \\\"\" | sudo tee -a /etc/cozy/cozy.yml.local > /dev/null; fi Restart cozy-stack: sudo systemctl restart cozy-stack Activate functionality (give cozy-stack admin password when asked): read -p \"Cozy stack admin password: \" -r -s COZY_PASS sudo COZY_ADMIN_PASSWORD=\" ${ COZY_PASS } \" cozy-stack features defaults '{\"drive.office\": {\"enabled\": true, \"write\": true}}' You can now upload an office document in cozy-drive and start editing it online by clicking on it or start a new empty document from the \u201cNew document\u201d menu.", "title": "Configure cozy-stack for OnlyOffice"}, {"location": "tutorials/selfhosting/administration/office/#futher-information", "text": "The drive.office feature flag has other options for customising the experience with OnlyOffice: enabled : Enables OnlyOffice (OO) write : Gives the right to edit. Otherwise OO opens in read mode and a modal is displayed on editing actions to warn that the functionality is blocked defaultMode : By default, OO opens in read mode ( view ). It can be switched to edit with the edit value. touchScreen : Corresponds to Cozy mobile applications or a browser with a screen width of 1023px or less or a user-agent on an iOS or Android operating system enabled : Enable OnlyOffice (OO) readOnly : Disables edit mode. You can no longer create new documents, only open existing ones in read mode without an edit button mobile : Corresponds to the browser with a screen width of 768px or less defaultMode : By default, the opening mode is the same as the main defaultMode . It can be changed to either view reading or edit editing Example : { \"enabled\": true, \"write\": true, \"defaultMode\": \"view\" \"touchScreen\": { \"enabled\": true \"readOnly\": false }, \"mobile\": { \"defaultMode\": \"view\" } } Index ^", "title": "Futher information"}, {"location": "tutorials/selfhosting/administration/upgrade/", "text": "Upgrading cozy-stack \u00b6 Applications inside your Cozy are automatically updated, however, cozy-stack application running on your server must be updated from time to time (once every 3 month is a good compromise between too much and too few). Upgrading cozy-stack ensure you get new features and security improvements. The way to update cozy-stack differ wether you installed it from precompiled package or from sources. Upgading precompiled package \u00b6 sudo apt update sudo apt install --only-upgrade cozy-stack Upgrading from sources \u00b6 Update source code: cd /opt/cozy-stack git pull compile source code: cd /opt/cozy-stack scripts/build.sh release $(go env GOPATH)/bin/cozy-stack You can test compilation produced a valid binary with: $(go env GOPATH)/bin/cozy-stack version This command should respond with the compiled cozy-stack version, like 1.6.14-36-ge4577c7ff Install new generated binary: sudo install -o root -g root -m 0755 -T \\ $(go env GOPATH)/bin/cozy-stack /usr/bin/cozy-stack Restart cozy-stack: sudo systemctl restart cozy-stack Check out installation documentation and adjust your cozy-stack configuration if needed. Et voil\u00e0, you just upgraded cozy-stack to the latest version. pretty easy. Index ^", "title": "Upgrade cozy-stack"}, {"location": "tutorials/selfhosting/administration/upgrade/#upgrading-cozy-stack", "text": "Applications inside your Cozy are automatically updated, however, cozy-stack application running on your server must be updated from time to time (once every 3 month is a good compromise between too much and too few). Upgrading cozy-stack ensure you get new features and security improvements. The way to update cozy-stack differ wether you installed it from precompiled package or from sources.", "title": "Upgrading cozy-stack"}, {"location": "tutorials/selfhosting/administration/upgrade/#upgading-precompiled-package", "text": "sudo apt update sudo apt install --only-upgrade cozy-stack", "title": "Upgading precompiled package"}, {"location": "tutorials/selfhosting/administration/upgrade/#upgrading-from-sources", "text": "Update source code: cd /opt/cozy-stack git pull compile source code: cd /opt/cozy-stack scripts/build.sh release $(go env GOPATH)/bin/cozy-stack You can test compilation produced a valid binary with: $(go env GOPATH)/bin/cozy-stack version This command should respond with the compiled cozy-stack version, like 1.6.14-36-ge4577c7ff Install new generated binary: sudo install -o root -g root -m 0755 -T \\ $(go env GOPATH)/bin/cozy-stack /usr/bin/cozy-stack Restart cozy-stack: sudo systemctl restart cozy-stack Check out installation documentation and adjust your cozy-stack configuration if needed. Et voil\u00e0, you just upgraded cozy-stack to the latest version. pretty easy. Index ^", "title": "Upgrading from sources"}, {"location": "tutorials/selfhosting/docker/", "text": "Running Cozy inside Docker \u00b6 Introduction \u00b6 Cozycloud publish the cozy/cozy-stack docker production image to run the cozy-stack inside a docker container. It comes with everything bundled and preconfigured: cozy-stack backend server asynchronous konnector and services execution preconfigured PDF and SVG thumbnail generation Mail relay \u2026 Cozycloud also publish a docker-compose onfiguration to automatically setup a whole Cozy hosting infrastructure inside docker for selfhosting purposes with a CouchDB database as well as a frontend reverse proxy with on-demand TLS (automatic TLS certificate issuance). This guide will help you selfhost your Cozy inside docker with docker-compose. Requirements \u00b6 First you need a working docker installation with compose plugin. Plense refer to official Docker installation guide for detailed instructions. If you don\u2019t work as root, add your unpriviledged user to the docker group. Refer to docker documentation on how to manage docker as a non-root user Note docker-compose comes in two flavor. The first, v1, is a serapate python executable called docker-compose , the second, v2, is a plugin to the docker command called with docker compose (with a space instead of a dash between docker and compose ). In this documentation, we will use the newer docker compose version. If you still use the old separate executable, remplace all docker compose occurences with docker-compose You also need a domain name or a subdomain under which all your cozy instances will reside. For example, if you want all your cozy instances under the domain.example domain. Configure your domain to point to your server in your domain\u2019s DNS: @ IN A * IN A If you prefer tu use a subdomain of your main domain, in case you use it for anything else, simply create DNS entries pointing to your server for that subdomain. For exmaple if you want all your instances to be located under the cozy subdomain of your domain.example domain, you need to add a wildcard dns entry to your server like this: cozy IN A *.cozy IN A Clone cozy-stack docker-compose repository \u00b6 sudo git clone https://github.com/cozy/cozy-stack-compose.git /opt/cozy sudo chown -R ` whoami ` : /opt/cozy Configuration \u00b6 Copy the configuration file env.template file to .env cd /opt/cozy cp env.example .env and edit this .env file to configure your environment. You should at least edit the following variables: DOMAIN : The domain under which all your instances will be served. In our example, it\u2019s domain.example or cozy.domain.example if you use a subdomain. ACME_EMAIL : The email under which you want the TLS certificates to be issued with Let\u2019s Encrypt COUCHDB_PASSWORD : Generate and define a strong password for cozy-stack to connect to CouchDB COZY_ADMIN_PASSPHRASE : The cozy-stack administrative password. Generate and define a strong admin password. If unset a random password will be chosen and shown in stack logs. If you want cozy-stack cli to ask for the password everytime, you can undefine this variable and restart container after the first run Starting the environment \u00b6 You can then start with cd /opt/cozy docker-compose up -d Create instance \u00b6 To execute cozy-stack commands inside the docker container, you can use the provided cozy-stack.sh script that executes the cozy-stack command inside the docker container with provided arguments. You can execute any cozy-stack command by simply replacing cozy-stack with ./cozy-stack.sh For example: cd /opt/cozy ./cozy-stack.sh status To create your first instance: cd /opt/cozy ./cozy-stack.sh instances add \\ --apps home,banks,contacts,drive,notes,passwords,photos,settings,store \\ --email \"your.email@domain.example\" \\ --locale fr \\ --tz \"Europe/Paris\" \\ --passphrase YourStrongP@ssw0rd \\ myinstance.domain.example And then direct your browser to https://myinstance.domain.example . The first time you access an application it will take a handful of seconds for the Caddy reverse proxy to automatically generate the TLS certificate. All data will be stored in a volumes subdirectory. You can backup them. Going further \u00b6 Debugging \u00b6 You can list running containers with their state with cd /opt/cozy docker compose ps In case something gets wrong, you can access logs from docker compose. cozy-stack logs cd /opt/cozy docker compose logs stack Caddy reverse proxy cd /opt/cozy docker compose logs caddy CouchDB logs cd /opt/cozy docker compose logs couchdb Stopping environment \u00b6 Simply run cd /opt/cozy docker compose down Upgrading \u00b6 To upgrade to latest version, you need to stop the whole environment, pull the new images and restart it. Carefully plan the upgrade as it will lead to service interruption during the upgrade. cd /opt/cozy docker compose down git pull docker compose pull docker compose up -d", "title": "Running inside Docker"}, {"location": "tutorials/selfhosting/docker/#running-cozy-inside-docker", "text": "", "title": "Running Cozy inside Docker"}, {"location": "tutorials/selfhosting/docker/#introduction", "text": "Cozycloud publish the cozy/cozy-stack docker production image to run the cozy-stack inside a docker container. It comes with everything bundled and preconfigured: cozy-stack backend server asynchronous konnector and services execution preconfigured PDF and SVG thumbnail generation Mail relay \u2026 Cozycloud also publish a docker-compose onfiguration to automatically setup a whole Cozy hosting infrastructure inside docker for selfhosting purposes with a CouchDB database as well as a frontend reverse proxy with on-demand TLS (automatic TLS certificate issuance). This guide will help you selfhost your Cozy inside docker with docker-compose.", "title": "Introduction"}, {"location": "tutorials/selfhosting/docker/#requirements", "text": "First you need a working docker installation with compose plugin. Plense refer to official Docker installation guide for detailed instructions. If you don\u2019t work as root, add your unpriviledged user to the docker group. Refer to docker documentation on how to manage docker as a non-root user Note docker-compose comes in two flavor. The first, v1, is a serapate python executable called docker-compose , the second, v2, is a plugin to the docker command called with docker compose (with a space instead of a dash between docker and compose ). In this documentation, we will use the newer docker compose version. If you still use the old separate executable, remplace all docker compose occurences with docker-compose You also need a domain name or a subdomain under which all your cozy instances will reside. For example, if you want all your cozy instances under the domain.example domain. Configure your domain to point to your server in your domain\u2019s DNS: @ IN A * IN A If you prefer tu use a subdomain of your main domain, in case you use it for anything else, simply create DNS entries pointing to your server for that subdomain. For exmaple if you want all your instances to be located under the cozy subdomain of your domain.example domain, you need to add a wildcard dns entry to your server like this: cozy IN A *.cozy IN A ", "title": "Requirements"}, {"location": "tutorials/selfhosting/docker/#clone-cozy-stack-docker-compose-repository", "text": "sudo git clone https://github.com/cozy/cozy-stack-compose.git /opt/cozy sudo chown -R ` whoami ` : /opt/cozy", "title": "Clone cozy-stack docker-compose repository"}, {"location": "tutorials/selfhosting/docker/#configuration", "text": "Copy the configuration file env.template file to .env cd /opt/cozy cp env.example .env and edit this .env file to configure your environment. You should at least edit the following variables: DOMAIN : The domain under which all your instances will be served. In our example, it\u2019s domain.example or cozy.domain.example if you use a subdomain. ACME_EMAIL : The email under which you want the TLS certificates to be issued with Let\u2019s Encrypt COUCHDB_PASSWORD : Generate and define a strong password for cozy-stack to connect to CouchDB COZY_ADMIN_PASSPHRASE : The cozy-stack administrative password. Generate and define a strong admin password. If unset a random password will be chosen and shown in stack logs. If you want cozy-stack cli to ask for the password everytime, you can undefine this variable and restart container after the first run", "title": "Configuration"}, {"location": "tutorials/selfhosting/docker/#starting-the-environment", "text": "You can then start with cd /opt/cozy docker-compose up -d", "title": "Starting the environment"}, {"location": "tutorials/selfhosting/docker/#create-instance", "text": "To execute cozy-stack commands inside the docker container, you can use the provided cozy-stack.sh script that executes the cozy-stack command inside the docker container with provided arguments. You can execute any cozy-stack command by simply replacing cozy-stack with ./cozy-stack.sh For example: cd /opt/cozy ./cozy-stack.sh status To create your first instance: cd /opt/cozy ./cozy-stack.sh instances add \\ --apps home,banks,contacts,drive,notes,passwords,photos,settings,store \\ --email \"your.email@domain.example\" \\ --locale fr \\ --tz \"Europe/Paris\" \\ --passphrase YourStrongP@ssw0rd \\ myinstance.domain.example And then direct your browser to https://myinstance.domain.example . The first time you access an application it will take a handful of seconds for the Caddy reverse proxy to automatically generate the TLS certificate. All data will be stored in a volumes subdirectory. You can backup them.", "title": "Create instance"}, {"location": "tutorials/selfhosting/docker/#going-further", "text": "", "title": "Going further"}, {"location": "tutorials/selfhosting/docker/#debugging", "text": "You can list running containers with their state with cd /opt/cozy docker compose ps In case something gets wrong, you can access logs from docker compose. cozy-stack logs cd /opt/cozy docker compose logs stack Caddy reverse proxy cd /opt/cozy docker compose logs caddy CouchDB logs cd /opt/cozy docker compose logs couchdb", "title": "Debugging"}, {"location": "tutorials/selfhosting/docker/#stopping-environment", "text": "Simply run cd /opt/cozy docker compose down", "title": "Stopping environment"}, {"location": "tutorials/selfhosting/docker/#upgrading", "text": "To upgrade to latest version, you need to stop the whole environment, pull the new images and restart it. Carefully plan the upgrade as it will lead to service interruption during the upgrade. cd /opt/cozy docker compose down git pull docker compose pull docker compose up -d", "title": "Upgrading"}, {"location": "tutorials/selfhosting/finalize/apache/", "text": "Using Apache instead of nginx \u00b6 Note This page contains configuration for using apache as a reverse proxy instead of nginx. It only contains apache installation and configuration instructions and assume you have already managed to configure DNS entries as explained on nginx configuration page . Install Apache and Certbot: sudo apt install -y apache2 certbot We will first define some variables that will make life easier when issuing our SSL certificate and configuring apache (adjust the DOMAIN variable on the first line to your real domain name) DOMAIN=domain.example EMAIL=\"\" Each application in your Cozy will use a different sub-domain and so you need a certificate which include all needed domains. Generate SSL certificate with certbot: sudo certbot certonly --email \" ${ EMAIL } \" --non-interactive --agree-tos --webroot -w /var/www/html -d cozy. ${ DOMAIN } $(printf -- \" -d %s.cozy. ${ DOMAIN } \" home banks contacts drive notes passwords photos settings store mespapiers) Create apache reload script for your certificate to be reloaded each time it is automatically refreshed, every 3 months: cat < /dev/null #!/bin/bash apachectl configtest && apachectl graceful EOF sudo chmod 0755 /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh We will first define some variables that will make life easier when issuing our SSL certificate and configuring apache (adjust the DOMAIN variable on the first line to your real domain name) DOMAIN=domain.example EMAIL=\"\" Configure apache: cat < /dev/null ServerName cozy. ${ DOMAIN } ServerAlias *.cozy. ${ DOMAIN } ServerAdmin ${ EMAIL } DocumentRoot /var/www/html ErrorLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } _error.log CustomLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } access.log combined RewriteEngine on RewriteCond %{REQUEST_URI} !^/.well-known/.*$ [NC] RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] ServerName cozy. ${ DOMAIN } ServerAlias *.cozy. ${ DOMAIN } ServerAdmin ${ EMAIL } DocumentRoot /var/www/html ErrorLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } _error.log CustomLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } _access.log combined SSLEngine on SSLCertificateFile /etc/letsencrypt/live/cozy. ${ DOMAIN } /fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/cozy. ${ DOMAIN } /privkey.pem Header always set Strict-Transport-Security \"max-age=31536000; includeSubDomains;\" LimitRequestBody 1073741824 ProxyPass / http://127.0.0.1:8080/ retry=0 Keepalive=On timeout=1600 upgrade=websocket ProxyPassReverse / http://127.0.0.1:8080/ ProxyPreserveHost On EOF sudo a2ensite cozy. ${ DOMAIN } .conf Then enable required apache modules and restart apache sudo a2enmod ssl rewrite headers proxy proxy_http sudo systemctl restart apache2 You can then test from your browser by visiting https://cozy.domain.example and you should see a page telling you this Cozy instance doesn\u2019t exist yet. This is the sign that everything went well and the only part left is to create the instance. Next -->", "title": "Using Apache instead of Nginx"}, {"location": "tutorials/selfhosting/finalize/apache/#using-apache-instead-of-nginx", "text": "Note This page contains configuration for using apache as a reverse proxy instead of nginx. It only contains apache installation and configuration instructions and assume you have already managed to configure DNS entries as explained on nginx configuration page . Install Apache and Certbot: sudo apt install -y apache2 certbot We will first define some variables that will make life easier when issuing our SSL certificate and configuring apache (adjust the DOMAIN variable on the first line to your real domain name) DOMAIN=domain.example EMAIL=\"\" Each application in your Cozy will use a different sub-domain and so you need a certificate which include all needed domains. Generate SSL certificate with certbot: sudo certbot certonly --email \" ${ EMAIL } \" --non-interactive --agree-tos --webroot -w /var/www/html -d cozy. ${ DOMAIN } $(printf -- \" -d %s.cozy. ${ DOMAIN } \" home banks contacts drive notes passwords photos settings store mespapiers) Create apache reload script for your certificate to be reloaded each time it is automatically refreshed, every 3 months: cat < /dev/null #!/bin/bash apachectl configtest && apachectl graceful EOF sudo chmod 0755 /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh We will first define some variables that will make life easier when issuing our SSL certificate and configuring apache (adjust the DOMAIN variable on the first line to your real domain name) DOMAIN=domain.example EMAIL=\"\" Configure apache: cat < /dev/null ServerName cozy. ${ DOMAIN } ServerAlias *.cozy. ${ DOMAIN } ServerAdmin ${ EMAIL } DocumentRoot /var/www/html ErrorLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } _error.log CustomLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } access.log combined RewriteEngine on RewriteCond %{REQUEST_URI} !^/.well-known/.*$ [NC] RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] ServerName cozy. ${ DOMAIN } ServerAlias *.cozy. ${ DOMAIN } ServerAdmin ${ EMAIL } DocumentRoot /var/www/html ErrorLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } _error.log CustomLog ${ APACHE_LOG_DIR } /cozy. ${ DOMAIN } _access.log combined SSLEngine on SSLCertificateFile /etc/letsencrypt/live/cozy. ${ DOMAIN } /fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/cozy. ${ DOMAIN } /privkey.pem Header always set Strict-Transport-Security \"max-age=31536000; includeSubDomains;\" LimitRequestBody 1073741824 ProxyPass / http://127.0.0.1:8080/ retry=0 Keepalive=On timeout=1600 upgrade=websocket ProxyPassReverse / http://127.0.0.1:8080/ ProxyPreserveHost On EOF sudo a2ensite cozy. ${ DOMAIN } .conf Then enable required apache modules and restart apache sudo a2enmod ssl rewrite headers proxy proxy_http sudo systemctl restart apache2 You can then test from your browser by visiting https://cozy.domain.example and you should see a page telling you this Cozy instance doesn\u2019t exist yet. This is the sign that everything went well and the only part left is to create the instance. Next -->", "title": "Using Apache instead of nginx"}, {"location": "tutorials/selfhosting/finalize/create_instance/", "text": "Create your first cozy instance \u00b6 Create your First Cozy instance \u00b6 First define some variable you will need to configure your instance: The DOMAIN variable should contain your domain name, the one under which all cozy instances will be created The EMAIL variable should contain your email address (it will be used as a parameter of your cozy instance) DOMAIN=domain.example EMAIL=your.email@email.domain Then create the instance (you can of course adapt your language ( locale ) to choose english ( en ) or spanish ( es ) and choose another timezone ( tz )). sudo cozy-stack instances add \\ --apps home,banks,contacts,drive,notes,passwords,photos,settings,store \\ --email \" ${ EMAIL } \" \\ --locale fr \\ --tz \"Europe/Paris\" \\ cozy. ${ DOMAIN } Warning Instance creation can take up to 30 seconds without printing anything on screen. Please wait during creation and avoid stopping it in the middle or your instance will miss some important bits. In case something goes wrong, you can remove the instance with the following command before trying again sudo COZY_ADMIN_PASSWORD=\" ${ COZY_PASS } \" cozy-stack instances rm --force cozy. ${ DOMAIN } Note the \u201cRegistration token\u201d this command returns and visit from your browser https://cozy.domain.example?registerToken= substituting domain.example with your real domain name and with the \u201cRegistration token\u201d you got. You will be prompted to define your Cozy password and you will be able to start using your self-hosted Cozy. To create more instances, refer to the corresponding chapter of the administration guide Et voil\u00e0 ! \u00b6 Your Cozy is now fully operational! Its address is https://cozy.domain.example (remplace domain.example with your own domain name). You will find some quick start guides on our online support site . You can then start installing connectors from store to automatically gather your data, save your passwords in cozy-pass, store your files in cozy-drive and install cozy-desktop client on your PC to synchronize your Cozy content with a local folder. Administration section give more details on how to manage your installation. Next -->", "title": "Create first instance"}, {"location": "tutorials/selfhosting/finalize/create_instance/#create-your-first-cozy-instance", "text": "", "title": "Create your first cozy instance"}, {"location": "tutorials/selfhosting/finalize/create_instance/#create-your-first-cozy-instance_1", "text": "First define some variable you will need to configure your instance: The DOMAIN variable should contain your domain name, the one under which all cozy instances will be created The EMAIL variable should contain your email address (it will be used as a parameter of your cozy instance) DOMAIN=domain.example EMAIL=your.email@email.domain Then create the instance (you can of course adapt your language ( locale ) to choose english ( en ) or spanish ( es ) and choose another timezone ( tz )). sudo cozy-stack instances add \\ --apps home,banks,contacts,drive,notes,passwords,photos,settings,store \\ --email \" ${ EMAIL } \" \\ --locale fr \\ --tz \"Europe/Paris\" \\ cozy. ${ DOMAIN } Warning Instance creation can take up to 30 seconds without printing anything on screen. Please wait during creation and avoid stopping it in the middle or your instance will miss some important bits. In case something goes wrong, you can remove the instance with the following command before trying again sudo COZY_ADMIN_PASSWORD=\" ${ COZY_PASS } \" cozy-stack instances rm --force cozy. ${ DOMAIN } Note the \u201cRegistration token\u201d this command returns and visit from your browser https://cozy.domain.example?registerToken= substituting domain.example with your real domain name and with the \u201cRegistration token\u201d you got. You will be prompted to define your Cozy password and you will be able to start using your self-hosted Cozy. To create more instances, refer to the corresponding chapter of the administration guide", "title": "Create your First Cozy instance"}, {"location": "tutorials/selfhosting/finalize/create_instance/#et-voila", "text": "Your Cozy is now fully operational! Its address is https://cozy.domain.example (remplace domain.example with your own domain name). You will find some quick start guides on our online support site . You can then start installing connectors from store to automatically gather your data, save your passwords in cozy-pass, store your files in cozy-drive and install cozy-desktop client on your PC to synchronize your Cozy content with a local folder. Administration section give more details on how to manage your installation. Next -->", "title": "Et voil\u00e0 !"}, {"location": "tutorials/selfhosting/finalize/nginx/", "text": "Configure nginx and domain \u00b6 Cozy relies on sub-domains for each applications you installed on your instance. For an instance cozy.domain.example , .cozy.domain.example must be available too. Currently, you need at least: settings.cozy.domain.example drive.cozy.domain.example photos.cozy.domain.example home.cozy.domain.example store.cozy.domain.example .cozy.domain.example for each application you use Follow your usual way to create those entries on your domain zone. The simpliest way to handle this is to use a wildcard entry if supported by your domain hosting. First create a DNS entry in your domain for cozy.domain.example and *.cozy.domain.example pointing at your server. For example: cozy 1h IN A *.cozy 1h IN CNAME cozy Note If you prefer using Apache as a reverse proxy, please stop here and consult apache configuration page instead Then install Nginx and Certbot: sudo apt install -y nginx certbot We will first define some variables that will make life easier when issuing our SSL certificate and configuring nginx (adjust the DOMAIN variable on the first line to your real domain name) DOMAIN=domain.example EMAIL=\"\" Each application in your Cozy will use a different sub-domain and so you need a certificate which include all needed domains. Generate SSL certificate with certbot: sudo certbot certonly --email \" ${ EMAIL } \" --non-interactive --agree-tos --webroot -w /var/www/html -d cozy. ${ DOMAIN } $(printf -- \" -d %s.cozy. ${ DOMAIN } \" home banks contacts drive notes passwords photos settings store mespapiers) Create nginx reload script for your certificate to be reloaded each time it is automatically refreshed, every 3 months: cat < /dev/null #!/bin/bash nginx -t -q && nginx -s reload EOF sudo chmod 0755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh Configure nginx: cat < /dev/null log_format with_host '\\ $remote_addr \\ $host \\ $remote_user [\\ $time_local ] \"\\ $request \" ' '\\ $status \\ $body_bytes_sent \"\\ $http_referer \" ' '\"\\ $request_body \"' ; EOF cat < /dev/null server { listen 80; listen [::]:80; root /var/www/html; server_name *.cozy. ${ DOMAIN } cozy. ${ DOMAIN } ; access_log /var/log/nginx/cozy. ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/cozy. ${ DOMAIN } .error.log; location /.well-known { alias /var/www/html/.well-known; } location / { return 301 https://\\ $host \\ $request_uri ; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/letsencrypt/live/cozy. ${ DOMAIN } /fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cozy. ${ DOMAIN } /privkey.pem; server_name *.cozy. ${ DOMAIN } cozy. ${ DOMAIN } ; access_log /var/log/nginx/cozy. ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/cozy. ${ DOMAIN } .error.log; add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains;\"; client_max_body_size 1g; location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade \\ $http_upgrade ; proxy_set_header Connection \"upgrade\"; proxy_set_header Host \\ $host ; proxy_set_header X-Forwarded-For \\ $remote_addr ; } } EOF sudo ln -s ../sites-available/cozy. ${ DOMAIN } /etc/nginx/sites-enabled/ sudo systemctl reload nginx You can then test from your browser by visiting https://cozy.domain.example and you should see a page telling you this Cozy instance doesn\u2019t exist yet. This is the sign that everything went well and the only part left is to create the instance. Next -->", "title": "Nginx and certificates"}, {"location": "tutorials/selfhosting/finalize/nginx/#configure-nginx-and-domain", "text": "Cozy relies on sub-domains for each applications you installed on your instance. For an instance cozy.domain.example , .cozy.domain.example must be available too. Currently, you need at least: settings.cozy.domain.example drive.cozy.domain.example photos.cozy.domain.example home.cozy.domain.example store.cozy.domain.example .cozy.domain.example for each application you use Follow your usual way to create those entries on your domain zone. The simpliest way to handle this is to use a wildcard entry if supported by your domain hosting. First create a DNS entry in your domain for cozy.domain.example and *.cozy.domain.example pointing at your server. For example: cozy 1h IN A *.cozy 1h IN CNAME cozy Note If you prefer using Apache as a reverse proxy, please stop here and consult apache configuration page instead Then install Nginx and Certbot: sudo apt install -y nginx certbot We will first define some variables that will make life easier when issuing our SSL certificate and configuring nginx (adjust the DOMAIN variable on the first line to your real domain name) DOMAIN=domain.example EMAIL=\"\" Each application in your Cozy will use a different sub-domain and so you need a certificate which include all needed domains. Generate SSL certificate with certbot: sudo certbot certonly --email \" ${ EMAIL } \" --non-interactive --agree-tos --webroot -w /var/www/html -d cozy. ${ DOMAIN } $(printf -- \" -d %s.cozy. ${ DOMAIN } \" home banks contacts drive notes passwords photos settings store mespapiers) Create nginx reload script for your certificate to be reloaded each time it is automatically refreshed, every 3 months: cat < /dev/null #!/bin/bash nginx -t -q && nginx -s reload EOF sudo chmod 0755 /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh Configure nginx: cat < /dev/null log_format with_host '\\ $remote_addr \\ $host \\ $remote_user [\\ $time_local ] \"\\ $request \" ' '\\ $status \\ $body_bytes_sent \"\\ $http_referer \" ' '\"\\ $request_body \"' ; EOF cat < /dev/null server { listen 80; listen [::]:80; root /var/www/html; server_name *.cozy. ${ DOMAIN } cozy. ${ DOMAIN } ; access_log /var/log/nginx/cozy. ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/cozy. ${ DOMAIN } .error.log; location /.well-known { alias /var/www/html/.well-known; } location / { return 301 https://\\ $host \\ $request_uri ; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /etc/letsencrypt/live/cozy. ${ DOMAIN } /fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cozy. ${ DOMAIN } /privkey.pem; server_name *.cozy. ${ DOMAIN } cozy. ${ DOMAIN } ; access_log /var/log/nginx/cozy. ${ DOMAIN } .access.log with_host; error_log /var/log/nginx/cozy. ${ DOMAIN } .error.log; add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains;\"; client_max_body_size 1g; location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade \\ $http_upgrade ; proxy_set_header Connection \"upgrade\"; proxy_set_header Host \\ $host ; proxy_set_header X-Forwarded-For \\ $remote_addr ; } } EOF sudo ln -s ../sites-available/cozy. ${ DOMAIN } /etc/nginx/sites-enabled/ sudo systemctl reload nginx You can then test from your browser by visiting https://cozy.domain.example and you should see a page telling you this Cozy instance doesn\u2019t exist yet. This is the sign that everything went well and the only part left is to create the instance. Next -->", "title": "Configure nginx and domain"}, {"location": "tutorials/selfhosting/install/", "text": "Cozy-stack installation \u00b6 Cozycloud provides precompiled packages for the last two versions of Debian and Ubuntu LTS on amd64 architecture. Currently, precompiled packages are provided for Debian 11 Bullseye Debian 12 Bookworm Ubuntu 20.04 Focal Fossa Ubuntu 22.04 Jammy Jellyfish Ubuntu 24.04 Noble Numbat Precompiled packages install precompiled binaries of cozy-stack as well as configuration and system glue (log management, systemd unit for autostart at boot, \u2026) If you use one of the supported distribution, using precompiled package is the preferred way to go. There are also community provided precompiled packages for Arch Linux. Find out more on Arch linux wiki . If we don\u2019t provide precompiled package for your distribution or architecture and you can\u2019t find community precompiled packages, you can manually compile, install and configure cozy-stack from sources . Install from precompiled deb package for Debian and Ubuntu Install from Arch Linux precompiled community packages Install from sources on other distribution or architecture", "title": "Introduction"}, {"location": "tutorials/selfhosting/install/#cozy-stack-installation", "text": "Cozycloud provides precompiled packages for the last two versions of Debian and Ubuntu LTS on amd64 architecture. Currently, precompiled packages are provided for Debian 11 Bullseye Debian 12 Bookworm Ubuntu 20.04 Focal Fossa Ubuntu 22.04 Jammy Jellyfish Ubuntu 24.04 Noble Numbat Precompiled packages install precompiled binaries of cozy-stack as well as configuration and system glue (log management, systemd unit for autostart at boot, \u2026) If you use one of the supported distribution, using precompiled package is the preferred way to go. There are also community provided precompiled packages for Arch Linux. Find out more on Arch linux wiki . If we don\u2019t provide precompiled package for your distribution or architecture and you can\u2019t find community precompiled packages, you can manually compile, install and configure cozy-stack from sources . Install from precompiled deb package for Debian and Ubuntu Install from Arch Linux precompiled community packages Install from sources on other distribution or architecture", "title": "Cozy-stack installation"}, {"location": "tutorials/selfhosting/install/package/", "text": "Installing cozy-stack from precompiled package \u00b6 Cozy repositories \u00b6 First, configure cozy repositories on your system. sudo apt install ca-certificates apt-transport-https wget Then, fetch the GPG Cozy signing key: wget https://apt.cozy.io/cozy-keyring.deb -O /tmp/cozy-keyring.deb sudo dpkg -i /tmp/cozy-keyring.deb Finally, setup your repository. DISTRIB_ID = \" $( lsb_release -is ) \" DISTRIB_CODENAME = \" $( lsb_release -cs ) \" echo \"deb [signed-by=/usr/share/keyrings/cozy-keyring.gpg] https://apt.cozy.io/ ${ DISTRIB_ID ,, } / ${ DISTRIB_CODENAME } stable\" | sudo tee /etc/apt/sources.list.d/cozy.list > /dev/null sudo apt update Install cozy-stack \u00b6 The package installation needs to connect to CouchDB as an administrator to create a CouchDB user for cozy-stack. When installing the cozy-stack package, it will ask you a few questions, including passwords. Warning The passwords that you need to define are used in shell scripts so currently avoid to use one with simple or double quotes or others shell meaningfull symbols. We advise you to choose one with only alphanumeric characters to avoid trouble. You will need to fill those mandatory parameters: CouchDB Address: by default, it\u2019s 127.0.0.1:5984 CouchDB Node name: by default, it\u2019s couchdb@127.0.0.1 . This is needed to create a cozy user CouchDB Admin user: by default, it\u2019s admin CouchDB Admin password: put the one you choose during CouchDB setup CouchDB cozy user name: by default, it\u2019s cozy . This is the user that will get created in CouchDB and used by cozy-stack to access CouchDB CouchDB cozy user password: pick a password Cozy-stack admin passphrase: pick a password. This is the passphrase that will be needed to launch cozy-stack administrative commands For stack management (create instances, install applications\u2026), Cozy need an administrator password . So pick a new one. When invoking cozy-stack , you need to set the COZY_ADMIN_PASSWORD environment variable with this password. You can put it on your .bashrc for simplier life if you want. If you don\u2019t, cozy-stack will simply ask for it. Installing cozy-stack package is done with the following command: sudo apt install -y cozy-stack At this point, you should have a working Cozy stack, depending on the branch you\u2019ve chosen you can get a different version displayed. curl http://localhost:8080/version This command should give you cozy-stack installed version. For example: {\"build_mode\":\"production\",\"build_time\":\"2023-10-18T05:57:06Z\",\"runtime_version\":\"go1.21.3\",\"version\":\"2:1.6.13\"} Next -->", "title": "From precompiled package"}, {"location": "tutorials/selfhosting/install/package/#installing-cozy-stack-from-precompiled-package", "text": "", "title": "Installing cozy-stack from precompiled package"}, {"location": "tutorials/selfhosting/install/package/#cozy-repositories", "text": "First, configure cozy repositories on your system. sudo apt install ca-certificates apt-transport-https wget Then, fetch the GPG Cozy signing key: wget https://apt.cozy.io/cozy-keyring.deb -O /tmp/cozy-keyring.deb sudo dpkg -i /tmp/cozy-keyring.deb Finally, setup your repository. DISTRIB_ID = \" $( lsb_release -is ) \" DISTRIB_CODENAME = \" $( lsb_release -cs ) \" echo \"deb [signed-by=/usr/share/keyrings/cozy-keyring.gpg] https://apt.cozy.io/ ${ DISTRIB_ID ,, } / ${ DISTRIB_CODENAME } stable\" | sudo tee /etc/apt/sources.list.d/cozy.list > /dev/null sudo apt update", "title": "Cozy repositories"}, {"location": "tutorials/selfhosting/install/package/#install-cozy-stack", "text": "The package installation needs to connect to CouchDB as an administrator to create a CouchDB user for cozy-stack. When installing the cozy-stack package, it will ask you a few questions, including passwords. Warning The passwords that you need to define are used in shell scripts so currently avoid to use one with simple or double quotes or others shell meaningfull symbols. We advise you to choose one with only alphanumeric characters to avoid trouble. You will need to fill those mandatory parameters: CouchDB Address: by default, it\u2019s 127.0.0.1:5984 CouchDB Node name: by default, it\u2019s couchdb@127.0.0.1 . This is needed to create a cozy user CouchDB Admin user: by default, it\u2019s admin CouchDB Admin password: put the one you choose during CouchDB setup CouchDB cozy user name: by default, it\u2019s cozy . This is the user that will get created in CouchDB and used by cozy-stack to access CouchDB CouchDB cozy user password: pick a password Cozy-stack admin passphrase: pick a password. This is the passphrase that will be needed to launch cozy-stack administrative commands For stack management (create instances, install applications\u2026), Cozy need an administrator password . So pick a new one. When invoking cozy-stack , you need to set the COZY_ADMIN_PASSWORD environment variable with this password. You can put it on your .bashrc for simplier life if you want. If you don\u2019t, cozy-stack will simply ask for it. Installing cozy-stack package is done with the following command: sudo apt install -y cozy-stack At this point, you should have a working Cozy stack, depending on the branch you\u2019ve chosen you can get a different version displayed. curl http://localhost:8080/version This command should give you cozy-stack installed version. For example: {\"build_mode\":\"production\",\"build_time\":\"2023-10-18T05:57:06Z\",\"runtime_version\":\"go1.21.3\",\"version\":\"2:1.6.13\"} Next -->", "title": "Install cozy-stack"}, {"location": "tutorials/selfhosting/install/sources/", "text": "Installing cozy-stack from sources \u00b6 Go \u00b6 cozy-stack is developped in Go language so we need to install the Go compiler to be able to compile cozy-stack sources: wget -O /tmp/go1.21.3.linux-amd64.tar.gz https://go.dev/dl/go1.21.3.linux-amd64.tar.gz sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzvf /tmp/go1.21.3.linux-amd64.tar.gz echo \"export PATH=\\\"\\$PATH:/usr/local/go/bin\\\"\" | sudo tee /etc/profile.d/golang.sh > /dev/null source /etc/profile.d/golang.sh Test Go installation is fine with: go version This command should respond with something like go version go1.21.3 linux/amd64 Cozy-stack \u00b6 First, add a CouchDB user and password for cozy-stack (replace COUCH_ADMIN_PWD with your previously defined CouchdDB admin password) read - p \"Couchdb password for cozy user: \" - r - s COUCH_PASS curl - X PUT - u \"admin:COUCH_ADMIN_PWD\" \"http://localhost:5984/_node/couchdb@127.0.0.1/_config/admins/cozy\" -- data \" \\\" ${COUCH_PASS} \\\" \" Install requirements: sudo apt install -y imagemagick ghostscript librsvg2-bin libprotobuf-c1 fonts-lato Activate PDF thumbnail generation in ImageMagick sudo sed -ie 's,^ \\(\\)$, ,g' /etc/ImageMagick-6/policy.xml Get the source code: sudo apt install -y git sudo mkdir -p /opt/cozy-stack sudo chown ${ USER } : /opt/cozy-stack git -C /opt/cozy-stack init git -C /opt/cozy-stack remote add origin https://github.com/cozy/cozy-stack.git git -C /opt/cozy-stack fetch git -C /opt/cozy-stack pull origin master Then compile the program: cd /opt/cozy-stack scripts/build.sh release $(go env GOPATH)/bin/cozy-stack The compilation generate a binary file under $GOPATH/bin/cozy-stack You can test it with: $(go env GOPATH)/bin/cozy-stack version This command should respond with the compiled cozy-stack version, like 1.6.14-36-ge4577c7ff You then have to create a user to run cozy-stack: sudo addgroup --quiet --system cozy sudo adduser --quiet --system --home /var/lib/cozy \\ --no-create-home --shell /usr/sbin/nologin \\ --ingroup cozy cozy-stack And install it: sudo install -o root -g root -m 0755 -T \\ $(go env GOPATH)/bin/cozy-stack /usr/bin/cozy-stack sudo sh -c 'cozy-stack completion bash > /etc/bash_completion.d/cozy-stack' source /etc/bash_completion.d/cozy-stack sudo install -o root -g root -m 0755 -d /etc/cozy sudo install -o root -g cozy -m 0750 -d /var/log/cozy sudo install -o cozy-stack -g cozy -m 750 -d /usr/share/cozy sudo install -o cozy-stack -g cozy -m 750 \\ /opt/cozy-stack/scripts/konnector-node-run.sh \\ /usr/share/cozy/konnector-node-run.sh sudo install -o cozy-stack -g cozy -m 750 -d /var/lib/cozy And create configuration: read - p \"Cozy stack admin password: \" - r - s COZY_PASS sudo sh - c \"COZY_ADMIN_PASSPHRASE= \\\" ${COZY_PASS} \\\" cozy-stack config passwd /etc/cozy/cozy-admin-passphrase\" sudo chown cozy - stack : cozy / etc / cozy / cozy - admin - passphrase sudo cozy - stack config gen - keys / etc / cozy / vault sudo chown cozy - stack : cozy / etc / cozy / vault . enc / etc / cozy / vault . dec sudo chmod 0600 / etc / cozy / vault . enc / etc / cozy / vault . dec cat << EOF | sudo tee / etc / cozy / cozy . yml >/ dev / null host : 127.0.0.1 port : 8080 admin : host : 127.0.0.1 port : 6060 couchdb : url : http : //cozy:${COUCH_PASS}@127.0.0.1:5984/ fs : url : file : ///var/lib/cozy vault : credentials_encryptor_key : / etc / cozy / vault . enc credentials_decryptor_key : / etc / cozy / vault . dec konnectors : cmd : / usr / share / cozy / konnector - node - run . sh log : level : info syslog : true registries : default : - https : //apps-registry.cozycloud.cc/selfhosted - https : //apps-registry.cozycloud.cc/mespapiers - https : //apps-registry.cozycloud.cc/banks - https : //apps-registry.cozycloud.cc/ EOF sudo chown cozy - stack : cozy / etc / cozy / cozy . yml sudo chmod 0640 / etc / cozy / cozy . yml Finally, configure systemd to automatically launch cozy-stack on boot: cat </dev/null [Unit] Description=Cozy service Wants=couchdb.service After=network.target couchdb.service [Service] User=cozy-stack Group=cozy WorkingDirectory=/var/lib/cozy/ PermissionsStartOnly=true ExecStart=/usr/bin/cozy-stack serve Restart=always [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable cozy-stack sudo systemctl start cozy-stack You can validate everything went well and cozy-stack is running thiw way: curl http://localhost:8080/version This command should give you cozy-stack installed version. For example: {\"build_mode\":\"production\",\"build_time\":\"2023-11-15T15:57:06Z\",\"runtime_version\":\"go1.21.3\",\"version\":\"1.6.14-36-ge4577c7ff\"} Next -->", "title": "From sources"}, {"location": "tutorials/selfhosting/install/sources/#installing-cozy-stack-from-sources", "text": "", "title": "Installing cozy-stack from sources"}, {"location": "tutorials/selfhosting/install/sources/#go", "text": "cozy-stack is developped in Go language so we need to install the Go compiler to be able to compile cozy-stack sources: wget -O /tmp/go1.21.3.linux-amd64.tar.gz https://go.dev/dl/go1.21.3.linux-amd64.tar.gz sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzvf /tmp/go1.21.3.linux-amd64.tar.gz echo \"export PATH=\\\"\\$PATH:/usr/local/go/bin\\\"\" | sudo tee /etc/profile.d/golang.sh > /dev/null source /etc/profile.d/golang.sh Test Go installation is fine with: go version This command should respond with something like go version go1.21.3 linux/amd64", "title": "Go"}, {"location": "tutorials/selfhosting/install/sources/#cozy-stack", "text": "First, add a CouchDB user and password for cozy-stack (replace COUCH_ADMIN_PWD with your previously defined CouchdDB admin password) read - p \"Couchdb password for cozy user: \" - r - s COUCH_PASS curl - X PUT - u \"admin:COUCH_ADMIN_PWD\" \"http://localhost:5984/_node/couchdb@127.0.0.1/_config/admins/cozy\" -- data \" \\\" ${COUCH_PASS} \\\" \" Install requirements: sudo apt install -y imagemagick ghostscript librsvg2-bin libprotobuf-c1 fonts-lato Activate PDF thumbnail generation in ImageMagick sudo sed -ie 's,^ \\(\\)$, ,g' /etc/ImageMagick-6/policy.xml Get the source code: sudo apt install -y git sudo mkdir -p /opt/cozy-stack sudo chown ${ USER } : /opt/cozy-stack git -C /opt/cozy-stack init git -C /opt/cozy-stack remote add origin https://github.com/cozy/cozy-stack.git git -C /opt/cozy-stack fetch git -C /opt/cozy-stack pull origin master Then compile the program: cd /opt/cozy-stack scripts/build.sh release $(go env GOPATH)/bin/cozy-stack The compilation generate a binary file under $GOPATH/bin/cozy-stack You can test it with: $(go env GOPATH)/bin/cozy-stack version This command should respond with the compiled cozy-stack version, like 1.6.14-36-ge4577c7ff You then have to create a user to run cozy-stack: sudo addgroup --quiet --system cozy sudo adduser --quiet --system --home /var/lib/cozy \\ --no-create-home --shell /usr/sbin/nologin \\ --ingroup cozy cozy-stack And install it: sudo install -o root -g root -m 0755 -T \\ $(go env GOPATH)/bin/cozy-stack /usr/bin/cozy-stack sudo sh -c 'cozy-stack completion bash > /etc/bash_completion.d/cozy-stack' source /etc/bash_completion.d/cozy-stack sudo install -o root -g root -m 0755 -d /etc/cozy sudo install -o root -g cozy -m 0750 -d /var/log/cozy sudo install -o cozy-stack -g cozy -m 750 -d /usr/share/cozy sudo install -o cozy-stack -g cozy -m 750 \\ /opt/cozy-stack/scripts/konnector-node-run.sh \\ /usr/share/cozy/konnector-node-run.sh sudo install -o cozy-stack -g cozy -m 750 -d /var/lib/cozy And create configuration: read - p \"Cozy stack admin password: \" - r - s COZY_PASS sudo sh - c \"COZY_ADMIN_PASSPHRASE= \\\" ${COZY_PASS} \\\" cozy-stack config passwd /etc/cozy/cozy-admin-passphrase\" sudo chown cozy - stack : cozy / etc / cozy / cozy - admin - passphrase sudo cozy - stack config gen - keys / etc / cozy / vault sudo chown cozy - stack : cozy / etc / cozy / vault . enc / etc / cozy / vault . dec sudo chmod 0600 / etc / cozy / vault . enc / etc / cozy / vault . dec cat << EOF | sudo tee / etc / cozy / cozy . yml >/ dev / null host : 127.0.0.1 port : 8080 admin : host : 127.0.0.1 port : 6060 couchdb : url : http : //cozy:${COUCH_PASS}@127.0.0.1:5984/ fs : url : file : ///var/lib/cozy vault : credentials_encryptor_key : / etc / cozy / vault . enc credentials_decryptor_key : / etc / cozy / vault . dec konnectors : cmd : / usr / share / cozy / konnector - node - run . sh log : level : info syslog : true registries : default : - https : //apps-registry.cozycloud.cc/selfhosted - https : //apps-registry.cozycloud.cc/mespapiers - https : //apps-registry.cozycloud.cc/banks - https : //apps-registry.cozycloud.cc/ EOF sudo chown cozy - stack : cozy / etc / cozy / cozy . yml sudo chmod 0640 / etc / cozy / cozy . yml Finally, configure systemd to automatically launch cozy-stack on boot: cat </dev/null [Unit] Description=Cozy service Wants=couchdb.service After=network.target couchdb.service [Service] User=cozy-stack Group=cozy WorkingDirectory=/var/lib/cozy/ PermissionsStartOnly=true ExecStart=/usr/bin/cozy-stack serve Restart=always [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable cozy-stack sudo systemctl start cozy-stack You can validate everything went well and cozy-stack is running thiw way: curl http://localhost:8080/version This command should give you cozy-stack installed version. For example: {\"build_mode\":\"production\",\"build_time\":\"2023-11-15T15:57:06Z\",\"runtime_version\":\"go1.21.3\",\"version\":\"1.6.14-36-ge4577c7ff\"} Next -->", "title": "Cozy-stack"}, {"location": "tutorials/selfhosting/requirements/", "text": "What you need \u00b6 The installation procedure requires: A server to install cozy programs. If you plan to use precompiled packages, the server must run one of the last two versions of Debian or Ubuntu LTS. A domain name (mandatory to host Cozy instances secured with https and accessible from internet. This is a major security feature to isolate applications and avoid bypassing data access permissions). In this documentation, we will use domain.example as an example domain. You will replace it with your own domain name throughout the explanation. The address of your Cozy instance will be cozy.domain.example . Good system administration knowledge. Despite documentation\u2019s goal is to be pretty straightforward to follow, there are some tricky and technical parts. During installation, you will also need to define: a CouchDB administration password a CouchDB database access password a cozy-stack admin password You will need to provide your email address for Let\u2019s Encrypt SSL certificate validation and your Cozy instance creation You can already prepare these elements. Next -->", "title": "What you need"}, {"location": "tutorials/selfhosting/requirements/#what-you-need", "text": "The installation procedure requires: A server to install cozy programs. If you plan to use precompiled packages, the server must run one of the last two versions of Debian or Ubuntu LTS. A domain name (mandatory to host Cozy instances secured with https and accessible from internet. This is a major security feature to isolate applications and avoid bypassing data access permissions). In this documentation, we will use domain.example as an example domain. You will replace it with your own domain name throughout the explanation. The address of your Cozy instance will be cozy.domain.example . Good system administration knowledge. Despite documentation\u2019s goal is to be pretty straightforward to follow, there are some tricky and technical parts. During installation, you will also need to define: a CouchDB administration password a CouchDB database access password a cozy-stack admin password You will need to provide your email address for Let\u2019s Encrypt SSL certificate validation and your Cozy instance creation You can already prepare these elements. Next -->", "title": "What you need"}, {"location": "tutorials/selfhosting/requirements/couchdb-pkg/", "text": "Installing CouchDB from precompiled packages \u00b6 Configure CouchDB package repository: sudo apt update && sudo apt install -y curl apt-transport-https gnupg curl -fsSL https://couchdb.apache.org/repo/keys.asc | gpg --dearmor | sudo tee /usr/share/keyrings/couchdb-archive-keyring.gpg >/dev/null 2>&1 echo \"deb [signed-by=/usr/share/keyrings/couchdb-archive-keyring.gpg] https://apache.jfrog.io/artifactory/couchdb-deb/ $(lsb_release -sc) main\" | sudo tee /etc/apt/sources.list.d/couchdb.list >/dev/null Install Couchdb: sudo apt update sudo apt install -y couchdb During CouchDB installation, you need to answer a few questions: Choose Standalone mode Define a random erlang cookie (choose any random string, this is only used in multi-server cluster configuration) Define a couchdb admin password. Remember that password , you will need it later when installing cozy-stack. Validate CouchDB is working: curl http://127.0.0.1:5984/ The above command should give you something like {\"couchdb\":\"Welcome\",\"version\":\"3.2.1\",\"git_sha\":\"244d428af\",\"uuid\":\"f7b83554fa2eb43778963d18a1f92211\",\"features\":[\"access-ready\",\"partitioned\",\"pluggable-storage-engines\",\"reshard\",\"scheduler\"],\"vendor\":{\"name\":\"The Apache Software Foundation\"}} Next -->", "title": "Installing CouchDB from precompiled packages"}, {"location": "tutorials/selfhosting/requirements/couchdb-pkg/#installing-couchdb-from-precompiled-packages", "text": "Configure CouchDB package repository: sudo apt update && sudo apt install -y curl apt-transport-https gnupg curl -fsSL https://couchdb.apache.org/repo/keys.asc | gpg --dearmor | sudo tee /usr/share/keyrings/couchdb-archive-keyring.gpg >/dev/null 2>&1 echo \"deb [signed-by=/usr/share/keyrings/couchdb-archive-keyring.gpg] https://apache.jfrog.io/artifactory/couchdb-deb/ $(lsb_release -sc) main\" | sudo tee /etc/apt/sources.list.d/couchdb.list >/dev/null Install Couchdb: sudo apt update sudo apt install -y couchdb During CouchDB installation, you need to answer a few questions: Choose Standalone mode Define a random erlang cookie (choose any random string, this is only used in multi-server cluster configuration) Define a couchdb admin password. Remember that password , you will need it later when installing cozy-stack. Validate CouchDB is working: curl http://127.0.0.1:5984/ The above command should give you something like {\"couchdb\":\"Welcome\",\"version\":\"3.2.1\",\"git_sha\":\"244d428af\",\"uuid\":\"f7b83554fa2eb43778963d18a1f92211\",\"features\":[\"access-ready\",\"partitioned\",\"pluggable-storage-engines\",\"reshard\",\"scheduler\"],\"vendor\":{\"name\":\"The Apache Software Foundation\"}} Next -->", "title": "Installing CouchDB from precompiled packages"}, {"location": "tutorials/selfhosting/requirements/couchdb-snap/", "text": "Installing CouchDB from snap package \u00b6 Warning Only install snap package if you can\u2019t install the precompiled package for your system. Install snapd sudo apt install snapd sudo systemctl enable --now snapd.socket Install Snap Core sudo snap install core Install CouchDB snap package sudo snap install couchdb Configure CouchDB admin password and start CouchDB. Be careful to replace StrongAdminPassw0rd with your chosen password . sudo snap set couchdb admin=StrongAdminPassw0rd sudo snap start couchdb Warning Don\u2019t forget your CouchDB admin password, you will need to provide it to cozy-stack at installation time Enable snap permissions sudo snap connect couchdb:mount-observe sudo snap connect couchdb:process-control Test your CouchDB installation curl http://127.0.0.1:5984/ The above command should give you something like {\"couchdb\":\"Welcome\",\"version\":\"3.2.1\",\"git_sha\":\"244d428af\",\"uuid\":\"f7b83554fa2eb43778963d18a1f92211\",\"features\":[\"access-ready\",\"partitioned\",\"pluggable-storage-engines\",\"reshard\",\"scheduler\"],\"vendor\":{\"name\":\"The Apache Software Foundation\"}} Create system databases. These databases are created automatically when installing couchdb from debian package but should be created manually when installing using snap. Replace StrongAdminPassw0rd with the password you chose previously. curl -u \"admin:StrongAdminPassw0rd\" -X PUT http://localhost:5984/_users curl -u \"admin:StrongAdminPassw0rd\" -X PUT http://localhost:5984/_replicator Next -->", "title": "Installing CouchDB from snap package"}, {"location": "tutorials/selfhosting/requirements/couchdb-snap/#installing-couchdb-from-snap-package", "text": "Warning Only install snap package if you can\u2019t install the precompiled package for your system. Install snapd sudo apt install snapd sudo systemctl enable --now snapd.socket Install Snap Core sudo snap install core Install CouchDB snap package sudo snap install couchdb Configure CouchDB admin password and start CouchDB. Be careful to replace StrongAdminPassw0rd with your chosen password . sudo snap set couchdb admin=StrongAdminPassw0rd sudo snap start couchdb Warning Don\u2019t forget your CouchDB admin password, you will need to provide it to cozy-stack at installation time Enable snap permissions sudo snap connect couchdb:mount-observe sudo snap connect couchdb:process-control Test your CouchDB installation curl http://127.0.0.1:5984/ The above command should give you something like {\"couchdb\":\"Welcome\",\"version\":\"3.2.1\",\"git_sha\":\"244d428af\",\"uuid\":\"f7b83554fa2eb43778963d18a1f92211\",\"features\":[\"access-ready\",\"partitioned\",\"pluggable-storage-engines\",\"reshard\",\"scheduler\"],\"vendor\":{\"name\":\"The Apache Software Foundation\"}} Create system databases. These databases are created automatically when installing couchdb from debian package but should be created manually when installing using snap. Replace StrongAdminPassw0rd with the password you chose previously. curl -u \"admin:StrongAdminPassw0rd\" -X PUT http://localhost:5984/_users curl -u \"admin:StrongAdminPassw0rd\" -X PUT http://localhost:5984/_replicator Next -->", "title": "Installing CouchDB from snap package"}, {"location": "tutorials/selfhosting/requirements/couchdb/", "text": "Installing CouchDB \u00b6 Cozy-stack uses couchdb to store structured data of your cozy. Preferred installation method is precompiled package. In case there is no package yet for your system, you can also install couchdb using snap package (see instructions linked below). Install CouchDB from precompiled package (Debian 10, 11 or 12 / Ubuntu 20.04, 22.04) Install CouchDB from snap package If neither method is available for your particular system and architecture, refer to CouchDB official installation documentation to build it from source.", "title": "Installing CouchDB"}, {"location": "tutorials/selfhosting/requirements/couchdb/#installing-couchdb", "text": "Cozy-stack uses couchdb to store structured data of your cozy. Preferred installation method is precompiled package. In case there is no package yet for your system, you can also install couchdb using snap package (see instructions linked below). Install CouchDB from precompiled package (Debian 10, 11 or 12 / Ubuntu 20.04, 22.04) Install CouchDB from snap package If neither method is available for your particular system and architecture, refer to CouchDB official installation documentation to build it from source.", "title": "Installing CouchDB"}, {"location": "tutorials/selfhosting/requirements/nodejs/", "text": "Installing NodeJS \u00b6 To be able to run Cozy connectors and gather all your data, cozy-stack needs NodeJS version 20. This documents gives instructions to instal NodeJS 20. You can refer to NodeJS installation documentation or simply follow the instructions below. Add NodeJS 20 package repository to your system: KEYRING=/usr/share/keyrings/nodesource.gpg curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o \"$KEYRING\" echo \"deb [signed-by=$KEYRING] https://deb.nodesource.com/node_20.x nodistro main\" | sudo tee /etc/apt/sources.list.d/nodesource.list >/dev/null cat < /dev/null Package: * Pin: origin deb.nodesource.com Pin-Priority: 700 EOF Install NodeJS: sudo apt update && sudo apt install -y nodejs Verify that NodeJS 20 is properly installed nodejs --version This command should give you nodejs installed version. For example: v20.11.1 Next -->", "title": "Installing NodeJS"}, {"location": "tutorials/selfhosting/requirements/nodejs/#installing-nodejs", "text": "To be able to run Cozy connectors and gather all your data, cozy-stack needs NodeJS version 20. This documents gives instructions to instal NodeJS 20. You can refer to NodeJS installation documentation or simply follow the instructions below. Add NodeJS 20 package repository to your system: KEYRING=/usr/share/keyrings/nodesource.gpg curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o \"$KEYRING\" echo \"deb [signed-by=$KEYRING] https://deb.nodesource.com/node_20.x nodistro main\" | sudo tee /etc/apt/sources.list.d/nodesource.list >/dev/null cat < /dev/null Package: * Pin: origin deb.nodesource.com Pin-Priority: 700 EOF Install NodeJS: sudo apt update && sudo apt install -y nodejs Verify that NodeJS 20 is properly installed nodejs --version This command should give you nodejs installed version. For example: v20.11.1 Next -->", "title": "Installing NodeJS"}, {"location": "use/", "text": "Welcome to your new home \u00b6 Hello, I\u2019m Claude, Cozy support team member. Let me introduce you to your new home in the cloud. Our charter \u00b6 Before starting the visit, I\u2019d like to tell you a few words about our values. Our priority is to help you take back the control on your data, by importing them into a safe place, a place that you\u2019re the only one to have access. In your personal cloud, you\u2019re at home \u00b6 By default, you are the only one that can access your data. (\u2026) Your data belongs to you \u00b6 Your are the one and only owner of the data stored on your cloud. Openness brings confidence \u00b6 Cozy is and will stay a service built on free software: you can use, copy, improve the source code. You decide how your data can be used \u00b6 Your Cozy server allows to control the data that you share with third party. Create your home in the cloud \u00b6 Your home has an address. Your home in the cloud also has an address. Let\u2019s choose it! Claude\u2019s tip Creating a good password may be hard. Your toolbox \u00b6 Save all your files and documents in just a click \u00b6 Access your files wherever your are, whenever you want \u00b6 Connect to deconnect \u00b6 Checklist \u00b6 Have you installed the Cozy application on your phone? \u00b6 Have you installed the Cozy application on your computers? \u00b6 Any question? \u00b6 One last surprise \u00b6", "title": "Welcome to your new home"}, {"location": "use/#welcome-to-your-new-home", "text": "Hello, I\u2019m Claude, Cozy support team member. Let me introduce you to your new home in the cloud.", "title": "Welcome to your new home"}, {"location": "use/#our-charter", "text": "Before starting the visit, I\u2019d like to tell you a few words about our values. Our priority is to help you take back the control on your data, by importing them into a safe place, a place that you\u2019re the only one to have access.", "title": "Our charter"}, {"location": "use/#in-your-personal-cloud-youre-at-home", "text": "By default, you are the only one that can access your data. (\u2026)", "title": "In your personal cloud, you\u2019re at home"}, {"location": "use/#your-data-belongs-to-you", "text": "Your are the one and only owner of the data stored on your cloud.", "title": "Your data belongs to you"}, {"location": "use/#openness-brings-confidence", "text": "Cozy is and will stay a service built on free software: you can use, copy, improve the source code.", "title": "Openness brings confidence"}, {"location": "use/#you-decide-how-your-data-can-be-used", "text": "Your Cozy server allows to control the data that you share with third party.", "title": "You decide how your data can be used"}, {"location": "use/#create-your-home-in-the-cloud", "text": "Your home has an address. Your home in the cloud also has an address. Let\u2019s choose it! Claude\u2019s tip Creating a good password may be hard.", "title": "Create your home in the cloud"}, {"location": "use/#your-toolbox", "text": "", "title": "Your toolbox"}, {"location": "use/#save-all-your-files-and-documents-in-just-a-click", "text": "", "title": "Save all your files and documents in just a click"}, {"location": "use/#access-your-files-wherever-your-are-whenever-you-want", "text": "", "title": "Access your files wherever your are, whenever you want"}, {"location": "use/#connect-to-deconnect", "text": "", "title": "Connect to deconnect"}, {"location": "use/#checklist", "text": "", "title": "Checklist"}, {"location": "use/#have-you-installed-the-cozy-application-on-your-phone", "text": "", "title": "Have you installed the Cozy application on your phone?"}, {"location": "use/#have-you-installed-the-cozy-application-on-your-computers", "text": "", "title": "Have you installed the Cozy application on your computers?"}, {"location": "use/#any-question", "text": "", "title": "Any question?"}, {"location": "use/#one-last-surprise", "text": "", "title": "One last surprise"}]} \ No newline at end of file diff --git a/en/sitemap.xml b/en/sitemap.xml index 95e13f6eb..df8d21945 100644 --- a/en/sitemap.xml +++ b/en/sitemap.xml @@ -2,2242 +2,2242 @@ https://docs.cozy.io/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/privacy/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/ach/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/ach/DirectoriesToInject/testFile2/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/ach/DirectoriesToInject/Folder/testFile1/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/ach/data/bank/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/ach/e2e/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/ach/examples/data-from-csv/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/babel-preset-cozy-app/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/babel-preset-cozy-app/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/commitlint-config-cozy/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/commitlint-config-cozy/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-app-publish/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-app-publish/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-apps-registry/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-apps-registry/CONTRIBUTING/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/account-types/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/bills-matching/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/brand-dictionary/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/categorization/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/category/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/code-conventions/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/credentials/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/data-fetching/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/demo/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/dev/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/notifications/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/perfs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/services/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/docs/tracking/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/scripts/visualizer/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/DisplayError/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/Select/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/Switch/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/Chart/LineChart/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/KonnectorChip/readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/Loading/Loading/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/Select/Readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/SelectDates/Readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/SharingIcon/SharingIcon/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/components/Table/Readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/ducks/balance/AccountRow/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/ducks/balance/History/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/ducks/filters/Readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/src/targets/services/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/test/fixtures/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/test/fixtures/matching-service/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-banks/test/fixtures/notifications-service/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/architecture/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/dev/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/devtools/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/entrypoints/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/getting-started/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/hooks/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/link-authoring/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/logging/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/metadata/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/mobile-guide/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/node/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/react-integration/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/relationships/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/schema/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/timeseries/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-pouch-link/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-stack-client/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/Association/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/BlockedCozyError/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/BulkEditError/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/CozyClient/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/CozyLink/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/CozyProvider/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/HasMany/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/HasManyInPlace/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/HasManyTriggers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/HasOne/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/HasOneInPlace/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/InvalidCozyUrlError/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/InvalidProtocolError/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/InvalidRedirectLinkError/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/Query/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/QueryDefinition/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/Registry/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/StackLink/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/classes/models.document.Qualification/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.dacc.Params/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.file.FileUploadOptions/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.instance.DiskInfos/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.instance.DiskInfosRaw/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.instance.SettingsInfo/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.permission.Document/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.permission.Permission/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.permission.PermissionItem/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeries/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/interfaces/models.timeseries.TimeSeriesJSONAPI/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/manifest/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.account/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.applications/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.contact/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.dacc/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.document.helpers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.document.locales/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.document/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.document.themes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.file/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.folder/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.geo/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.instance/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.konnectorFolder/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.note/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.paper/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.permission/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.sharing/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.timeseries/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.trigger/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.user/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/models.utils/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-client/api/cozy-client/modules/useMutation/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/feedback/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/developer/api_doc/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/developer/coffeescript/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/developer/debug/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/developer/log_analysis/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/developer/requirements/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/developer/setup/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/developer/test/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/build/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/cli/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/file_systems/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/ignore_files/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/inotify/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/limitations/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/linux/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/macos/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-desktop/usage/windows/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-device-helper/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-device-helper/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/pull_request_template/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/cc.cozycloud.autocategorization/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/com.bitwarden.ciphers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/com.bitwarden.contacts/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/com.bitwarden.folders/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/com.bitwarden.organizations/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/com.ecoledirecte.notes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/com.ecoledirecte.textbook.day/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/com.unibet.bets/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.account_types/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.accounts/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.apps/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.apps.suggestions/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.bank/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.bills/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.coachco2/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.contacts/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.docrules/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.exports/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.files/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.files_metadata/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.home.settings/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.identities/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.jobs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.konnectors/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.notes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.notifications/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.oauth.access_codes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.oauth.clients/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.permissions/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.photos/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.procedures/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.remote.nextcloud.files/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.remote.requests/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.sessions.logins/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.sessions/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.settings/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.shared/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.sharings/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.tags/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.terms/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.timeseries/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.todos/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.triggers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-doctypes/docs/io.cozy.triggers.state/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-flags/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-flags/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/CONTRIBUTING/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/docs/configuration/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/docs/connection-state/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/docs/develop/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/docs/intents/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-home/docs/services/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/api/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/categorization-dashboard/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/cli/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/dev/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/errors/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/operation-linking/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-konnector-libs/synchronization/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-notifications/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-notifications/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-realtime/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-realtime/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-scripts/webpack-configs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-scripts/webpack-merge-strategies/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/CONTRIBUTING/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/INSTALL/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/accept-from-flagship/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/admin/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/apps/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/assets/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/auth/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/bitwarden/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/client-app-dev/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/config/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/connection-check/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/contacts/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/couchdb-quirks/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/data-system/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/delegated-auth/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/docker/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/doctype/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/files/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/flagship/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/http-api/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/important-changes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/instance/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/intents/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/jobs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/konnectors-dev/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/konnectors-workflow/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/konnectors/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/mango/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/move-design/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/move/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/nextcloud/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/not-synchronized-vfs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/notes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/notifications/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/office/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/permissions/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/pouchdb-quirks/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/public/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/realtime-internals/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/realtime/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/references-docs-in-vfs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/registry-publish/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/registry/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/release/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/remote/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/security/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/settings/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/sharing-design/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/sharing/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/shortcuts/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/user-action-required/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/wellknown/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/workers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/archives/architecture/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/archives/couchdb-plugins/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/archives/konnectors-design/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/archives/moving/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/archives/onboarding/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/archives/realtime/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/archives/replication/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_apps/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_apps_install/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_apps_ls/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_apps_show/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_apps_uninstall/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_apps_update/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_assets/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_assets_add/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_assets_ls/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_assets_rm/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_check/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_check_fs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_check_shared/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_check_sharings/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_check_triggers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_completion/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_decrypt-creds/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_decrypt-data/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_encrypt-creds/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_encrypt-data/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_gen-keys/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_insert-asset/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_ls-assets/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_ls-contexts/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_passwd/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_rm-asset/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_config_show-context/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_doc/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_doc_man/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_doc_markdown/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_features/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_features_config/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_features_defaults/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_features_flags/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_features_ratio/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_features_sets/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_features_show/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_files/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_files_exec/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_files_import/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_files_usage/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_contact-emails/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_indexes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_jobs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_mime/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_orphan-account/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_password-defined/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_redis/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_service-triggers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_fix_thumbnails/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_add/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_auth-mode/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_clean-sessions/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_client-oauth/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_count/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_debug/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_destroy/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_export/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_find-oauth-client/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_fsck/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_import/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_ls/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_modify/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_refresh-token-oauth/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_set-disk-quota/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_set-passphrase/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_show-app-version/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_show-db-prefix/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_show-swift-prefix/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_show/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_token-app/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_token-cli/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_token-konnector/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_instances_token-oauth/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_jobs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_jobs_purge-old-jobs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_jobs_run/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_deactivate-maintenance/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_install/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_ls-maintenances/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_ls/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_maintenance/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_run/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_show/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_uninstall/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_konnectors_update/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_serve/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_settings/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_status/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_swift/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_swift_get/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_swift_ls-layouts/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_swift_ls/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_swift_put/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_swift_rm/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_tools/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_tools_bug/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_tools_encrypt-with-rsa/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_tools_heap/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_tools_unxor-document-id/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_triggers/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_triggers_launch/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_triggers_ls/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_triggers_show-from-app/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-stack/cli/cozy-stack_version/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-ui/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-ui/dev/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-ui/guidelines/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-ui/how-to-extract/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-ui/how-to-transpile/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-ui/components/Readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/cozy-ui/components/Readme/Readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/eslint-config-cozy-app/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/eslint-config-cozy-app/CHANGELOG/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/faq/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/faq/security/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/faq/start/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/dev/connect-mobile-app-local-stack/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/dev/cordova/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/dev/hmr/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/dev/run-connectors-on-local-cozy-stack/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/dev/runCozyDocker/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/dev/sendmail/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/dev/services/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/howTos/sync/linux/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/projects/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/references/auth/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/references/git-flow/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/references/tech-intro/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/app/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/readme/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/client-side-konnector/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/client-side-konnector/getting-started/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/client-side-konnector/scrape-data/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/cloudery/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/data/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/data/advanced/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/data/doctypes/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/data/pouchdb/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/data/qualification/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/data/queries/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/2fa/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/cozy-browser/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/faq/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/getting-started/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/going-further/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/how-does-it-work/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/oauth/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/packaging/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/save-data/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/konnector/scrape-data/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/administration/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/administration/mail/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/administration/more_instances/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/administration/office/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/administration/upgrade/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/docker/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/finalize/apache/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/finalize/create_instance/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/finalize/nginx/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/install/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/install/package/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/install/sources/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/requirements/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/requirements/couchdb-pkg/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/requirements/couchdb-snap/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/requirements/couchdb/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/tutorials/selfhosting/requirements/nodejs/ - 2024-07-11 + 2024-07-12 daily https://docs.cozy.io/use/ - 2024-07-11 + 2024-07-12 daily \ No newline at end of file diff --git a/en/sitemap.xml.gz b/en/sitemap.xml.gz index e47563bc9ebdf3d84a1c057195497879cf3823da..655c105d2c7b7d676ef7af9a43e5693b5123c6e5 100644 GIT binary patch delta 3293 zcmV<33?lQB8tKR@nL8ve0d z?smIHG>LjS#Dx#-GODh86PNRo%O4kifBfu+N9C)&!SrbSdTPCTR^KI-x6xk3h4Nqa z3*(nhm-VIdpOi86UO#*COHH89&$Kjl|8#lw%!IH! zGJG@55X@GpJs6c#9U#$56G$Z=48?1IQ!STMf$Lafi16I1zIwxhHkD1x)DjkQtqGO4cISI}XDbXsVmQn_kL%oTrzt7M|K zXvbe<<>dhjKc-$&J?FRN>Y#t3FE15HS5j%wNhi&oSnLCudJm7d1t)YqnZ_u|VHph+ z8g#};VQUopfuDj@8|Wn-RWL(}%dLr7TJwbhFl$it0y=nCcKNt`Y2skz{jic!i7w&&~=SJi1i_Q$oKvMU_2L82|)%|~R{GZuUe9vpN zC+e5w0ukAvmo-@?$W^&f+useMLSY zH^wFkJl129p{2w@gRWl9GPE}-2R@hwAr*aY&dSFaY z%fyK;d5>u=n-R;uupfWCspl^)W!X{FxaiC7nn(kacHVE0N75R%5i+OF2hh930o1oG zHepXmj?p*3h<i8dRJyo);zjTcC&B+3>^ZGiQD9a-(9V{~Rf-iM~pP+-7hdMav~ zA>>h%gPFb`d{&*Pn>z>Ea*V6Z;aLW}>_}Cih-KzJkI^fGzGr{kNB?X2?G5P{?3PA8e?fuQ#wBm)=T|%fDIh|W|54GsXF!-FHPKBxyFBQ;=Gr;??a*wlQ%0?saQ)i zQ0Pspr2-Z&=e_QGk>}m<;rA!eRid7?R43c~;<`Niz{Y<}|G!D}&kt|kJb!n^NU#Es z?HHxwOjF}u7@|)f$ei}bSb$-$$O$puCWZ2@+yfYY3{_!fOnC*XWyJbwl`aNd0e zjs}7|GQ@u=NsO-myn^)Zkzw-G^A#XR*7V7+JOj$8|2rpGkCLXiNq#^^Yl!q(stq!u zrY%`t56UtRR^{h-z$)LA(Vc2v@F3Q-&MgmA>)Vxd((a>)Jc!GCW)r9<&@8k6CXSTy zzymdb+Sw1JIm(un>ujvX$1H~|K4djJt>Qi=>LY(Xt!bSPw5re?XvakDJwB*4y-B$4 zox89u-{52RQh5fWxie1t9Vlq6Yak|f5k4Sv5#I95RCIU9)~>1!RZjX<+4Ki1F%5r5 z;;}d%JfKqJtIGPU7cwW0U*qXcpB?w)K4XXNLo3}p z!>gP_sr!I3-BO zUBukBMTO$A@g2wkTRS~OTRSlD!Bt+WPWdOCh`DG>2jcQg$d=P)OgDoMoQ4?Jwst@6 z3b}mNW$w=Rw1{)^4j*hYHtk4;(-isS*NlH?kD+jkn3>$8&Tz3Cd|bx%wbWwO?kUDq zZTG{DeF{5agnbIk;{@IL#MuSla7j=szssQ1-?L^o+N`7%?RX8zd`zz96jv>X@K zx5hC9=S0j+JFPLum=&Gx=jAoRNwT6X$2TWj=m_+Cn7!ttYb4-Ob`KLTVgmKlHx_?% zQ<%V@<1(rl2$llOVsIX?ufv~1p;ZxoYQWILnZtZ2z9MCO?0S4_Ub%&B_F<1_(swSySQ?<6I08KZ( z!yNZcb-_E}NKkl($ZbGqy)=-t^&)={%?3S!hc@RsS`TAymr-?&98h}-EfuXf)N>Wo zjx#pQ!39IV(oK|CZ$4ZAuE=JI>>X|R6 z4wvqj&47zIg-wVu3kB$XV&)tVYG}TLVM}#{dhxOFVhkH#&KiFeDyIB) zU`Vpm7L`#8?7dRg9(n1)8hEa&y~#=svpa^27a zA*|nI0z{21pXg4pXCuOy(5VFZa2GyBuxq^R<4-%=A12Moo zIKl>-Q4><{5Z|&2VsE8K=H73ix6~u3cVhrG4_N$5#~JFe1u1l(28$TG+ng)x@TLo} ztI>01EiY)xY>}hhw|99WA4Xib$p(JVcs}@%rwAOWnNNA1+axcA_l%og%JDfouf*f(N99C|UQp{UaFQuA z!mT%aUbKI!mbeiYHN?uj&ndD4X9hfEZgYcCwtw=T(S#UjSDf6-6Y(KsbZ1g0LX^z# zJCXx4TFpWq>O!EguQm6h44jv+V0u^xRnV-rhGP6c4+UpAmrpbcsY zS(}X}YaFH#t^n3GlDwds6r@VnkOk4j!B_&ttVJPdyc?TNy(g)AKAe!a6wAU%a|>@V z!sBh^_dudHNpIw5li>?LA}G(kL~I9ph8fA}nr(_qIA(@LOv2i{ZCQ@Sj21yR1pkSX zLJV$ypR=^bKC$Si6b$f(j(;$n2%j{P0p)nLT?fC5#9>hJ>};1Px#%Hh#J=)2Ii!xo zJQ(xgJVjA%O|^|417yTJnoFF6R2$jiHA}n18s!#TVdkaYN3u=lV?zG)&l$^&+PK=M z8C$n{02$C0`fc1k5NuJWZ<4?_MJFeYc$NVWX!~(hgm0uj#x2Ap97b3W$uOEkAXkzfRDYhH!WZI=;Xkbo*%gL bnm(b;_5A-RPBi`(DLwlSrC}*jNi_igyO(th delta 3293 zcmV<33?lQB81JR5({ ze!l7Lqb-GKy!+|#lf{pZACXgD8`u8y_|x@k@wdl6KmXxb4mMJHRDRgSpB{H94gXj! zce~vpnnb-E;=+e^8C6%liOc!P<&TTMKYsqhqw-bXV0tuuJ+odtukRAe+i0)iLisQI zh4IU0%lgv!Ps*5jub)5t@#$a0kAHs^Po9(?nV&oRG1W=eQWNOU=UN)Of3`e(W%S#2)l~h`E(n+%?7W;sv-oqnq!3mvDrZGx#SVjYd z2Awfd*ct_Y;HMzf26~A{70i(0a%*Ci)_kD=%ofnK)Rv|1|{92l^w~ zYPe&AyE933Y;a$8GNk1j<7j%sh5KLLxzV`$vNOXnkkmb~fq&y=b-#Zc|7W%oKkypu ziTYK!Kty)vWlfd|a#d~=w;prhzm{uDECyX?RUWOSl}^#}#bhG+;CGy;e>X8fUy)D9 zjj@RWkM)>jXen{fpsQE24DC(Ife+@vxF_cE<-&dIf{F~UtSOuEQid|jshos`9vBnU zGI63y-eX$JX2kL@><52u>iLUHS$5PkF8Z>&Cepy9o%b8$k+jBbgv_b)0rW0$0QGH) zP1sYCWAqI$qF)o{E}g z2zeCcV5aW}pH(O7=FWk(9OG(pc$NV#J5p6BVwt%wV)V+O?^%EM(f?9@dqetVc?s4D z@ih^$-TbOe;>usg{w3GhU*X>{*%B|HzYl(EG;y3ZzsvY<>GpiduiSepu?;j23veAw z+g6(?O9|dNVhhf9>Rh?4v}QbSKLyM6$eN`nyJzysa~IFWz4<6087Z zJ4Wd^)71DEhUn7=GN(N<7GM}Gazf0vNuj(e_W;HpLsgg=(;sdy9od1GHSs=4%9}|` z-+?6G!Do>=>N$TD^%lvPekyLnmcJ#>7yfV=2ljhVgbxT^gtt6172O@OwX3Q_m6Lu|HvPd$OvB%i zcr4Bb52)1msU}jJ(M_66zRc97nSXW!FanP>EysoR zt#J&&IT3TyPHPM@W<}@wd3lX+lB{UU@y!VrIs*M3X0JKv8VR_R-NVF-m_R-CjRk+* z6ecj}xQuEBg5|;=IrP5aBjoG^b&Y8=Zq4^wsMP{hI0fvUbE2Jtm$4yhkrq(H#|aX- z%hb^-Dy&&^AgrlY_>{MU)P$C?TYDKa2XxC}fI)jo-Jzsf43@*Hs!1x-RITkPK+}!y zFvq=9UGNS#5)|GcavKm@FAXGZy~uw#<}xh(^$Xb0E^4mmv{5Pcz#Q@4vA?UHY6_HG4dD~(I;_o zeiY?)+eBzu!p6gP(M*`WDUg4_%LY85V}@jMw;uA^8imVuaCeEZN0O5^;7YE=@ z2nRqPlFG<-mD&eD$jMhTS9}J(>Fmhbjq^L;Nm=bGglw{qL3L(Zu3&%TgG4IjKn!pX zjE%gZM-55a40~Y_%afW(qK?)tH!6L@)Hs=aEyy*h$ zYV=%L%M02v8|0!U?sySr$8uuiK}+Pz>s@B>c*BdhE2%X%WXo=lL(hg7Jp%9o?W&2) zfN=}5d<7cY5_S*N522F&_8> zJja1=$%zf^*^PO*zEDVF)TX$x+bEdb3{K!R--2%Vp$}!mcbXe@=y}fYY7jY06*lak zeSYs_UG>s2;|&`P?fSa|-H=SE#daSA=B9lgxivL1+r)6hVM~AeJ&Zlph~bCLN_jd_ zb8-`aC*WP8UC|9GX2??#95d*tAub>08&0gNIi+1tU;bibg>IZKYmgT+c4FcM;2t^- z zqGai5eTr$Za+D!53YR)zGqXgTz&Yw$s{&#gj$2Epe+|H z(8g^6>g9Ck0(83Z{Q^`MaV^xjE%!W5k!^QGs0nRlO)!75G2Rg%?o5+-%fJwO+CIzt zXUh)SR^*%5kBOaZCE#`Nva+#P*wv70e*$l{;Kv>^pVO2>jlg@6SDI?&g{@2^dO4Qh z#I6#0za-q!0ngBFJRkhXQv{CG%%?ohZIYM5d&bQ#<@g+)SK@K?qjI7}FQ|1FILVY5 z;no{IFWP@qOWcTy8e-+%=M>q2GXownx4FS6+dp~FXhMv%D^Bj^iTIE*x-+R0AxdWW z9m#)hSdYG(v56%orvk9^FB?!Q&;~Vy ztj$J~H4f7VR{-l8NnX%R3Q{F($b#tNU@U=R)}kRa-i=MCK9JNsA5KVIie=%XxrMhF z;qf-|dmvGpq&M?LA}r6oLTm?nh8fA}nr(_qIA(@LOv2i{ZCQ@Sj21yR1pk?n zLJV$ye`aZqePYp3DHz}n9sgiD5k74s1IqDgyAFOAiNm1c+1V~pa?wN1h<)X4a!4JE zc`)X~d5WUknra(82FQqcG?zFBsW!63YnFD2HOeix!puv(k7S$9$AtXppEH&lwQ;pi zGq!H^05YI0^xL?7AlRZ#-z0%=icU@($@9=;2B~?VYeav-qmtoM`+nQhNR$p8q9jNi_igC=O~B