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

Allow linking and unlinking lambdas to applications #8

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Currently, the CLI supports the following commands:
- `fusionauth email:create` - Create a new email template locally.
- Lambdas
- `fusionauth lambda:create` - Upload a lambda to a FusionAuth server.
- `fusionauth lambda:update` - Update a lambda on a FusionAuth server.
- `fusionauth lambda:delete` - Delete a lambda from a FusionAuth server.
- `fusionauth lambda:retrieve` - Download a lambda from a FusionAuth server.
- Themes
Expand Down Expand Up @@ -72,6 +73,9 @@ npm run build;

# now you can use it
npx fusionauth --version;

# to get help on a command
npm run build; npx fusionauth lambda:link-to-application --help
```

To see examples of use look at https://fusionauth.io/docs/v1/tech/lambdas/testing.
Expand Down
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"figlet": "1.6.0",
"fs-extra": "11.1.1",
"html-to-text": "9.0.5",
"js-yaml": "^4.1.0",
"log-symbols": "5.1.0",
"log-update": "5.0.1",
"merge": "2.1.1",
Expand All @@ -42,6 +43,7 @@
"@types/figlet": "1.5.6",
"@types/fs-extra": "11.0.1",
"@types/html-to-text": "9.0.1",
"@types/js-yaml": "^4.0.5",
"@types/node": "20.4.5",
"@types/uuid": "9.0.2",
"ts-node": "10.9.1",
Expand Down
3 changes: 2 additions & 1 deletion src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ export * from './email-duplicate.js';
export * from './email-html-to-text.js';
export * from './email-upload.js';
export * from './email-watch.js';
export * from './lambda-update.js';
export * from './lambda-create.js';
export * from './lambda-delete.js';
export * from './lambda-retrieve.js';
export * from './lambda-update.js';
export * from './theme-watch.js';
export * from './theme-upload.js';
export * from './theme-download.js';
55 changes: 55 additions & 0 deletions src/commands/lambda-create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {Command} from '@commander-js/extra-typings';
import {FusionAuthClient} from '@fusionauth/typescript-client';
import {readFile} from 'fs/promises';
import chalk from 'chalk';
import {join} from 'path';
import {errorAndExit} from '../utils.js';
import {apiKeyOption, hostOption} from "../options.js";
import {load as loadYaml} from 'js-yaml';

const action = async function (lambdaId: string, {input, key: apiKey, host}: {
input: string;
key: string;
host: string
}): Promise<void> {
console.log(`Creating lambda ${lambdaId} on ${host}`);
try {
const filename = join(input, lambdaId + ".yaml");
const data = await readFile(filename, 'utf-8');
const lambda = loadYaml(data) as object;
const fusionAuthClient = new FusionAuthClient(apiKey, host);
const clientResponse = await fusionAuthClient.createLambda(lambdaId, { lambda });
if (!clientResponse.wasSuccessful()) {
errorAndExit(`Error creating lambda: `, clientResponse);
}
console.log(chalk.green(`Lambda created`));
}
catch (e: unknown) {
errorAndExit(`Error creating lambda: `, e);
}
}

// noinspection JSUnusedGlobalSymbols
export const lambdaCreate = new Command('lambda:create')
.summary('Create a lambda on FusionAuth')
.description(`Create a lambda on FusionAuth.
Copy link
Collaborator

@ColinFrick ColinFrick Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a short .summary('Create a lambda on FusionAuth') for commands with a large description. (lamdba:create, lambda:link-to-application, lamdba:unlink-from-application)

Example lambda .yaml file:

body: |
function populate(jwt, user, registration) {
jwt.message = 'Hello World!';
console.info('Hello World!');
}
debug: true
engineType: GraalJS
id: f3b3b547-7754-452d-8729-21b50d111505
insertInstant: 1692177291178
lastUpdateInstant: 1692211131823
name: '[ATestLambda]'
type: JWTPopulate
`)
.argument('<lambdaId>', 'The lambda id to create. The lambda is read from the file <id>.yaml in the <input> directory.')
.option('-i, --input <input>', 'The input directory', './lambdas/')
.addOption(apiKeyOption)
.addOption(hostOption)
.action(action);
3 changes: 2 additions & 1 deletion src/commands/lambda-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ const action = async function (lambdaId: string, {key: apiKey, host}: {
try {
const fusionAuthClient = new FusionAuthClient(apiKey, host);
const clientResponse = await fusionAuthClient.deleteLambda(lambdaId);
if (!clientResponse.wasSuccessful())
if (!clientResponse.wasSuccessful()) {
errorAndExit(`Error deleting lambda: `, clientResponse);
}
console.log(chalk.green(`Lambda deleted`));
}
catch (e: unknown) {
Expand Down
16 changes: 12 additions & 4 deletions src/commands/lambda-retrieve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {join} from 'path';
import {mkdir, writeFile} from 'fs/promises';
import {errorAndExit, toJson} from '../utils.js';
import {apiKeyOption, hostOption} from "../options.js";
import {dump as dumpYaml} from 'js-yaml';

const action = async function (lambdaId: string, {output, key: apiKey, host}: {
output: string;
Expand All @@ -16,12 +17,19 @@ const action = async function (lambdaId: string, {output, key: apiKey, host}: {
try {
const fusionAuthClient = new FusionAuthClient(apiKey, host);
const clientResponse = await fusionAuthClient.retrieveLambda(lambdaId);
if (!clientResponse.wasSuccessful())
if (!clientResponse.wasSuccessful()) {
errorAndExit(`Error retrieving lambda: `, clientResponse);
if (!existsSync(output))
}
if (!existsSync(output)) {
await mkdir(output);
const filename = join(output, clientResponse.response.lambda?.id + ".json");
await writeFile(filename, toJson(clientResponse.response.lambda));
}
const filename = join(output, clientResponse.response.lambda?.id + ".yaml");
const lambdaContent = clientResponse.response.lambda;
if (lambdaContent) {
lambdaContent.body = lambdaContent?.body?.replace(/\r\n/g, '\n'); // allow newlines in .yaml file
}
const yamlData = dumpYaml(lambdaContent, { styles: { '!!str': '|' } });
await writeFile(filename, yamlData);
console.log(chalk.green(`Lambda downloaded to ${filename}`));
}
catch (e: unknown) {
Expand Down
13 changes: 7 additions & 6 deletions src/commands/lambda-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import chalk from 'chalk';
import {join} from 'path';
import {errorAndExit} from '../utils.js';
import {apiKeyOption, hostOption} from "../options.js";
import {load as loadYaml} from 'js-yaml';

const action = async function (lambdaId: string, {input, key: apiKey, host}: {
input: string;
Expand All @@ -13,14 +14,14 @@ const action = async function (lambdaId: string, {input, key: apiKey, host}: {
}): Promise<void> {
console.log(`Updating lambda ${lambdaId} on ${host}`);
try {
const filename = join(input, lambdaId + ".json");
const filename = join(input, lambdaId + ".yaml");
const data = await readFile(filename, 'utf-8');
const lambda = JSON.parse(data);
const request = { lambda };
const lambda = loadYaml(data) as object;
const fusionAuthClient = new FusionAuthClient(apiKey, host);
const clientResponse = await fusionAuthClient.updateLambda(lambdaId, request);
if (!clientResponse.wasSuccessful())
const clientResponse = await fusionAuthClient.updateLambda(lambdaId, {lambda} );
if (!clientResponse.wasSuccessful()) {
errorAndExit(`Error updating lambda: `, clientResponse);
}
console.log(chalk.green(`Lambda updated`));
}
catch (e: unknown) {
Expand All @@ -31,7 +32,7 @@ const action = async function (lambdaId: string, {input, key: apiKey, host}: {
// noinspection JSUnusedGlobalSymbols
export const lambdaUpdate = new Command('lambda:update')
.description('Update a lambda on FusionAuth')
.argument('<lambdaId>', 'The lambda id to update. The lambda is read from the file <id>.json in the <input> directory.')
.argument('<lambdaId>', 'The lambda id to update. The lambda is read from the file <id>.yaml in the <input> directory.')
.option('-i, --input <input>', 'The input directory', './lambdas/')
.addOption(apiKeyOption)
.addOption(hostOption)
Expand Down
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ const fusionString = figlet.textSync('Fusion').split('\n');
const authString = figlet.textSync('Auth').split('\n');

fusionString.forEach((line, i) => {
console.log(chalk.white(line) + chalk.hex('#F58320')(authString[i]));
console.log(chalk.white(line) + chalk.hex('#F58320')(authString[i]));
});

const program = new Command();
program
.name('@fusionauth/cli')
.description('CLI for FusionAuth')
.version(pkg.version);
.name('@fusionauth/cli')
.description('CLI for FusionAuth')
.version(pkg.version);

Object.values(commands).forEach(command => program.addCommand(command));

program.parse();
program.parse();
16 changes: 16 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ClientResponse from '@fusionauth/typescript-client/build/src/ClientResponse.js';
import {FusionAuthClient, Application} from '@fusionauth/typescript-client';
import {Errors} from '@fusionauth/typescript-client';
import chalk from 'chalk';

Expand Down Expand Up @@ -126,3 +127,18 @@ export function errorAndExit(message: string, error?: any) {
reportError(message, error);
process.exit(1);
}

export async function getApplication(applicationId: string,
{key: apiKey, host}:
{
key: string;
host: string
}
): Promise<Application>
{
const fusionAuthClient = new FusionAuthClient(apiKey, host);
const clientResponse = await fusionAuthClient.retrieveApplication(applicationId);
if (!clientResponse.wasSuccessful() || !clientResponse.response.application)
errorAndExit(`Error retrieving application: `, clientResponse);
return clientResponse.response.application as Application;
}