incur 0.1.16 → 0.2.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.
- package/README.md +86 -0
- package/SKILL.md +42 -0
- package/dist/Cli.d.ts +25 -2
- package/dist/Cli.d.ts.map +1 -1
- package/dist/Cli.js +233 -25
- package/dist/Cli.js.map +1 -1
- package/dist/Fetch.d.ts +26 -0
- package/dist/Fetch.d.ts.map +1 -0
- package/dist/Fetch.js +150 -0
- package/dist/Fetch.js.map +1 -0
- package/dist/Help.d.ts +4 -0
- package/dist/Help.d.ts.map +1 -1
- package/dist/Help.js +11 -9
- package/dist/Help.js.map +1 -1
- package/dist/Openapi.d.ts +20 -0
- package/dist/Openapi.d.ts.map +1 -0
- package/dist/Openapi.js +136 -0
- package/dist/Openapi.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
- package/src/Cli.test-d.ts +2 -2
- package/src/Cli.test.ts +206 -2
- package/src/Cli.ts +273 -26
- package/src/Completions.test.ts +49 -0
- package/src/Fetch.test.ts +274 -0
- package/src/Fetch.ts +170 -0
- package/src/Help.test.ts +48 -0
- package/src/Help.ts +13 -6
- package/src/Openapi.test.ts +320 -0
- package/src/Openapi.ts +196 -0
- package/src/bun-compile.test.ts +84 -0
- package/src/e2e.test.ts +179 -5
- package/src/index.ts +2 -0
package/src/e2e.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Cli, Errors, Skill, Typegen, z } from 'incur'
|
|
2
|
+
import { app as honoApp } from '../test/fixtures/hono-api.js'
|
|
2
3
|
|
|
3
4
|
let __mockSkillsHash: string | undefined
|
|
4
5
|
|
|
@@ -816,12 +817,12 @@ describe('help', () => {
|
|
|
816
817
|
const { output, exitCode } = await serve(createApp(), [])
|
|
817
818
|
expect(exitCode).toBeUndefined()
|
|
818
819
|
expect(output).toMatchInlineSnapshot(`
|
|
819
|
-
"app — A comprehensive CLI application for testing.
|
|
820
|
-
v3.5.0
|
|
820
|
+
"app@3.5.0 — A comprehensive CLI application for testing.
|
|
821
821
|
|
|
822
822
|
Usage: app <command>
|
|
823
823
|
|
|
824
824
|
Commands:
|
|
825
|
+
api Proxy to HTTP API
|
|
825
826
|
auth Authentication commands
|
|
826
827
|
config Show current configuration
|
|
827
828
|
echo Echo back arguments
|
|
@@ -939,8 +940,8 @@ describe('help', () => {
|
|
|
939
940
|
--dry-run <boolean> Dry run mode (default: false)
|
|
940
941
|
|
|
941
942
|
Examples:
|
|
942
|
-
$ app project deploy create staging Deploy staging from main
|
|
943
|
-
$ app project deploy create production --branch release --dryRun true Dry run a production deploy
|
|
943
|
+
$ app project deploy create staging # Deploy staging from main
|
|
944
|
+
$ app project deploy create production --branch release --dryRun true # Dry run a production deploy
|
|
944
945
|
|
|
945
946
|
Global Options:
|
|
946
947
|
--format <toon|json|yaml|md|jsonl> Output format
|
|
@@ -969,7 +970,7 @@ describe('help', () => {
|
|
|
969
970
|
test('--help takes precedence over --version', async () => {
|
|
970
971
|
const { output } = await serve(createApp(), ['--help', '--version'])
|
|
971
972
|
expect(output).toContain('Usage: app <command>')
|
|
972
|
-
expect(output).toContain('
|
|
973
|
+
expect(output).toContain('app@3.5.0')
|
|
973
974
|
})
|
|
974
975
|
})
|
|
975
976
|
|
|
@@ -981,6 +982,7 @@ describe('--llms', () => {
|
|
|
981
982
|
const names = manifest.commands.map((c: any) => c.name)
|
|
982
983
|
expect(names).toMatchInlineSnapshot(`
|
|
983
984
|
[
|
|
985
|
+
"api",
|
|
984
986
|
"auth login",
|
|
985
987
|
"auth logout",
|
|
986
988
|
"auth status",
|
|
@@ -1181,6 +1183,7 @@ describe('typegen', () => {
|
|
|
1181
1183
|
"declare module 'incur' {
|
|
1182
1184
|
interface Register {
|
|
1183
1185
|
commands: {
|
|
1186
|
+
'api': { args: {}; options: {} }
|
|
1184
1187
|
'auth login': { args: {}; options: { hostname: string; web: boolean; scopes: string[] } }
|
|
1185
1188
|
'auth logout': { args: {}; options: {} }
|
|
1186
1189
|
'auth status': { args: {}; options: {} }
|
|
@@ -1765,6 +1768,176 @@ describe('deprecated flags', () => {
|
|
|
1765
1768
|
})
|
|
1766
1769
|
})
|
|
1767
1770
|
|
|
1771
|
+
describe('fetch gateway', () => {
|
|
1772
|
+
test('routes to fetch handler', async () => {
|
|
1773
|
+
const { output } = await serve(createApp(), ['api', 'health'])
|
|
1774
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1775
|
+
"ok: true
|
|
1776
|
+
"
|
|
1777
|
+
`)
|
|
1778
|
+
})
|
|
1779
|
+
|
|
1780
|
+
test('path segments map to URL path', async () => {
|
|
1781
|
+
const { output } = await serve(createApp(), ['api', 'users'])
|
|
1782
|
+
expect(output).toContain('Alice')
|
|
1783
|
+
})
|
|
1784
|
+
|
|
1785
|
+
test('path segments with dynamic params', async () => {
|
|
1786
|
+
const { output } = await serve(createApp(), ['api', 'users', '42'])
|
|
1787
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1788
|
+
"id: 42
|
|
1789
|
+
name: Alice
|
|
1790
|
+
"
|
|
1791
|
+
`)
|
|
1792
|
+
})
|
|
1793
|
+
|
|
1794
|
+
test('query params from --key value', async () => {
|
|
1795
|
+
const { output } = await serve(createApp(), ['api', 'users', '--limit', '5'])
|
|
1796
|
+
const { output: jsonOut } = await serve(createApp(), [
|
|
1797
|
+
'api',
|
|
1798
|
+
'users',
|
|
1799
|
+
'--limit',
|
|
1800
|
+
'5',
|
|
1801
|
+
'--format',
|
|
1802
|
+
'json',
|
|
1803
|
+
])
|
|
1804
|
+
expect(json(jsonOut).limit).toBe(5)
|
|
1805
|
+
})
|
|
1806
|
+
|
|
1807
|
+
test('POST with -X and -d', async () => {
|
|
1808
|
+
const { output } = await serve(createApp(), [
|
|
1809
|
+
'api',
|
|
1810
|
+
'users',
|
|
1811
|
+
'-X',
|
|
1812
|
+
'POST',
|
|
1813
|
+
'-d',
|
|
1814
|
+
'{"name":"Bob"}',
|
|
1815
|
+
])
|
|
1816
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1817
|
+
"created: true
|
|
1818
|
+
name: Bob
|
|
1819
|
+
"
|
|
1820
|
+
`)
|
|
1821
|
+
})
|
|
1822
|
+
|
|
1823
|
+
test('implicit POST with --body', async () => {
|
|
1824
|
+
const { output } = await serve(createApp(), [
|
|
1825
|
+
'api',
|
|
1826
|
+
'users',
|
|
1827
|
+
'--body',
|
|
1828
|
+
'{"name":"Eve"}',
|
|
1829
|
+
])
|
|
1830
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1831
|
+
"created: true
|
|
1832
|
+
name: Eve
|
|
1833
|
+
"
|
|
1834
|
+
`)
|
|
1835
|
+
})
|
|
1836
|
+
|
|
1837
|
+
test('DELETE with --method', async () => {
|
|
1838
|
+
const { output } = await serve(createApp(), [
|
|
1839
|
+
'api',
|
|
1840
|
+
'users',
|
|
1841
|
+
'1',
|
|
1842
|
+
'--method',
|
|
1843
|
+
'DELETE',
|
|
1844
|
+
])
|
|
1845
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1846
|
+
"deleted: true
|
|
1847
|
+
id: 1
|
|
1848
|
+
"
|
|
1849
|
+
`)
|
|
1850
|
+
})
|
|
1851
|
+
|
|
1852
|
+
test('error response produces error envelope', async () => {
|
|
1853
|
+
const { output, exitCode } = await serve(createApp(), ['api', 'error'])
|
|
1854
|
+
expect(exitCode).toBe(1)
|
|
1855
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1856
|
+
"code: HTTP_404
|
|
1857
|
+
message: not found
|
|
1858
|
+
"
|
|
1859
|
+
`)
|
|
1860
|
+
})
|
|
1861
|
+
|
|
1862
|
+
test('text response', async () => {
|
|
1863
|
+
const { output } = await serve(createApp(), ['api', 'text'])
|
|
1864
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1865
|
+
"hello world
|
|
1866
|
+
"
|
|
1867
|
+
`)
|
|
1868
|
+
})
|
|
1869
|
+
|
|
1870
|
+
test('--format json', async () => {
|
|
1871
|
+
const { output } = await serve(createApp(), ['api', 'health', '--format', 'json'])
|
|
1872
|
+
expect(json(output)).toEqual({ ok: true })
|
|
1873
|
+
})
|
|
1874
|
+
|
|
1875
|
+
test('--verbose wraps in envelope', async () => {
|
|
1876
|
+
const { output } = await serve(createApp(), [
|
|
1877
|
+
'api',
|
|
1878
|
+
'health',
|
|
1879
|
+
'--verbose',
|
|
1880
|
+
'--format',
|
|
1881
|
+
'json',
|
|
1882
|
+
])
|
|
1883
|
+
const parsed = json(output)
|
|
1884
|
+
expect(parsed.ok).toBe(true)
|
|
1885
|
+
expect(parsed.data).toEqual({ ok: true })
|
|
1886
|
+
expect(parsed.meta.command).toBe('api')
|
|
1887
|
+
expect(parsed.meta.duration).toBeDefined()
|
|
1888
|
+
})
|
|
1889
|
+
|
|
1890
|
+
test('--help shows curl-style flags', async () => {
|
|
1891
|
+
const { output } = await serve(createApp(), ['api', '--help'])
|
|
1892
|
+
expect(output).toContain('Proxy to HTTP API')
|
|
1893
|
+
expect(output).toContain('--method')
|
|
1894
|
+
expect(output).toContain('--header')
|
|
1895
|
+
expect(output).toContain('--body')
|
|
1896
|
+
expect(output).toContain('--data')
|
|
1897
|
+
})
|
|
1898
|
+
|
|
1899
|
+
test('appears in root --help', async () => {
|
|
1900
|
+
const { output } = await serve(createApp(), ['--help'])
|
|
1901
|
+
expect(output).toContain('api')
|
|
1902
|
+
expect(output).toContain('Proxy to HTTP API')
|
|
1903
|
+
})
|
|
1904
|
+
|
|
1905
|
+
test('appears in --llms', async () => {
|
|
1906
|
+
const { output } = await serve(createApp(), ['--llms'])
|
|
1907
|
+
expect(output).toContain('api')
|
|
1908
|
+
expect(output).toContain('Proxy to HTTP API')
|
|
1909
|
+
})
|
|
1910
|
+
|
|
1911
|
+
test('coexists with native commands', async () => {
|
|
1912
|
+
const { output: fetchOut } = await serve(createApp(), ['api', 'health'])
|
|
1913
|
+
expect(fetchOut).toContain('ok: true')
|
|
1914
|
+
const { output: nativeOut } = await serve(createApp(), ['ping'])
|
|
1915
|
+
expect(nativeOut).toContain('pong: true')
|
|
1916
|
+
})
|
|
1917
|
+
|
|
1918
|
+
test('streaming NDJSON response', async () => {
|
|
1919
|
+
const { output } = await serve(createApp(), ['api', 'stream'])
|
|
1920
|
+
expect(output).toMatchInlineSnapshot(`
|
|
1921
|
+
"progress: 1
|
|
1922
|
+
progress: 2
|
|
1923
|
+
"
|
|
1924
|
+
`)
|
|
1925
|
+
})
|
|
1926
|
+
|
|
1927
|
+
test('streaming NDJSON --format json buffers all chunks', async () => {
|
|
1928
|
+
const { output } = await serve(createApp(), ['api', 'stream', '--format', 'json'])
|
|
1929
|
+
expect(json(output)).toEqual([{ progress: 1 }, { progress: 2 }])
|
|
1930
|
+
})
|
|
1931
|
+
|
|
1932
|
+
test('streaming NDJSON --format jsonl', async () => {
|
|
1933
|
+
const { output } = await serve(createApp(), ['api', 'stream', '--format', 'jsonl'])
|
|
1934
|
+
const lines = output.trim().split('\n').map((l) => JSON.parse(l))
|
|
1935
|
+
expect(lines[0]).toEqual({ type: 'chunk', data: { progress: 1 } })
|
|
1936
|
+
expect(lines[1]).toEqual({ type: 'chunk', data: { progress: 2 } })
|
|
1937
|
+
expect(lines[2].type).toBe('done')
|
|
1938
|
+
})
|
|
1939
|
+
})
|
|
1940
|
+
|
|
1768
1941
|
async function serve(
|
|
1769
1942
|
cli: { serve: Cli.Cli['serve'] },
|
|
1770
1943
|
argv: string[],
|
|
@@ -2175,6 +2348,7 @@ function createApp() {
|
|
|
2175
2348
|
cli.command(auth)
|
|
2176
2349
|
cli.command(project)
|
|
2177
2350
|
cli.command(config)
|
|
2351
|
+
cli.command('api', { description: 'Proxy to HTTP API', fetch: honoApp.fetch })
|
|
2178
2352
|
|
|
2179
2353
|
return cli
|
|
2180
2354
|
}
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,8 @@ export * as Errors from './Errors.js'
|
|
|
7
7
|
export * as Formatter from './Formatter.js'
|
|
8
8
|
export * as Help from './Help.js'
|
|
9
9
|
export * as Mcp from './Mcp.js'
|
|
10
|
+
export * as Fetch from './Fetch.js'
|
|
11
|
+
export * as Openapi from './Openapi.js'
|
|
10
12
|
export * as Parser from './Parser.js'
|
|
11
13
|
export type { Register } from './Register.js'
|
|
12
14
|
export * as Schema from './Schema.js'
|