Skip to content
This repository was archived by the owner on Nov 15, 2024. It is now read-only.

Commit 166de37

Browse files
authored
feat: Merge pull request #21 from seamapi/feat-cli-browser
2 parents 030d332 + 8a7143f commit 166de37

20 files changed

+380
-105
lines changed

modules.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare module "https://unpkg.com/[email protected]/browser.mjs" {
2+
export const Yargs: any
3+
}
4+
declare module "esbuild-plugin-cache" {
5+
export const cache: any
6+
}

package.json

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@
1919
"import": "./dist/index.mjs",
2020
"types": "./dist/index.d.ts"
2121
},
22-
"./cli": {
23-
"require": "./dist/cli/index.js",
24-
"import": "./dist/cli/index.js",
25-
"types": "./dist/cli/index.d.ts"
22+
"./cli/browser": {
23+
"require": "./dist/cli/browser.js",
24+
"import": "./dist/cli/browser.mjs",
25+
"types": "./dist/cli/browser.d.ts"
26+
},
27+
"./dist/cli/browser": {
28+
"require": "./dist/cli/browser.js",
29+
"import": "./dist/cli/browser.mjs",
30+
"types": "./dist/cli/browser.d.ts"
2631
}
2732
},
2833
"files": [
@@ -32,6 +37,8 @@
3237
"dependencies": {
3338
"axios": "0.25.0",
3439
"change-case": "4.1.2",
40+
"eventemitter3": "4.0.7",
41+
"node-inspect-extracted": "1.1.0",
3542
"ora": "5.4.1",
3643
"yargs": "17.3.1"
3744
},
@@ -46,6 +53,7 @@
4653
"ajv": "8.9.0",
4754
"ava": "4.0.1",
4855
"esbuild": "0.14.18",
56+
"esbuild-plugin-cache": "0.2.9",
4957
"esbuild-runner": "2.2.1",
5058
"husky": ">=6",
5159
"knex": "1.0.2",
@@ -58,27 +66,27 @@
5866
"ts-json-schema-generator": "0.98.0",
5967
"tsup": "5.11.11",
6068
"type-fest": "2.11.1",
69+
"typed-emitter": "2.1.0",
6170
"typedoc": "0.22.12",
6271
"typedoc-plugin-markdown": "3.11.12",
6372
"typescript": "4.5.5"
6473
},
6574
"lint-staged": {
66-
"*.{ts,css,md}": "prettier --write"
75+
"*.{ts,css,md,js}": "prettier --write"
6776
},
6877
"pkg": {
69-
"outputPath": "cli-binaries",
70-
"assets": "./dist/cli/commands/**/*"
78+
"outputPath": "cli-binaries"
7179
},
7280
"scripts": {
7381
"prepare": "husky install",
7482
"prepack": "npm run build && npm run pack:cli",
7583
"build:package": "tsup",
7684
"build:docs": "typedoc",
85+
"build:json-response-schemas": "ts-json-schema-generator --path src/types/route-responses.ts -o src/types/route-responses.generated.json && ts-json-schema-generator --path src/types/models.ts -o src/types/models.generated.json",
7786
"build": "npm run build:package && npm run build:docs",
7887
"pack:cli": "pkg -c package.json dist/cli/entry.js",
7988
"format": "prettier --write .",
8089
"format:check": "prettier --check .",
81-
"build:json-response-schemas": "ts-json-schema-generator --path src/types/route-responses.ts -o src/types/route-responses.generated.json && ts-json-schema-generator --path src/types/models.ts -o src/types/models.generated.json",
8290
"test": "npm run build:json-response-schemas && ava",
8391
"test:watch": "npm run build:json-response-schemas && ava --watch",
8492
"cli:dev": "esr src/cli/entry.ts"

release.config.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,24 @@ module.exports = {
1212
"chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}",
1313
},
1414
],
15-
["@semantic-release/github", {
16-
"assets": [
17-
{"path": "cli-binaries/seamapi-linux", "label": "seamapi-linux-x64-${nextRelease.gitTag}"},
18-
{"path": "cli-binaries/seamapi-macos", "label": "seamapi-macos-x64-${nextRelease.gitTag}"},
19-
{"path": "cli-binaries/seamapi-win.exe", "label": "seamapi-win-x64-${nextRelease.gitTag}.exe"},
20-
]
21-
}],
15+
[
16+
"@semantic-release/github",
17+
{
18+
assets: [
19+
{
20+
path: "cli-binaries/seamapi-linux",
21+
label: "seamapi-linux-x64-${nextRelease.gitTag}",
22+
},
23+
{
24+
path: "cli-binaries/seamapi-macos",
25+
label: "seamapi-macos-x64-${nextRelease.gitTag}",
26+
},
27+
{
28+
path: "cli-binaries/seamapi-win.exe",
29+
label: "seamapi-win-x64-${nextRelease.gitTag}.exe",
30+
},
31+
],
32+
},
33+
],
2234
],
2335
}

src/cli/browser.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { getCLI } from "."
2+
import type Y from "yargs"
3+
// todo: replace with yargs/browser.mjs when https://github.com/yargs/yargs/pull/2144 is merged
4+
import { Yargs } from "https://unpkg.com/[email protected]/browser.mjs"
5+
import EventEmitter from "eventemitter3"
6+
import TypedEmitter from "typed-emitter"
7+
8+
const yargsInstance = Yargs() as ReturnType<typeof Y>
9+
10+
type CLIEvents = {
11+
data: (data: string) => void
12+
}
13+
14+
class BrowserCLI extends (EventEmitter as unknown as new () => TypedEmitter<CLIEvents>) {
15+
private instance = getCLI(yargsInstance).scriptName("seam")
16+
17+
/**
18+
* Use the Seam CLI in the browser!
19+
*/
20+
constructor(private apiKey?: string) {
21+
super()
22+
this.setUpShims()
23+
}
24+
25+
/**
26+
* Parse a command line string. Output will be emitted as data events.
27+
* @param input a given command string
28+
* @example
29+
* ```
30+
* const cli = new BrowserCLI()
31+
* await cli.parse("seam --help")
32+
* ```
33+
*/
34+
async parse(input: string) {
35+
this.setUpShims()
36+
37+
const inputWithKey = input.includes("--api-key")
38+
? input
39+
: `${input} --api-key ${this.apiKey}`
40+
41+
const inputWithKeyAndWithoutPrefix = inputWithKey.startsWith("seam ")
42+
? inputWithKey.replace("seam ", "")
43+
: inputWithKey.startsWith("seamapi ")
44+
? inputWithKey.replace("seamapi ", "")
45+
: inputWithKey
46+
47+
await new Promise<void>((resolve, reject) => {
48+
// .parseAsync isn't available in v16, so we listen for the ending newline instead
49+
const onData = (data: string) => {
50+
if (data === "\n") {
51+
this.removeListener("data", onData)
52+
resolve()
53+
}
54+
}
55+
this.on("data", onData)
56+
57+
this.instance.parse(
58+
inputWithKeyAndWithoutPrefix,
59+
(error: Error, _argv: any, output?: string) => {
60+
if (error) {
61+
this.removeListener("data", onData)
62+
return reject(error)
63+
}
64+
65+
if (output) {
66+
this.emit("data", output)
67+
this.emit("data", "\n")
68+
}
69+
}
70+
)
71+
})
72+
}
73+
74+
/**
75+
* Set the wrap value of the Yargs instance
76+
* @param columns number of columns to wrap to
77+
*/
78+
setWidth(columns: number) {
79+
this.instance = this.instance.wrap(columns)
80+
}
81+
82+
private setUpShims() {
83+
process.stdout = {} as any
84+
process.stdout.write = (data: string) => {
85+
this.emit("data", data)
86+
return true
87+
}
88+
}
89+
}
90+
91+
export default BrowserCLI

src/cli/commands/access-codes.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import executeCommand from "../execute-command"
2-
import { YargsWithGlobalOptions } from "../global-options"
1+
import { CommandModule } from "yargs"
2+
import executeCommand from "../lib/execute-command"
3+
import { GlobalOptions } from "../lib/global-options"
34

4-
export default {
5+
const command: CommandModule<GlobalOptions> = {
56
command: "access-codes",
67
aliases: ["access-code", "ac"],
78
describe: "interact with access codes",
8-
builder: (yargs: YargsWithGlobalOptions) => {
9-
yargs
9+
builder: (yargs) => {
10+
return yargs
1011
.demandCommand()
1112
.command(
1213
"list",
@@ -99,4 +100,7 @@ export default {
99100
}
100101
)
101102
},
103+
handler: () => {},
102104
}
105+
106+
export default command

src/cli/commands/action-attempts.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import executeCommand from "../execute-command"
2-
import { YargsWithGlobalOptions } from "../global-options"
1+
import { CommandModule } from "yargs"
2+
import executeCommand from "../lib/execute-command"
3+
import { GlobalOptions } from "../lib/global-options"
34

4-
export default {
5+
const command: CommandModule<GlobalOptions> = {
56
command: "action-attempts",
67
aliases: ["action-attempt", "aa"],
78
describe: "interact with action attempts",
8-
builder: (yargs: YargsWithGlobalOptions) => {
9-
yargs.demandCommand().command(
9+
builder: (yargs) => {
10+
return yargs.demandCommand().command(
1011
"get <id>",
1112
"get an action attempt",
1213
(yargs) => {
@@ -21,4 +22,7 @@ export default {
2122
}
2223
)
2324
},
25+
handler: () => {},
2426
}
27+
28+
export default command

src/cli/commands/connect-webviews.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
import { CommandModule } from "yargs"
12
import { Provider } from "../../types/models"
2-
import executeCommand from "../execute-command"
3-
import { YargsWithGlobalOptions } from "../global-options"
3+
import executeCommand from "../lib/execute-command"
4+
import { GlobalOptions } from "../lib/global-options"
45

5-
export default {
6+
const command: CommandModule<GlobalOptions> = {
67
command: "connect-webviews",
78
aliases: ["connect-webview", "cw"],
89
describe: "interact with connect webviews",
9-
builder: (yargs: YargsWithGlobalOptions) => {
10-
yargs
10+
builder: (yargs) => {
11+
return yargs
1112
.demandCommand()
1213
.command(
1314
"list",
@@ -65,4 +66,7 @@ export default {
6566
}
6667
)
6768
},
69+
handler: () => {},
6870
}
71+
72+
export default command

src/cli/commands/connected-accounts.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import executeCommand from "../execute-command"
2-
import { YargsWithGlobalOptions } from "../global-options"
1+
import { CommandModule } from "yargs"
2+
import executeCommand from "../lib/execute-command"
3+
import { GlobalOptions } from "../lib/global-options"
34

4-
export default {
5+
const command: CommandModule<GlobalOptions> = {
56
command: "connected-accounts",
67
aliases: ["connected-account", "ca"],
78
describe: "interact with connected accounts",
8-
builder: (yargs: YargsWithGlobalOptions) => {
9-
yargs
9+
builder: (yargs) => {
10+
return yargs
1011
.demandCommand()
1112
.command(
1213
"list",
@@ -31,4 +32,7 @@ export default {
3132
}
3233
)
3334
},
35+
handler: () => {},
3436
}
37+
38+
export default command

src/cli/commands/devices.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import executeCommand from "../execute-command"
2-
import { YargsWithGlobalOptions } from "../global-options"
1+
import { CommandModule } from "yargs"
2+
import executeCommand from "../lib/execute-command"
3+
import { GlobalOptions } from "../lib/global-options"
34

4-
export default {
5+
const command: CommandModule<GlobalOptions> = {
56
command: "devices",
67
aliases: ["device"],
78
describe: "interact with devices",
8-
builder: (yargs: YargsWithGlobalOptions) => {
9-
yargs
9+
builder: (yargs) => {
10+
return yargs
1011
.demandCommand()
1112
.command(
1213
"get <id>",
@@ -37,4 +38,7 @@ export default {
3738
}
3839
)
3940
},
41+
handler: () => {},
4042
}
43+
44+
export default command

src/cli/commands/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export * as accessCodes from "./access-codes"
2+
export * as actionAttempts from "./action-attempts"
3+
export * as connectWebviews from "./connect-webviews"
4+
export * as connectedAccounts from "./connected-accounts"
5+
export * as devices from "./devices"
6+
export * as locks from "./locks"
7+
export * as workspaces from "./workspaces"

0 commit comments

Comments
 (0)