Skip to content

Support for async mode #155

Open
Open

Description

@basert

Summary

Currently all calls to the op-cli are using spawnSync to block until op-cli has a result. This causes issues when you don't want to block the event loop. Is there planned support for async execution (with Promise as result)?

Proposed solution

Add an async version of https://github.com/1Password/op-js/blob/main/src/cli.ts#L255, using spawn and returning an Promise.
Provide an async package of https://github.com/1Password/op-js/blob/main/src/index.ts that returns a Promise instead.

Activity

  1. jodyheavener commented on Sep 19, 2023

    @jodyheavener
    Member

    Thanks for filing @basert - this seems like a great idea. I'm slating it for review.

  2. added
    hacktoberfestThis issue is open to submissions from Hacktoberfest participants
    on Oct 3, 2023
  3. dreusel commented on Feb 22, 2024

    @dreusel

    Just as a hint, here is what I do to wrap calls to op-js in a Promise-wrapped Worker thread:
    op-cli-worker.js:

    'use strict';
    
    const {
    	parentPort, workerData,
    } = require('node:worker_threads');
    
    const [fName, args] = workerData;
    const opJs = require('@1password/op-js');
    
    // Resolve string in the form of 'vault.list' to the actual function
    const theFunction = fName.split('.').reduce((o, i) => o[i], opJs);
    if (typeof theFunction !== 'function') {
    	parentPort.postMessage({error: new Error(`Function ${fName} not found`)});
    }
    
    try {
    	const result = theFunction(...args);
    	parentPort.postMessage({result});
    } catch (error) {
    	parentPort.postMessage({error});
    }

    And in your application:

    function wrapOpJs(f, ...args) {
    	return new Promise((resolve, reject) => {
    		const worker = new worker_threads.Worker(`${__dirname}/op-cli-worker.js`, {
    			workerData: [f, args],
    			env: worker_threads.SHARE_ENV,
    		});
    		worker.on('message', ({error, result}) => {
    			if (error) {
    				reject(error);
    			} else {
    				resolve(result);
    			}
    		});
    		worker.on('error', cause => {
    			reject(new Error('1password worker failed', cause));
    		});
    		worker.on('exit', code => {
    			if (code !== 0) {
    				reject(new Error(`Worker stopped with exit code ${code}`));
    			}
    		});
    	});
    }

    Instead of the usual

    require('@1password/op-js').item.edit(item.id, fields, flags)

    I do:

    await wrapOpJs('item.edit', item.id, fields, flags);

    [edit: Put the worker code in a separate file as the original way using a stringified function had some weird side-effects]

  4. removed
    hacktoberfestThis issue is open to submissions from Hacktoberfest participants
    on Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions