Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for async mode #155

Open
basert opened this issue Aug 30, 2023 · 2 comments
Open

Support for async mode #155

basert opened this issue Aug 30, 2023 · 2 comments
Labels
enhancement New feature or request

Comments

@basert
Copy link

basert commented Aug 30, 2023

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.

@jodyheavener
Copy link
Member

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

@jodyheavener jodyheavener added the enhancement New feature or request label Sep 19, 2023
@jodyheavener jodyheavener added the hacktoberfest This issue is open to submissions from Hacktoberfest participants label Oct 3, 2023
@dreusel
Copy link

dreusel commented Feb 22, 2024

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]

@jodyheavener jodyheavener removed the hacktoberfest This issue is open to submissions from Hacktoberfest participants label Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants