Skip to content

Commit

Permalink
[repl] initial cli
Browse files Browse the repository at this point in the history
Co-authored-by: elf Pavlik <[email protected]>
  • Loading branch information
samurex and elf-pavlik committed Oct 9, 2024
1 parent 9d911d7 commit 7b50f2e
Show file tree
Hide file tree
Showing 10 changed files with 519 additions and 11 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"key":"setup/current-server-version","payload":"7.1.1"}
{"key":"setup/current-server-version","payload":"7.1.2"}
4 changes: 3 additions & 1 deletion packages/css-test-utils/src/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ const password = 'password';

export const shapeTree = {
Gadget: `${host}/solid/trees/Gadget`,
Widget: `${host}/solid/trees/Widget`
Widget: `${host}/solid/trees/Widget`,
Event: `${host}/solid/trees/Event`,
Contact: `${host}/solid/trees/Contact`
};

export type Application = {
Expand Down
5 changes: 4 additions & 1 deletion packages/css-test-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ export * from './css-util';
export * from './solid-test-utils';
export * from './config';
export * from './types';
export * as accounts from './accounts';
export { shapeTree } from './accounts';

import { luka, vaporcg, solid } from './accounts';
export const accounts = { luka, vaporcg, solid };
2 changes: 1 addition & 1 deletion packages/data-model/src/readable/data-registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { InteropFactory } from '..';
import { ReadableResource, ReadableShapeTree } from '.';

export class ReadableDataRegistration extends ReadableResource {
shapeTree?: ReadableShapeTree;
shapeTree: ReadableShapeTree;

private async bootstrap(): Promise<void> {
await this.fetchData();
Expand Down
161 changes: 161 additions & 0 deletions packages/repl/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
1. select account from accounts
2. create session
3. select operation for example:
- data registries
- select registry from list of registries
- list data registration from registry
- add data registration to registry
- select shape tree from list of shape trees
- go back
*/

import * as Command from '@effect/cli/Command';
import * as Prompt from '@effect/cli/Prompt';
import * as NodeContext from '@effect/platform-node/NodeContext';
import * as Runtime from '@effect/platform-node/NodeRuntime';
import { Context, Effect, Layer } from 'effect';

import { type Account, accounts, shapeTree, createApp, SolidTestUtils } from '@janeirodigital/css-test-utils';
import { AuthorizationAgent } from '@janeirodigital/interop-authorization-agent';
import { asyncIterableToArray } from '@janeirodigital/interop-utils';
import { init } from '@paralleldrive/cuid2';

const cuid = init({ length: 6 });

console.log('Server starting');
const server = await createApp();
await server.start();
console.log('Server started');

class SessionManager extends Context.Tag('SessionManager')<
SessionManager,
{ readonly getSession: (account: Account) => Effect.Effect<AuthorizationAgent> }
>() {}

const SessionManagerLive = Layer.succeed(
SessionManager,
SessionManager.of({
getSession: (account: Account) => Effect.promise(() => buildSession(account))
})
);

const createSelectDataRegistryPrompt = (registryList: string[]) => {
return Prompt.select({
message: 'Pick data registry',
choices: registryList.map((registry) => ({ title: registry, value: registry }))
});
};

const createSelectShapeTreePrompt = (shapeTreeList: string[]) => {
return Prompt.select({
message: 'Pick shape tree',
choices: shapeTreeList.map((st) => ({ title: st, value: st }))
});
};

const accountPrompt = Prompt.select({
message: 'Pick account',
choices: Object.keys(accounts).map((accountName: keyof typeof accounts) => ({
title: accountName,
value: accountName
}))
});

enum Actions {
createDataRegistration = 'createDataRegistration',
createSocialAgentRegistration = 'createSocialAgentRegistration'
}

const selectActionPrompt = Prompt.select({
message: 'Select action',
choices: [
{ title: 'Create data registration', value: Actions.createDataRegistration },
{ title: 'Create social agent registration', value: Actions.createSocialAgentRegistration }
]
});

const getSession = Effect.gen(function* () {
const sessionManager = yield* SessionManager;
const account = yield* accountPrompt;
return yield* sessionManager.getSession(accounts[account]);
});

const mainPrompt = Effect.provide(
Effect.gen(function* () {
const sessionManager = yield* SessionManager;

const action = yield* selectActionPrompt;

switch (action) {
case Actions.createDataRegistration:
yield* createDataRegistration.pipe(Effect.provideService(SessionManager, sessionManager));
break;
case Actions.createSocialAgentRegistration:
yield* createSocialAgentRegistration.pipe(Effect.provideService(SessionManager, sessionManager));
break;
}
}),
SessionManagerLive
);

const createDataRegistration = Effect.gen(function* () {
const sessionManager = yield* SessionManager;

const session = yield* getSession.pipe(Effect.provideService(SessionManager, sessionManager));

const registryId = yield* createSelectDataRegistryPrompt(session.registrySet.hasDataRegistry.map(({ iri }) => iri));

const registry = session.registrySet.hasDataRegistry.find(({ iri }) => iri === registryId)!;

const registrations = yield* Effect.promise(async () => asyncIterableToArray(registry.registrations));

const existingShapeTrees = registrations.map((registration) => registration.shapeTree.iri);

existingShapeTrees.forEach((iri) => console.log(iri));

const remainingShapeTrees = [...new Set(Object.values(shapeTree)).difference(new Set(existingShapeTrees))];

const shapeTreeId = yield* createSelectShapeTreePrompt(remainingShapeTrees);

yield* Effect.promise(async () => registry.createRegistration(shapeTreeId));
});

const createSocialAgentRegistration = Effect.gen(function* () {
const sessionManager = yield* SessionManager;

const account = yield* accountPrompt;

const session = yield* sessionManager.getSession(accounts[account]);

const webId = yield* Prompt.text({ message: 'Enter social agent name' });
const label = yield* Prompt.text({ message: 'Enter social agent label' });
const note = yield* Prompt.text({ message: 'Enter social agent note (optional)' });

yield* Effect.promise(async () =>
session.registrySet.hasAgentRegistry.addSocialAgentRegistration(webId, label, note)
);
});

const command = Command.make('sai', {}, () => mainPrompt);

const cli = Command.run(command, {
name: 'Prompt Examples',
version: '0.0.1'
});

Effect.suspend(() => cli(process.argv)).pipe(Effect.provide(NodeContext.layer), Runtime.runMain);

async function buildSession(account: Account): Promise<AuthorizationAgent> {
const stu = new SolidTestUtils(account);
await stu.auth();
return await AuthorizationAgent.build(
account.webId,
`https://auth.example/${account.shortName}`,
{
fetch: stu.authFetch,
randomUUID: cuid
},
account.registrySet
);
}
9 changes: 7 additions & 2 deletions packages/repl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,18 @@
"test": "test"
},
"scripts": {
"repl": "node --import=tsx ./repl.ts"
"repl": "tsx ./repl.ts",
"cli": "NODE_OPTIONS='--no-deprecation' tsx ./cli.ts"
},
"dependencies": {
"@janeirodigital/interop-utils": "^1.0.0-rc.24",
"@effect/cli": "^0.43.2",
"@effect/platform-node": "^0.59.0",
"effect": "^3.7.2"
},
"devDependencies": {
"@janeirodigital/interop-authorization-agent": "workspace:^1.0.0-rc.24",
"@janeirodigital/css-test-utils": "^1.0.0-rc.24",
"@janeirodigital/interop-authorization-agent": "workspace:^1.0.0-rc.24",
"@janeirodigital/interop-data-model": "workspace:^1.0.0-rc.24",
"@paralleldrive/cuid2": "^2.2.2",
"tsx": "^4.17.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/repl/repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { init } from '@paralleldrive/cuid2';
import type { CRUDRegistrySet, CRUDRegistrySetData } from '@janeirodigital/interop-data-model';
import { AuthorizationAgent } from '@janeirodigital/interop-authorization-agent';

import { type Account, accounts, createApp, SolidTestUtils } from '@janeirodigital/css-test-utils';
import { type Account, accounts, shapeTree, createApp, SolidTestUtils } from '@janeirodigital/css-test-utils';

global.shapeTrees = accounts.shapeTree;
global.shapeTrees = shapeTree;

global.cuid = init({ length: 6 });

Expand Down
Loading

0 comments on commit 7b50f2e

Please sign in to comment.