@carthooks/arcubase-cli 0.1.0 → 0.1.1

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.
@@ -112,8 +112,18 @@ function buildRequestHeaders(env) {
112
112
  }
113
113
  return headers;
114
114
  }
115
+ function normalizeExternalEndpoint(endpoint) {
116
+ const trimmed = endpoint.trim();
117
+ if (trimmed === "/api") {
118
+ return "/";
119
+ }
120
+ if (trimmed.startsWith("/api/")) {
121
+ return trimmed.slice(4);
122
+ }
123
+ return trimmed;
124
+ }
115
125
  function buildURL(baseURL, endpoint, query) {
116
- const url = new URL(endpoint, baseURL.endsWith("/") ? baseURL : `${baseURL}/`);
126
+ const url = new URL(normalizeExternalEndpoint(endpoint), baseURL.endsWith("/") ? baseURL : `${baseURL}/`);
117
127
  if (query) {
118
128
  for (const [key, value] of Object.entries(query)) {
119
129
  if (value === void 0 || value === null) continue;
@@ -9711,7 +9721,7 @@ function renderCommandHelp(scope, moduleName, commandName) {
9711
9721
  return [
9712
9722
  `${scope === "admin" ? "arcubase-admin" : "arcubase"} ${moduleName} ${commandName}`,
9713
9723
  `method: ${command.method}`,
9714
- `endpoint: ${command.endpoint}`,
9724
+ `endpoint: ${normalizeExternalEndpoint(command.endpoint)}`,
9715
9725
  command.requestType ? `body: ${command.requestType} via --body-file` : "body: none",
9716
9726
  command.endpointParams.length ? `path flags: ${command.endpointParams.map((item) => `--${item.replace(/_/g, "-")}`).join(", ")}` : "path flags: none",
9717
9727
  command.scalarParams.length ? `scalar flags: ${command.scalarParams.map((item) => `--${item.name.replace(/([A-Z])/g, "-$1").toLowerCase()}`).join(", ")}` : "scalar flags: none"
@@ -9777,7 +9787,7 @@ async function executeCLI(scope, argv, env = loadRuntimeEnv(scope), fetchImpl =
9777
9787
  if (!command) {
9778
9788
  throw new CLIError("UNKNOWN_COMMAND", `unknown command: ${moduleName} ${commandName}`, 2);
9779
9789
  }
9780
- const endpoint = resolveEndpoint(command.endpoint, parsed.flags);
9790
+ const endpoint = normalizeExternalEndpoint(resolveEndpoint(command.endpoint, parsed.flags));
9781
9791
  const scalarQuery = buildScalarQuery(command, parsed.flags);
9782
9792
  const fileQuery = loadQueryFromFlags(parsed.flags);
9783
9793
  const query = { ...scalarQuery ?? {}, ...fileQuery ?? {} };
@@ -112,8 +112,18 @@ function buildRequestHeaders(env) {
112
112
  }
113
113
  return headers;
114
114
  }
115
+ function normalizeExternalEndpoint(endpoint) {
116
+ const trimmed = endpoint.trim();
117
+ if (trimmed === "/api") {
118
+ return "/";
119
+ }
120
+ if (trimmed.startsWith("/api/")) {
121
+ return trimmed.slice(4);
122
+ }
123
+ return trimmed;
124
+ }
115
125
  function buildURL(baseURL, endpoint, query) {
116
- const url = new URL(endpoint, baseURL.endsWith("/") ? baseURL : `${baseURL}/`);
126
+ const url = new URL(normalizeExternalEndpoint(endpoint), baseURL.endsWith("/") ? baseURL : `${baseURL}/`);
117
127
  if (query) {
118
128
  for (const [key, value] of Object.entries(query)) {
119
129
  if (value === void 0 || value === null) continue;
@@ -9711,7 +9721,7 @@ function renderCommandHelp(scope, moduleName, commandName) {
9711
9721
  return [
9712
9722
  `${scope === "admin" ? "arcubase-admin" : "arcubase"} ${moduleName} ${commandName}`,
9713
9723
  `method: ${command.method}`,
9714
- `endpoint: ${command.endpoint}`,
9724
+ `endpoint: ${normalizeExternalEndpoint(command.endpoint)}`,
9715
9725
  command.requestType ? `body: ${command.requestType} via --body-file` : "body: none",
9716
9726
  command.endpointParams.length ? `path flags: ${command.endpointParams.map((item) => `--${item.replace(/_/g, "-")}`).join(", ")}` : "path flags: none",
9717
9727
  command.scalarParams.length ? `scalar flags: ${command.scalarParams.map((item) => `--${item.name.replace(/([A-Z])/g, "-$1").toLowerCase()}`).join(", ")}` : "scalar flags: none"
@@ -9777,7 +9787,7 @@ async function executeCLI(scope, argv, env = loadRuntimeEnv(scope), fetchImpl =
9777
9787
  if (!command) {
9778
9788
  throw new CLIError("UNKNOWN_COMMAND", `unknown command: ${moduleName} ${commandName}`, 2);
9779
9789
  }
9780
- const endpoint = resolveEndpoint(command.endpoint, parsed.flags);
9790
+ const endpoint = normalizeExternalEndpoint(resolveEndpoint(command.endpoint, parsed.flags));
9781
9791
  const scalarQuery = buildScalarQuery(command, parsed.flags);
9782
9792
  const fileQuery = loadQueryFromFlags(parsed.flags);
9783
9793
  const query = { ...scalarQuery ?? {}, ...fileQuery ?? {} };
@@ -1,7 +1,7 @@
1
1
  import { parseCLIArgs, hasFlag, flagValue } from './argv.js';
2
2
  import { loadRuntimeEnv } from './env.js';
3
3
  import { CLIError } from './errors.js';
4
- import { buildRequestHeaders, buildURL } from './http.js';
4
+ import { buildRequestHeaders, buildURL, normalizeExternalEndpoint } from './http.js';
5
5
  import { listModules, listModuleCommands, findCommand } from './command_registry.js';
6
6
  import { loadBodyFromFlags, loadQueryFromFlags } from './body_loader.js';
7
7
  import { getBodySchema, getTypeHints, getUnsupportedBodySchemaReason } from './zod_registry.js';
@@ -34,7 +34,7 @@ export function renderCommandHelp(scope, moduleName, commandName) {
34
34
  return [
35
35
  `${scope === 'admin' ? 'arcubase-admin' : 'arcubase'} ${moduleName} ${commandName}`,
36
36
  `method: ${command.method}`,
37
- `endpoint: ${command.endpoint}`,
37
+ `endpoint: ${normalizeExternalEndpoint(command.endpoint)}`,
38
38
  command.requestType ? `body: ${command.requestType} via --body-file` : 'body: none',
39
39
  command.endpointParams.length ? `path flags: ${command.endpointParams.map((item) => `--${item.replace(/_/g, '-')}`).join(', ')}` : 'path flags: none',
40
40
  command.scalarParams.length ? `scalar flags: ${command.scalarParams.map((item) => `--${item.name.replace(/([A-Z])/g, '-$1').toLowerCase()}`).join(', ')}` : 'scalar flags: none',
@@ -93,7 +93,7 @@ export function summarizeCommand(scope, moduleName, commandName) {
93
93
  scope,
94
94
  commandPath: command.commandPath,
95
95
  method: command.method,
96
- endpoint: command.endpoint,
96
+ endpoint: normalizeExternalEndpoint(command.endpoint),
97
97
  requestType: command.requestType,
98
98
  pathFlags: command.endpointParams,
99
99
  scalarFlags: command.scalarParams.map((item) => item.name.replace(/([A-Z])/g, '-$1').toLowerCase()),
@@ -118,7 +118,7 @@ export async function executeCLI(scope, argv, env = loadRuntimeEnv(scope), fetch
118
118
  if (!command) {
119
119
  throw new CLIError('UNKNOWN_COMMAND', `unknown command: ${moduleName} ${commandName}`, 2);
120
120
  }
121
- const endpoint = resolveEndpoint(command.endpoint, parsed.flags);
121
+ const endpoint = normalizeExternalEndpoint(resolveEndpoint(command.endpoint, parsed.flags));
122
122
  const scalarQuery = buildScalarQuery(command, parsed.flags);
123
123
  const fileQuery = loadQueryFromFlags(parsed.flags);
124
124
  const query = { ...(scalarQuery ?? {}), ...(fileQuery ?? {}) };
@@ -1,4 +1,5 @@
1
1
  import type { RuntimeEnv } from './env.js';
2
2
  export declare function buildRequestHeaders(env: Pick<RuntimeEnv, 'ARCUBASE_ACCESS_TOKEN' | 'ARCUBASE_TENANT_ID' | 'ARCUBASE_TRACE_ID'>): Record<string, string>;
3
+ export declare function normalizeExternalEndpoint(endpoint: string): string;
3
4
  export declare function buildURL(baseURL: string, endpoint: string, query?: Record<string, any>): string;
4
5
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/runtime/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,uBAAuB,GAAG,oBAAoB,GAAG,mBAAmB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASvJ;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAS/F"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/runtime/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,EAAE,uBAAuB,GAAG,oBAAoB,GAAG,mBAAmB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASvJ;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASlE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAS/F"}
@@ -8,8 +8,18 @@ export function buildRequestHeaders(env) {
8
8
  }
9
9
  return headers;
10
10
  }
11
+ export function normalizeExternalEndpoint(endpoint) {
12
+ const trimmed = endpoint.trim();
13
+ if (trimmed === '/api') {
14
+ return '/';
15
+ }
16
+ if (trimmed.startsWith('/api/')) {
17
+ return trimmed.slice(4);
18
+ }
19
+ return trimmed;
20
+ }
11
21
  export function buildURL(baseURL, endpoint, query) {
12
- const url = new URL(endpoint, baseURL.endsWith('/') ? baseURL : `${baseURL}/`);
22
+ const url = new URL(normalizeExternalEndpoint(endpoint), baseURL.endsWith('/') ? baseURL : `${baseURL}/`);
13
23
  if (query) {
14
24
  for (const [key, value] of Object.entries(query)) {
15
25
  if (value === undefined || value === null)
@@ -6,7 +6,7 @@ import path from 'path';
6
6
  import { executeCLI } from '../runtime/execute.js';
7
7
  import { CLIError } from '../runtime/errors.js';
8
8
  const env = {
9
- ARCUBASE_BASE_URL: 'https://arcubase.example.com/api/',
9
+ ARCUBASE_BASE_URL: 'https://arcubase.example.com',
10
10
  ARCUBASE_TENANT_ID: 'tenant_1',
11
11
  ARCUBASE_ACCESS_TOKEN: 'tok',
12
12
  ARCUBASE_TRACE_ID: '',
@@ -38,4 +38,10 @@ test('admin create entity executes with valid body file', async () => {
38
38
  const out = await executeCLI('admin', ['app', 'create-entity', '--id', 'app_1', '--body-file', bodyFile], env, async (url, init) => new Response(JSON.stringify({ ok: true, url, method: init?.method }), { status: 200 }));
39
39
  assert.equal(out.kind, 'result');
40
40
  assert.equal(out.status, 200);
41
+ assert.equal(out.data.url, 'https://arcubase.example.com/apps/app_1/entities');
42
+ });
43
+ test('admin api-prefixed command executes against external root path', async () => {
44
+ const out = await executeCLI('admin', ['app-entity-share', 'get-app-entity-shares', '--app-id', 'app_1'], env, async (url, init) => new Response(JSON.stringify({ ok: true, url, method: init?.method }), { status: 200 }));
45
+ assert.equal(out.kind, 'result');
46
+ assert.equal(out.data.url, 'https://arcubase.example.com/apps/app_1/entity-shares');
41
47
  });
@@ -2,7 +2,7 @@ import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { executeCLI } from '../runtime/execute.js';
4
4
  const env = {
5
- ARCUBASE_BASE_URL: 'https://arcubase.example.com/api/',
5
+ ARCUBASE_BASE_URL: 'https://arcubase.example.com',
6
6
  ARCUBASE_TENANT_ID: 'tenant_1',
7
7
  ARCUBASE_ACCESS_TOKEN: 'tok',
8
8
  ARCUBASE_TRACE_ID: '',
@@ -20,3 +20,9 @@ test('module help prints create-entity command', async () => {
20
20
  assert.equal(out.kind, 'help');
21
21
  assert.match(out.text, /create-entity/);
22
22
  });
23
+ test('command help prints normalized external endpoint', async () => {
24
+ const out = await executeCLI('admin', ['app-entity-share', 'get-app-entity-shares', '--help'], env, async () => new Response('{}'));
25
+ assert.equal(out.kind, 'help');
26
+ assert.match(out.text, /endpoint: \/apps\/:app_id\/entity-shares/);
27
+ assert.doesNotMatch(out.text, /endpoint: \/api\//);
28
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carthooks/arcubase-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Arcubase runtime CLI for admin and user command execution",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,8 +39,5 @@
39
39
  "ts-morph": "^25.0.1",
40
40
  "tsx": "^4.20.6",
41
41
  "typescript": "^5.3.3"
42
- },
43
- "publishConfig": {
44
- "access": "public"
45
42
  }
46
43
  }
@@ -1,7 +1,7 @@
1
1
  import { parseCLIArgs, hasFlag, flagValue } from './argv.js'
2
2
  import { loadRuntimeEnv, type RuntimeEnv } from './env.js'
3
3
  import { CLIError } from './errors.js'
4
- import { buildRequestHeaders, buildURL } from './http.js'
4
+ import { buildRequestHeaders, buildURL, normalizeExternalEndpoint } from './http.js'
5
5
  import { listModules, listModuleCommands, findCommand, type CommandScope } from './command_registry.js'
6
6
  import { loadBodyFromFlags, loadQueryFromFlags } from './body_loader.js'
7
7
  import { getBodySchema, getTypeHints, getUnsupportedBodySchemaReason } from './zod_registry.js'
@@ -47,7 +47,7 @@ export function renderCommandHelp(scope: CommandScope, moduleName: string, comma
47
47
  return [
48
48
  `${scope === 'admin' ? 'arcubase-admin' : 'arcubase'} ${moduleName} ${commandName}`,
49
49
  `method: ${command.method}`,
50
- `endpoint: ${command.endpoint}`,
50
+ `endpoint: ${normalizeExternalEndpoint(command.endpoint)}`,
51
51
  command.requestType ? `body: ${command.requestType} via --body-file` : 'body: none',
52
52
  command.endpointParams.length ? `path flags: ${command.endpointParams.map((item) => `--${item.replace(/_/g, '-')}`).join(', ')}` : 'path flags: none',
53
53
  command.scalarParams.length ? `scalar flags: ${command.scalarParams.map((item) => `--${item.name.replace(/([A-Z])/g, '-$1').toLowerCase()}`).join(', ')}` : 'scalar flags: none',
@@ -107,7 +107,7 @@ export function summarizeCommand(scope: CommandScope, moduleName: string, comman
107
107
  scope,
108
108
  commandPath: command.commandPath,
109
109
  method: command.method,
110
- endpoint: command.endpoint,
110
+ endpoint: normalizeExternalEndpoint(command.endpoint),
111
111
  requestType: command.requestType,
112
112
  pathFlags: command.endpointParams,
113
113
  scalarFlags: command.scalarParams.map((item) => item.name.replace(/([A-Z])/g, '-$1').toLowerCase()),
@@ -135,7 +135,7 @@ export async function executeCLI(scope: CommandScope, argv: string[], env: Runti
135
135
  throw new CLIError('UNKNOWN_COMMAND', `unknown command: ${moduleName} ${commandName}`, 2)
136
136
  }
137
137
 
138
- const endpoint = resolveEndpoint(command.endpoint, parsed.flags)
138
+ const endpoint = normalizeExternalEndpoint(resolveEndpoint(command.endpoint, parsed.flags))
139
139
  const scalarQuery = buildScalarQuery(command, parsed.flags)
140
140
  const fileQuery = loadQueryFromFlags(parsed.flags)
141
141
  const query = { ...(scalarQuery ?? {}), ...(fileQuery ?? {}) }
@@ -11,8 +11,19 @@ export function buildRequestHeaders(env: Pick<RuntimeEnv, 'ARCUBASE_ACCESS_TOKEN
11
11
  return headers
12
12
  }
13
13
 
14
+ export function normalizeExternalEndpoint(endpoint: string): string {
15
+ const trimmed = endpoint.trim()
16
+ if (trimmed === '/api') {
17
+ return '/'
18
+ }
19
+ if (trimmed.startsWith('/api/')) {
20
+ return trimmed.slice(4)
21
+ }
22
+ return trimmed
23
+ }
24
+
14
25
  export function buildURL(baseURL: string, endpoint: string, query?: Record<string, any>): string {
15
- const url = new URL(endpoint, baseURL.endsWith('/') ? baseURL : `${baseURL}/`)
26
+ const url = new URL(normalizeExternalEndpoint(endpoint), baseURL.endsWith('/') ? baseURL : `${baseURL}/`)
16
27
  if (query) {
17
28
  for (const [key, value] of Object.entries(query)) {
18
29
  if (value === undefined || value === null) continue
@@ -7,7 +7,7 @@ import { executeCLI } from '../runtime/execute.js'
7
7
  import { CLIError } from '../runtime/errors.js'
8
8
 
9
9
  const env = {
10
- ARCUBASE_BASE_URL: 'https://arcubase.example.com/api/',
10
+ ARCUBASE_BASE_URL: 'https://arcubase.example.com',
11
11
  ARCUBASE_TENANT_ID: 'tenant_1',
12
12
  ARCUBASE_ACCESS_TOKEN: 'tok',
13
13
  ARCUBASE_TRACE_ID: '',
@@ -47,4 +47,16 @@ test('admin create entity executes with valid body file', async () => {
47
47
  )
48
48
  assert.equal(out.kind, 'result')
49
49
  assert.equal(out.status, 200)
50
+ assert.equal(out.data.url, 'https://arcubase.example.com/apps/app_1/entities')
51
+ })
52
+
53
+ test('admin api-prefixed command executes against external root path', async () => {
54
+ const out = await executeCLI(
55
+ 'admin',
56
+ ['app-entity-share', 'get-app-entity-shares', '--app-id', 'app_1'],
57
+ env as any,
58
+ async (url, init) => new Response(JSON.stringify({ ok: true, url, method: init?.method }), { status: 200 })
59
+ )
60
+ assert.equal(out.kind, 'result')
61
+ assert.equal(out.data.url, 'https://arcubase.example.com/apps/app_1/entity-shares')
50
62
  })
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict'
3
3
  import { executeCLI } from '../runtime/execute.js'
4
4
 
5
5
  const env = {
6
- ARCUBASE_BASE_URL: 'https://arcubase.example.com/api/',
6
+ ARCUBASE_BASE_URL: 'https://arcubase.example.com',
7
7
  ARCUBASE_TENANT_ID: 'tenant_1',
8
8
  ARCUBASE_ACCESS_TOKEN: 'tok',
9
9
  ARCUBASE_TRACE_ID: '',
@@ -23,3 +23,10 @@ test('module help prints create-entity command', async () => {
23
23
  assert.equal(out.kind, 'help')
24
24
  assert.match(out.text, /create-entity/)
25
25
  })
26
+
27
+ test('command help prints normalized external endpoint', async () => {
28
+ const out = await executeCLI('admin', ['app-entity-share', 'get-app-entity-shares', '--help'], env as any, async () => new Response('{}'))
29
+ assert.equal(out.kind, 'help')
30
+ assert.match(out.text, /endpoint: \/apps\/:app_id\/entity-shares/)
31
+ assert.doesNotMatch(out.text, /endpoint: \/api\//)
32
+ })