kubun 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +22 -234
  2. package/bin/dev.js +12 -4
  3. package/bin/run.js +11 -2
  4. package/lib/account.d.ts +2 -0
  5. package/lib/account.js +5 -0
  6. package/lib/client.d.ts +2 -0
  7. package/{dist → lib}/client.js +4 -1
  8. package/lib/commands/account.d.ts +2 -0
  9. package/lib/commands/account.js +24 -0
  10. package/lib/commands/graph.d.ts +2 -0
  11. package/lib/commands/graph.js +74 -0
  12. package/lib/commands/graphql.d.ts +2 -0
  13. package/lib/commands/graphql.js +33 -0
  14. package/lib/commands/mcp.d.ts +2 -0
  15. package/lib/commands/mcp.js +21 -0
  16. package/lib/commands/model.d.ts +2 -0
  17. package/lib/commands/model.js +69 -0
  18. package/lib/commands/serve.d.ts +2 -0
  19. package/lib/commands/serve.js +116 -0
  20. package/lib/fs.d.ts +4 -0
  21. package/{dist → lib}/fs.js +6 -2
  22. package/lib/identity.d.ts +19 -0
  23. package/lib/identity.js +31 -0
  24. package/lib/index.d.ts +3 -0
  25. package/lib/index.js +19 -0
  26. package/lib/options.d.ts +19 -0
  27. package/lib/options.js +47 -0
  28. package/lib/program.d.ts +2 -0
  29. package/lib/program.js +28 -0
  30. package/lib/ui.d.ts +5 -0
  31. package/lib/ui.js +23 -0
  32. package/package.json +36 -45
  33. package/bin/dev.cmd +0 -3
  34. package/bin/run.cmd +0 -3
  35. package/dist/account.js +0 -5
  36. package/dist/commands/account/generate.js +0 -10
  37. package/dist/commands/account/id.js +0 -18
  38. package/dist/commands/graph/deploy.js +0 -32
  39. package/dist/commands/graph/mutate.js +0 -32
  40. package/dist/commands/graph/query.js +0 -32
  41. package/dist/commands/graphql/schema.js +0 -41
  42. package/dist/commands/mcp.js +0 -33
  43. package/dist/commands/model/cluster.js +0 -35
  44. package/dist/commands/model/create.js +0 -69
  45. package/dist/commands/serve.js +0 -126
  46. package/dist/index.js +0 -1
  47. package/oclif.manifest.json +0 -533
@@ -0,0 +1,116 @@
1
+ import { NodeSQLiteAdapter } from '@kubun/db-node-sqlite';
2
+ import { PostgresAdapter } from '@kubun/db-postgres';
3
+ import { KubunEngine } from '@kubun/engine';
4
+ import { getKubunLogger } from '@kubun/logger';
5
+ import { createHTTPPlugin } from '@kubun/plugin-http';
6
+ import { createP2PPlugin } from '@kubun/plugin-p2p';
7
+ import { createRPCPlugin } from '@kubun/plugin-rpc';
8
+ import { configureSync, getConsoleSink } from '@logtape/logtape';
9
+ import { Command } from 'commander';
10
+ import { resolvePath } from '../fs.js';
11
+ import { resolveIdentity } from '../identity.js';
12
+ import { withAllowedOrigin, withLogLevel, withPort, withPrivateKey } from '../options.js';
13
+ import { renderNotice, withSpinner } from '../ui.js';
14
+ export function createServeCommand() {
15
+ const cmd = new Command('serve').description('Start a local Kubun server').option('--auto-accept-peers <dids>', 'comma-separated DIDs to auto-accept for peer join flows').option('--db <path>', 'path to the local SQLite database').option('--id <id>', 'server ID').option('--p2p', 'enable P2P mode with sync and graph protocols over HTTP');
16
+ withAllowedOrigin(cmd);
17
+ withLogLevel(cmd);
18
+ withPort(cmd);
19
+ withPrivateKey(cmd);
20
+ cmd.action(async (opts)=>{
21
+ if (opts.id != null && opts.privateKey != null) {
22
+ throw new Error('--id and --private-key are mutually exclusive');
23
+ }
24
+ if (opts.autoAcceptPeers != null && !opts.p2p) {
25
+ throw new Error('--auto-accept-peers requires --p2p');
26
+ }
27
+ configureSync({
28
+ reset: true,
29
+ sinks: {
30
+ console: getConsoleSink()
31
+ },
32
+ loggers: [
33
+ {
34
+ category: [
35
+ 'logtape',
36
+ 'meta'
37
+ ],
38
+ lowestLevel: 'error',
39
+ sinks: [
40
+ 'console'
41
+ ]
42
+ },
43
+ {
44
+ category: [
45
+ 'kubun'
46
+ ],
47
+ lowestLevel: opts.logLevel ?? 'warning',
48
+ sinks: [
49
+ 'console'
50
+ ]
51
+ }
52
+ ]
53
+ });
54
+ const logger = getKubunLogger('cli');
55
+ const identity = resolveIdentity(opts, logger);
56
+ const adapter = opts.db == null || opts.db === ':memory:' ? new NodeSQLiteAdapter({
57
+ database: ':memory:'
58
+ }) : opts.db.startsWith('postgres://') || opts.db.startsWith('postgresql://') ? new PostgresAdapter({
59
+ url: opts.db
60
+ }) : new NodeSQLiteAdapter({
61
+ database: resolvePath(opts.db)
62
+ });
63
+ const autoAcceptPeers = opts.autoAcceptPeers ? opts.autoAcceptPeers.split(',').map((s)=>s.trim()) : undefined;
64
+ const rpcAccessRules = autoAcceptPeers != null ? {
65
+ '*': {
66
+ allow: [
67
+ identity.id,
68
+ ...autoAcceptPeers
69
+ ]
70
+ }
71
+ } : undefined;
72
+ const port = opts.port == null ? undefined : typeof opts.port === 'number' ? opts.port : Number.parseInt(opts.port, 10);
73
+ const plugins = [
74
+ createRPCPlugin({
75
+ ...rpcAccessRules != null ? {
76
+ accessRules: rpcAccessRules
77
+ } : undefined,
78
+ allowDelegatedMutations: opts.p2p
79
+ }),
80
+ createHTTPPlugin({
81
+ port,
82
+ allowedOrigin: opts.allowedOrigin
83
+ })
84
+ ];
85
+ if (opts.p2p) {
86
+ plugins.push(createP2PPlugin({
87
+ http: true,
88
+ autoAcceptPeers
89
+ }));
90
+ }
91
+ const engine = new KubunEngine({
92
+ db: adapter,
93
+ identity,
94
+ plugins
95
+ });
96
+ const http = await withSpinner('Starting the server...', async ()=>{
97
+ const api = await engine.getAPI('http');
98
+ await api.listening;
99
+ if (opts.p2p) {
100
+ const p2p = await engine.getAPI('p2p');
101
+ await p2p.syncReady;
102
+ }
103
+ return api;
104
+ });
105
+ renderNotice('success', `HTTP server listening at ${http.getURL()}\n DID: ${identity.id}`);
106
+ if (opts.p2p && autoAcceptPeers) {
107
+ process.stderr.write(` Auto-accept peers: ${autoAcceptPeers.length} DID(s)\n`);
108
+ }
109
+ await new Promise((resolve)=>{
110
+ process.once('SIGINT', resolve);
111
+ process.once('SIGTERM', resolve);
112
+ });
113
+ await engine.dispose();
114
+ });
115
+ return cmd;
116
+ }
package/lib/fs.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare function resolvePath(value: string): string;
2
+ export declare function readJSON<T = unknown>(path: string): Promise<T>;
3
+ export declare function writeFile(path: string, value: string): Promise<void>;
4
+ export declare function writeJSON(path: string, value: unknown, format?: boolean): Promise<void>;
@@ -4,10 +4,14 @@ export function resolvePath(value) {
4
4
  return isAbsolute(value) ? value : resolve(process.cwd(), value);
5
5
  }
6
6
  export async function readJSON(path) {
7
- return JSON.parse(await read(resolvePath(path), { encoding: 'utf8' }));
7
+ return JSON.parse(await read(resolvePath(path), {
8
+ encoding: 'utf8'
9
+ }));
8
10
  }
9
11
  export async function writeFile(path, value) {
10
- await write(resolvePath(path), value, { encoding: 'utf8' });
12
+ await write(resolvePath(path), value, {
13
+ encoding: 'utf8'
14
+ });
11
15
  }
12
16
  export async function writeJSON(path, value, format = false) {
13
17
  await writeFile(path, format ? JSON.stringify(value, null, 2) : JSON.stringify(value));
@@ -0,0 +1,19 @@
1
+ import type { Identity, OwnIdentity } from '@kokuin/token';
2
+ type Logger = {
3
+ warn: (message: string, properties?: Record<string, unknown>) => void;
4
+ };
5
+ export type IdentityOptions = {
6
+ privateKey?: string;
7
+ id?: string;
8
+ p2p?: boolean;
9
+ };
10
+ /**
11
+ * Resolve the server signing identity from CLI options.
12
+ *
13
+ * The random-identity fallback logs only the DID — never the private key — and
14
+ * flags that the identity is ephemeral so it is not mistaken for a persistent
15
+ * one. Logging the key would leak the server's signing secret to console sinks
16
+ * and log aggregation.
17
+ */
18
+ export declare function resolveIdentity(opts: IdentityOptions, logger: Logger): Identity | OwnIdentity;
19
+ export {};
@@ -0,0 +1,31 @@
1
+ import { createFullIdentity, randomIdentity } from '@kokuin/token';
2
+ import { fromB64 } from '@sozai/codec';
3
+ /**
4
+ * Resolve the server signing identity from CLI options.
5
+ *
6
+ * The random-identity fallback logs only the DID — never the private key — and
7
+ * flags that the identity is ephemeral so it is not mistaken for a persistent
8
+ * one. Logging the key would leak the server's signing secret to console sinks
9
+ * and log aggregation.
10
+ */ export function resolveIdentity(opts, logger) {
11
+ if (opts.privateKey != null) {
12
+ const privateKey = fromB64(opts.privateKey);
13
+ return {
14
+ ...createFullIdentity(privateKey),
15
+ privateKey
16
+ };
17
+ }
18
+ if (opts.id != null) {
19
+ if (opts.p2p) {
20
+ throw new Error('P2P mode requires a signing identity. Use --private-key instead of --id.');
21
+ }
22
+ return {
23
+ id: opts.id
24
+ };
25
+ }
26
+ const generated = randomIdentity();
27
+ logger.warn('No identity provided; generated an ephemeral one (DID: {id}). It is discarded on exit — pass --private-key or --id to persist.', {
28
+ id: generated.id
29
+ });
30
+ return generated;
31
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { buildProgram } from './program.js';
2
+ export { buildProgram };
3
+ export declare function run(argv: Array<string>): Promise<void>;
package/lib/index.js ADDED
@@ -0,0 +1,19 @@
1
+ import { buildProgram } from './program.js';
2
+ export { buildProgram };
3
+ export async function run(argv) {
4
+ const program = buildProgram();
5
+ if (argv.slice(2).length === 0) {
6
+ program.outputHelp();
7
+ return;
8
+ }
9
+ try {
10
+ await program.parseAsync(argv);
11
+ } catch (error) {
12
+ const message = error instanceof Error ? error.message : String(error);
13
+ process.stderr.write(`✘ ${message}\n`);
14
+ if (process.env.KUBUN_DEBUG === '1' && error instanceof Error && error.stack != null) {
15
+ process.stderr.write(`${error.stack}\n`);
16
+ }
17
+ process.exitCode = 1;
18
+ }
19
+ }
@@ -0,0 +1,19 @@
1
+ import type { Command } from 'commander';
2
+ /** Add `-k, --private-key <key>`, bound to KUBUN_PRIVATE_KEY, optionally required. */
3
+ export declare function withPrivateKey(cmd: Command, opts?: {
4
+ required?: boolean;
5
+ }): Command;
6
+ /** Add `--url <url>` for the Kubun server URL. */
7
+ export declare function withURL(cmd: Command): Command;
8
+ /** Add `-l, --log-level <level>` with the `warning` default and the logtape level set. */
9
+ export declare function withLogLevel(cmd: Command): Command;
10
+ /** Add `-p, --port <port>`, default resolved lazily from @tejika/env at action time. */
11
+ export declare function withPort(cmd: Command): Command;
12
+ /**
13
+ * Add `-a, --allowed-origin <origin>`, bound to KUBUN_ALLOWED_ORIGIN.
14
+ *
15
+ * No default: an unset option denies cross-origin browser requests. Opening a
16
+ * surface is an explicit choice — pass `-a '*'` to reflect any origin, or a
17
+ * comma-separated list to allow only those.
18
+ */
19
+ export declare function withAllowedOrigin(cmd: Command): Command;
package/lib/options.js ADDED
@@ -0,0 +1,47 @@
1
+ import { getLogLevels } from '@logtape/logtape';
2
+ import { getAppEnvVar, getPort } from '@tejika/env';
3
+ /** Add `-k, --private-key <key>`, bound to KUBUN_PRIVATE_KEY, optionally required. */ export function withPrivateKey(cmd, opts = {}) {
4
+ cmd.option('-k, --private-key <key>', 'base64-encoded private key (env: KUBUN_PRIVATE_KEY)');
5
+ cmd.hook('preAction', (_thisCmd, actionCmd)=>{
6
+ if (actionCmd.opts().privateKey == null && process.env.KUBUN_PRIVATE_KEY != null) {
7
+ actionCmd.setOptionValue('privateKey', process.env.KUBUN_PRIVATE_KEY);
8
+ }
9
+ if (opts.required && actionCmd.opts().privateKey == null) {
10
+ throw new Error('--private-key is required (or set KUBUN_PRIVATE_KEY)');
11
+ }
12
+ });
13
+ return cmd;
14
+ }
15
+ /** Add `--url <url>` for the Kubun server URL. */ export function withURL(cmd) {
16
+ return cmd.option('--url <url>', 'Kubun server URL');
17
+ }
18
+ /** Add `-l, --log-level <level>` with the `warning` default and the logtape level set. */ export function withLogLevel(cmd) {
19
+ return cmd.option('-l, --log-level <level>', `log level (${getLogLevels().join(', ')})`, 'warning');
20
+ }
21
+ /** Add `-p, --port <port>`, default resolved lazily from @tejika/env at action time. */ export function withPort(cmd) {
22
+ cmd.option('-p, --port <port>', 'port to listen on');
23
+ cmd.hook('preAction', async (_thisCmd, actionCmd)=>{
24
+ if (actionCmd.opts().port == null) {
25
+ actionCmd.setOptionValue('port', await getPort('kubun'));
26
+ }
27
+ });
28
+ return cmd;
29
+ }
30
+ /**
31
+ * Add `-a, --allowed-origin <origin>`, bound to KUBUN_ALLOWED_ORIGIN.
32
+ *
33
+ * No default: an unset option denies cross-origin browser requests. Opening a
34
+ * surface is an explicit choice — pass `-a '*'` to reflect any origin, or a
35
+ * comma-separated list to allow only those.
36
+ */ export function withAllowedOrigin(cmd) {
37
+ cmd.option('-a, --allowed-origin <origin>', 'allowed HTTP origin(s), comma-separated (env: KUBUN_ALLOWED_ORIGIN); unset denies cross-origin browser requests');
38
+ cmd.hook('preAction', (_thisCmd, actionCmd)=>{
39
+ if (actionCmd.opts().allowedOrigin == null) {
40
+ const envOrigin = getAppEnvVar('kubun', 'ALLOWED_ORIGIN');
41
+ if (envOrigin != null) {
42
+ actionCmd.setOptionValue('allowedOrigin', envOrigin);
43
+ }
44
+ }
45
+ });
46
+ return cmd;
47
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function buildProgram(): Command;
package/lib/program.js ADDED
@@ -0,0 +1,28 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { buildProgram as tejikaBuildProgram } from '@tejika/cli';
5
+ import { createAccountCommand } from './commands/account.js';
6
+ import { createGraphCommand } from './commands/graph.js';
7
+ import { createGraphQLCommand } from './commands/graphql.js';
8
+ import { createMCPCommand } from './commands/mcp.js';
9
+ import { createModelCommand } from './commands/model.js';
10
+ import { createServeCommand } from './commands/serve.js';
11
+ const pkgPath = resolve(dirname(fileURLToPath(import.meta.url)), '../package.json');
12
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
13
+ export function buildProgram() {
14
+ const program = tejikaBuildProgram({
15
+ name: 'kubun',
16
+ version: pkg.version,
17
+ commands: [
18
+ createAccountCommand(),
19
+ createGraphCommand(),
20
+ createGraphQLCommand(),
21
+ createModelCommand(),
22
+ createMCPCommand(),
23
+ createServeCommand()
24
+ ]
25
+ });
26
+ program.description(pkg.description);
27
+ return program;
28
+ }
package/lib/ui.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { type SystemNoticeVariant } from '@tejika/ui';
2
+ /** Render a one-shot status notice to stderr, then unmount. */
3
+ export declare function renderNotice(variant: SystemNoticeVariant, text: string): void;
4
+ /** Show a live spinner on stderr for the duration of `fn`, then unmount. */
5
+ export declare function withSpinner<T>(label: string, fn: () => Promise<T>): Promise<T>;
package/lib/ui.js ADDED
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Spinner, SystemNotice } from '@tejika/ui';
3
+ import { render } from 'ink';
4
+ const renderToStderr = {
5
+ stdout: process.stderr
6
+ };
7
+ /** Render a one-shot status notice to stderr, then unmount. */ export function renderNotice(variant, text) {
8
+ const { unmount } = render(/*#__PURE__*/ _jsx(SystemNotice, {
9
+ variant: variant,
10
+ text: text
11
+ }), renderToStderr);
12
+ unmount();
13
+ }
14
+ /** Show a live spinner on stderr for the duration of `fn`, then unmount. */ export async function withSpinner(label, fn) {
15
+ const app = render(/*#__PURE__*/ _jsx(Spinner, {
16
+ label: label
17
+ }), renderToStderr);
18
+ try {
19
+ return await fn();
20
+ } finally{
21
+ app.unmount();
22
+ }
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kubun",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "license": "see LICENSE.md",
5
5
  "description": "Kubun CLI",
6
6
  "keywords": [],
@@ -8,61 +8,52 @@
8
8
  "engines": {
9
9
  "node": ">=22.0.0"
10
10
  },
11
- "main": "dist/index.js",
12
- "types": "dist/index.d.ts",
11
+ "main": "lib/index.js",
12
+ "types": "lib/index.d.ts",
13
13
  "files": [
14
14
  "/bin",
15
- "/dist",
16
- "/oclif.manifest.json"
15
+ "/lib"
17
16
  ],
18
17
  "bin": {
19
18
  "kubun": "./bin/run.js"
20
19
  },
21
- "oclif": {
22
- "bin": "kubun",
23
- "dirname": "kubun",
24
- "commands": "./dist/commands",
25
- "plugins": [
26
- "@oclif/plugin-help"
27
- ],
28
- "topicSeparator": " "
29
- },
30
20
  "dependencies": {
31
- "@enkaku/codec": "^0.15.0",
32
- "@enkaku/token": "^0.15.0",
33
- "@logtape/logtape": "^2.0.7",
34
- "@mokei/context-server": "^0.6.0",
35
- "@oclif/core": "^4.11.0",
36
- "@oclif/plugin-help": "^6.2.46",
37
- "@oclif/plugin-plugins": "^5.4.63",
38
- "graphql": "^16.13.2",
39
- "ora": "^9.4.0",
40
- "@kubun/client": "^0.9.0",
41
- "@kubun/db-node-sqlite": "^0.9.0",
42
- "@kubun/db-postgres": "^0.9.0",
43
- "@kubun/http-client": "^0.9.0",
44
- "@kubun/engine": "^0.9.0",
45
- "@kubun/logger": "^0.9.0",
46
- "@kubun/graphql": "^0.9.0",
47
- "@kubun/plugin-p2p": "^0.9.0",
48
- "@kubun/plugin-http": "^0.9.0",
49
- "@kubun/mcp": "^0.9.0",
50
- "@kubun/plugin-rpc": "^0.9.0",
51
- "@kubun/protocol": "^0.9.0"
21
+ "@kokuin/token": "^0.1.1",
22
+ "@logtape/logtape": "^2.2.3",
23
+ "@mokei/context-server": "^0.8.0",
24
+ "@sozai/codec": "^0.1.0",
25
+ "@tejika/cli": "^0.1.0",
26
+ "@tejika/env": "^0.1.0",
27
+ "@tejika/ui": "^0.1.0",
28
+ "commander": "^15.0.0",
29
+ "graphql": "^16.14.2",
30
+ "ink": "^7.1.0",
31
+ "react": "19.2.3",
32
+ "@kubun/client": "^0.11.0",
33
+ "@kubun/engine": "^0.11.0",
34
+ "@kubun/db-node-sqlite": "^0.11.0",
35
+ "@kubun/http-client": "^0.11.0",
36
+ "@kubun/mcp": "^0.11.0",
37
+ "@kubun/graphql": "^0.11.0",
38
+ "@kubun/db-postgres": "^0.11.0",
39
+ "@kubun/logger": "^0.11.0",
40
+ "@kubun/plugin-p2p": "^0.11.0",
41
+ "@kubun/plugin-rpc": "^0.11.0",
42
+ "@kubun/plugin-http": "^0.11.0",
43
+ "@kubun/protocol": "^0.11.0"
52
44
  },
53
45
  "devDependencies": {
54
- "@oclif/test": "^4.1.17",
55
- "oclif": "^4.22.96",
56
- "ts-node": "^10",
57
- "typescript": "^6.0.3"
46
+ "ink-testing-library": "^4.0.0"
58
47
  },
59
48
  "scripts": {
60
49
  "kubun": "./bin/dev.js",
61
- "build": "del dist && tsc -b",
62
- "posttest": "pnpm run lint",
63
- "test:types": "tsc --noEmit",
64
- "test:unit": "OCLIF_TEST_ROOT=. vitest run",
65
- "test": "pnpm run test:types && pnpm run test:unit",
66
- "version": "oclif readme && git add README.md"
50
+ "build:clean": "del lib",
51
+ "build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
52
+ "build:types": "tsc --emitDeclarationOnly --skipLibCheck",
53
+ "build:types:ci": "tsc --emitDeclarationOnly --skipLibCheck --declarationMap false",
54
+ "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
55
+ "test:types": "tsc --noEmit --skipLibCheck",
56
+ "test:unit": "vitest run",
57
+ "test": "pnpm run test:types && pnpm run test:unit"
67
58
  }
68
59
  }
package/bin/dev.cmd DELETED
@@ -1,3 +0,0 @@
1
- @echo off
2
-
3
- node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %*
package/bin/run.cmd DELETED
@@ -1,3 +0,0 @@
1
- @echo off
2
-
3
- node "%~dp0\run" %*
package/dist/account.js DELETED
@@ -1,5 +0,0 @@
1
- import { fromB64 } from '@enkaku/codec';
2
- import { createSigningIdentity } from '@enkaku/token';
3
- export function getSigner(key) {
4
- return createSigningIdentity(fromB64(key));
5
- }
@@ -1,10 +0,0 @@
1
- import { toB64 } from '@enkaku/codec';
2
- import { randomPrivateKey } from '@enkaku/token';
3
- import { Command } from '@oclif/core';
4
- export default class GenerateAccount extends Command {
5
- static description = 'Generate a random private key to use as account signer';
6
- async run() {
7
- const key = await randomPrivateKey();
8
- this.log(toB64(key));
9
- }
10
- }
@@ -1,18 +0,0 @@
1
- import { Command, Flags } from '@oclif/core';
2
- import { getSigner } from '../../account.js';
3
- export default class AccountID extends Command {
4
- static description = 'Display the DID of an account given its private key';
5
- static flags = {
6
- privateKey: Flags.string({
7
- description: 'base64-encoded private key',
8
- char: 'k',
9
- env: 'KUBUN_PRIVATE_KEY',
10
- required: true,
11
- }),
12
- };
13
- async run() {
14
- const { flags } = await this.parse(AccountID);
15
- const signer = getSigner(flags.privateKey);
16
- this.log(signer.id);
17
- }
18
- }
@@ -1,32 +0,0 @@
1
- import { Command, Flags } from '@oclif/core';
2
- import ora from 'ora';
3
- import { createClient } from '../../client.js';
4
- import { readJSON } from '../../fs.js';
5
- export default class DeployGraph extends Command {
6
- static description = 'Deploy a documents model graph';
7
- static flags = {
8
- cluster: Flags.string({
9
- description: 'path of the JSON file of the cluster',
10
- char: 'c',
11
- required: true,
12
- multiple: true,
13
- }),
14
- id: Flags.string({ description: 'graph ID' }),
15
- name: Flags.string({ description: 'graph name', char: 'n' }),
16
- privateKey: Flags.string({
17
- description: 'base64-encoded private key',
18
- char: 'k',
19
- env: 'KUBUN_PRIVATE_KEY',
20
- required: true,
21
- }),
22
- url: Flags.string({ description: 'Kubun server URL' }),
23
- };
24
- async run() {
25
- const spinner = ora('Deploying graph clusters...').start();
26
- const { flags } = await this.parse(DeployGraph);
27
- const client = createClient(flags.privateKey, flags.url);
28
- const clusters = await Promise.all(flags.cluster.map((path) => readJSON(path)));
29
- const graph = await client.deployGraph({ clusters, id: flags.id, name: flags.name });
30
- spinner.succeed(`Deployed graph with ID: ${graph.id}`);
31
- }
32
- }
@@ -1,32 +0,0 @@
1
- import { Args, Command, Flags } from '@oclif/core';
2
- import ora from 'ora';
3
- import { createClient } from '../../client.js';
4
- export default class MutateGraph extends Command {
5
- static description = 'Execute a GraphQL mutation on a graph';
6
- static args = {
7
- id: Args.string({ description: 'graph ID', required: true }),
8
- text: Args.string({ description: 'mutation text', required: true }),
9
- };
10
- static flags = {
11
- privateKey: Flags.string({
12
- description: 'base64-encoded private key',
13
- char: 'k',
14
- env: 'KUBUN_PRIVATE_KEY',
15
- required: true,
16
- }),
17
- url: Flags.string({ description: 'Kubun server URL' }),
18
- variables: Flags.string({ description: 'query variables as JSON string' }),
19
- };
20
- async run() {
21
- const spinner = ora('Executing graph mutation...').start();
22
- const { args, flags } = await this.parse(MutateGraph);
23
- const client = createClient(flags.privateKey, flags.url);
24
- const result = await client.mutateGraph({
25
- id: args.id,
26
- text: args.text,
27
- variables: flags.variables ? JSON.parse(flags.variables) : {},
28
- });
29
- spinner.succeed('Graph mutation executed');
30
- this.log(JSON.stringify(result, null, 2));
31
- }
32
- }
@@ -1,32 +0,0 @@
1
- import { Args, Command, Flags } from '@oclif/core';
2
- import ora from 'ora';
3
- import { createClient } from '../../client.js';
4
- export default class QueryGraph extends Command {
5
- static description = 'Execute a GraphQL query on a graph';
6
- static args = {
7
- id: Args.string({ description: 'graph ID', required: true }),
8
- text: Args.string({ description: 'query text', required: true }),
9
- };
10
- static flags = {
11
- privateKey: Flags.string({
12
- description: 'base64-encoded private key',
13
- char: 'k',
14
- env: 'KUBUN_PRIVATE_KEY',
15
- required: true,
16
- }),
17
- url: Flags.string({ description: 'Kubun server URL' }),
18
- variables: Flags.string({ description: 'query variables as JSON string' }),
19
- };
20
- async run() {
21
- const spinner = ora('Querying graph...').start();
22
- const { args, flags } = await this.parse(QueryGraph);
23
- const client = createClient(flags.privateKey, flags.url);
24
- const result = await client.queryGraph({
25
- id: args.id,
26
- text: args.text,
27
- variables: flags.variables ? JSON.parse(flags.variables) : {},
28
- });
29
- spinner.succeed('Graph query executed');
30
- this.log(JSON.stringify(result, null, 2));
31
- }
32
- }
@@ -1,41 +0,0 @@
1
- import { createSchema } from '@kubun/graphql';
2
- import { clusterToRecord, GraphModel, } from '@kubun/protocol';
3
- import { Command, Flags } from '@oclif/core';
4
- import { printSchema } from 'graphql';
5
- import ora from 'ora';
6
- import { readJSON, writeFile } from '../../fs.js';
7
- export default class CreateGraphQLSchema extends Command {
8
- static description = 'Create a GraphQL schema from clusters of document models';
9
- static flags = {
10
- cluster: Flags.string({
11
- description: 'path of the JSON file of the cluster',
12
- char: 'c',
13
- required: true,
14
- multiple: true,
15
- }),
16
- output: Flags.file({
17
- description: 'output file for the GraphQL schema',
18
- char: 'o',
19
- }),
20
- };
21
- async run() {
22
- const spinner = ora('Loading clusters...').start();
23
- const { flags } = await this.parse(CreateGraphQLSchema);
24
- const clusterModels = await Promise.all(flags.cluster.map((path) => readJSON(path)));
25
- const clusters = {};
26
- for (const cluster of clusterModels) {
27
- Object.assign(clusters, clusterToRecord(cluster));
28
- }
29
- const model = GraphModel.fromClusters({ clusters });
30
- const schema = printSchema(createSchema(model));
31
- if (flags.output == null) {
32
- spinner.succeed('GraphQL schema generated');
33
- this.log(schema);
34
- }
35
- else {
36
- await writeFile(flags.output, schema);
37
- spinner.succeed(`GraphQL schema written to ${flags.output}`);
38
- }
39
- return schema;
40
- }
41
- }