Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »

    alfypublic

    Alfy

    Create Alfred workflows with ease

    Build Status

    Highlights

    • Easy input↔output.
    • Config and cache handling built-in.
    • Fetching remote files with optional caching.
    • Publish your workflow to npm.
    • Automatic update notifications.
    • Easily testable workflows.
    • Finds the node binary.
    • Presents uncaught exceptions and unhandled Promise rejections to the user.
      No need to manually .catch() top-level promises.

    Prerequisites

    You need Node.js 4+ and Alfred 3 with the paid Powerpack upgrade.

    Install

    $ npm install alfy
    

    Usage

    Create a new Alfred workflow and add a Script Filter with the following script:

    ./node_modules/.bin/run-node index.js "$1"

    We can't call node directly as GUI apps on macOS doesn't inherit the $PATH.

    In the workflow directory, create a index.js file, import alfy, and do your thing.

    Tip: you can use generator-alfred to scaffold out an alfy based workflow.

    Example

    Here we fetch some JSON from a placeholder API and present matching items to the user:

    const alfy = require('alfy');
     
    alfy.fetch('jsonplaceholder.typicode.com/posts').then(data => {
        const items = alfy
            .inputMatches(data, 'title')
            .map(x => ({
                title: x.title,
                subtitle: x.body,
                arg: x.id
            }));
     
        alfy.output(items);
    });
    More

    Some example usage in the wild: alfred-npms, alfred-emoj, alfred-ng.

    Update notifications

    Alfy uses alfred-notifier in the background to show a notification when an update for your workflow is available.

    Caching

    Alfy offers the possibility of caching data, either with the fetch or directly through the cache object.

    An important thing to note is that the cached data gets invalidated automatically when you update your workflow. This offers the flexibility for developers to change the structure of the cached data between workflows without having to worry about invalid older data.

    Publish to npm

    By adding alfy-init as postinstall and alfy-cleanup as preuninstall script, you can publish your package to npm instead of to Packal. This way, your packages are only one simple npm install command away.

    {
        "name": "alfred-unicorn",
        "version": "1.0.0",
        "description": "My awesome unicorn workflow",
        "author": {
            "name": "Sindre Sorhus",
            "email": "sindresorhus@gmail.com",
            "url": "sindresorhus.com"
        },
        "scripts": {
            "postinstall": "alfy-init",
            "preuninstall": "alfy-cleanup"
        },
        "dependencies": {
            "alfy": "*"
        }
    }

    Tip: Prefix your workflow with alfred- to make them easy searchable through npm.

    You can remove these properties from your info.plist file as they are being added automatically at install time.

    After publishing your workflow to npm, your users can easily install or update the workflow.

    $ npm install --global alfred-unicorn
    

    Tip: instead of manually updating every workflow yourself, use the alfred-updater workflow to do that for you.

    Testing

    Workflows can easily be tested with alfy-test. Here is a small example.

    import test from 'ava';
    import alfyTest from 'alfy-test';
     
    test(async t => {
        const alfy = alfyTest();
     
        const result = await alfy('workflow input');
     
        t.deepEqual(result, [
            {
                title: 'foo',
                subtitle: 'bar'
            }
        ]);
    });

    Debugging

    When developing your workflow it can be useful to be able to debug it when something is not working. This is when the workflow debugger comes in handy. You can find it in your workflow view in Alfred. Press the insect icon to open it. It will show you the plain text output of alfy.output() and anything you log with alfy.log():

    const unicorn = getUnicorn();
    alfy.log(unicorn);

    Environment variables

    Alfred lets users set environment variables for a workflow which can then be used by that workflow. This can be useful if you, for example, need the user to specify an API token for a service. You can access the workflow environment variables from process.env. For example process.env.apiToken.

    API

    alfy

    input

    Type: string

    Input from Alfred. What the user wrote in the input box.

    output(list)

    Return output to Alfred.

    list

    Type: Array

    List of Object with any of the supported properties.

    Example:

    alfy.output([{
        title: 'Unicorn'
    }, {
        title: 'Rainbow'
    }]);

    log(value)

    Log value to the Alfred workflow debugger.

    matches(input, list, [item])

    Returns an Array of items in list that case-insensitively contains input.

    alfy.matches('Corn', ['foo', 'unicorn']);
    //=> ['unicorn']
    input

    Type: string

    Text to match against the list items.

    list

    Type: Array

    List to be matched against.

    item

    Type: string Function

    By default it will match against the list items.

    Specify a string to match against an object property:

    const list = [{
        title: 'foo'
    }, {
        title: 'unicorn'
    }];
     
    alfy.matches('Unicorn', list, 'title');
    //=> [{title: 'unicorn'}]

    Or nested property:

    const list = [{
        name: {
            first: 'John',
            last: 'Doe'
        }
    }, {
        name: {
            first: 'Sindre',
            last: 'Sorhus'
        }
    }];
     
    alfy.matches('sindre', list, 'name.first');
    //=> [{name: {first: 'Sindre', last: 'Sorhus'}}]

    Specify a function to handle the matching yourself. The function receives the list item and input, both lowercased, as arguments, and is expected to return a boolean whether it matches:

    const list = ['foo', 'unicorn'];
     
    // here we do an exact match
    // `Foo` matches the item since it's lowercased for you
    alfy.matches('Foo', list, (item, input) => item === input);
    //=> ['foo']

    inputMatches(list, [item])

    Same as matches(), but with alfy.input as input.

    error(err)

    Display an error or error message in Alfred.

    Note: You don't need to .catch() top-level promises. Alfy handles that for you.

    err

    Type: Error string

    Error or error message to be displayed.

    fetch(url, [options])

    Returns a Promise that returns the body of the response.

    url

    Type: string

    URL to fetch.

    options

    Type: Object

    Any of the got options.

    json

    Type: boolean
    Default: true

    Parse response body with JSON.parse and set accept header to application/json.

    maxAge

    Type: number

    Number of milliseconds this request should be cached.

    transform

    Type: Function

    Transform the response before it gets cached.

    alfy.fetch('https://api.foo.com', {
        transform: body => {
            body.foo = 'bar';
            return body;
        }
    })

    You can also return a Promise.

    const xml2js = require('xmls2js');
    const pify = require('pify');
     
    const parseString = pify(xml2js.parseString);
     
    alfy.fetch('https://api.foo.com', {
        transform: body => parseString(body)
    })

    config

    Type: Object

    Persist config data.

    Exports a conf instance with the correct config path set.

    Example:

    alfy.config.set('unicorn', '🦄');
     
    alfy.config.get('unicorn');
    //=> '🦄'

    cache

    Type: Object

    Persist cache data.

    Exports a modified conf instance with the correct cache path set.

    Example:

    alfy.cache.set('unicorn', '🦄');
     
    alfy.cache.get('unicorn');
    //=> '🦄'
    maxAge

    The set method of this instance accepts an optional third argument where you can provide a maxAge option. maxAge is the number of milliseconds the value is valid in the cache.

    Example:

    const delay = require('delay');
     
    alfy.cache.set('foo', 'bar', {maxAge: 5000});
     
    alfy.cache.get('foo');
    //=> 'bar'
     
    // Wait 5 seconds
    await delay(5000);
     
    alfy.cache.get('foo');
    //=> undefined

    debug

    Type: boolean

    Whether the user currently has the workflow debugger open.

    icon

    Type: Object
    Keys: info warning error alert like delete

    Get various default system icons.

    The most useful ones are included as keys. The rest you can get with icon.get(). Go to /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources in Finder to see them all.

    Example:

    console.log(alfy.icon.error);
    //=> '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertStopIcon.icns'
     
    console.log(alfy.icon.get('Clock'));
    //=> '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Clock.icns'

    meta

    Type: Object

    Example:

    {
        name: 'Emoj',
        version: '0.2.5',
        uid: 'user.workflow.B0AC54EC-601C-479A-9428-01F9FD732959',
        bundleId: 'com.sindresorhus.emoj'
    }

    alfred

    Type: Object

    Alfred metadata.

    version

    Example: '3.0.2'

    Find out which version the user is currently running. This may be useful if your workflow depends on a particular Alfred version's features.

    theme

    Example: 'alfred.theme.yosemite'

    Current theme used.

    themeBackground

    Example: 'rgba(255,255,255,0.98)'

    If you're creating icons on the fly, this allows you to find out the color of the theme background.

    themeSelectionBackground

    Example: 'rgba(255,255,255,0.98)'

    The color of the selected result.

    themeSubtext

    Example: 3

    Find out what subtext mode the user has selected in the Appearance preferences.

    Usability note: This is available so developers can tweak the result text based on the user's selected mode, but a workflow's result text should not be bloated unnecessarily based on this, as the main reason users generally hide the subtext is to make Alfred look cleaner.

    data

    Example: '/Users/sindresorhus/Library/Application Support/Alfred 3/Workflow Data/com.sindresorhus.npms'

    Recommended location for non-volatile data. Just use alfy.data which uses this path.

    cache

    Example: '/Users/sindresorhus/Library/Caches/com.runningwithcrayons.Alfred-3/Workflow Data/com.sindresorhus.npms'

    Recommended location for volatile data. Just use alfy.cache which uses this path.

    preferences

    Example: '/Users/sindresorhus/Dropbox/Alfred/Alfred.alfredpreferences'

    This is the location of the Alfred.alfredpreferences. If a user has synced their settings, this will allow you to find out where their settings are regardless of sync state.

    preferencesLocalHash

    Example: 'adbd4f66bc3ae8493832af61a41ee609b20d8705'

    Non-synced local preferences are stored within Alfred.alfredpreferences under …/preferences/local/${preferencesLocalHash}/.

    Users

    Alfred workflows using Alfy

    Related

    Created by

    License

    MIT

    install

    npm i alfy

    Downloadslast 7 days

    199

    version

    0.7.0

    license

    MIT

    repository

    github.com

    last publish

    collaborators

    • avatar
    • avatar