@carthooks/arcubase-cli 0.1.7 → 0.1.9

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 (66) hide show
  1. package/bundle/arcubase-admin.mjs +1042 -5056
  2. package/bundle/arcubase.mjs +1042 -5056
  3. package/dist/generated/command_registry.generated.d.ts +693 -2812
  4. package/dist/generated/command_registry.generated.d.ts.map +1 -1
  5. package/dist/generated/command_registry.generated.js +812 -4100
  6. package/dist/generated/type_index.generated.d.ts +8 -397
  7. package/dist/generated/type_index.generated.d.ts.map +1 -1
  8. package/dist/generated/type_index.generated.js +8 -403
  9. package/dist/generated/zod_registry.generated.d.ts +33 -261
  10. package/dist/generated/zod_registry.generated.d.ts.map +1 -1
  11. package/dist/generated/zod_registry.generated.js +36 -365
  12. package/dist/runtime/body_loader.d.ts.map +1 -1
  13. package/dist/runtime/body_loader.js +12 -0
  14. package/dist/runtime/command_registry.d.ts +3 -21
  15. package/dist/runtime/command_registry.d.ts.map +1 -1
  16. package/dist/runtime/command_registry.js +17 -23
  17. package/dist/runtime/execute.d.ts +3 -3
  18. package/dist/runtime/execute.d.ts.map +1 -1
  19. package/dist/runtime/execute.js +53 -157
  20. package/dist/runtime/http.js +1 -1
  21. package/dist/runtime/upload.js +3 -3
  22. package/dist/runtime/zod_registry.d.ts.map +1 -1
  23. package/dist/runtime/zod_registry.js +7 -24
  24. package/dist/tests/command_registry.test.js +81 -28
  25. package/dist/tests/execute_validation.test.js +175 -510
  26. package/dist/tests/help.test.js +39 -62
  27. package/dist/tests/upload.test.js +4 -4
  28. package/dist/tests/zod_registry.test.js +0 -10
  29. package/package.json +1 -1
  30. package/sdk-dist/docs/runtime-reference/README.md +20 -30
  31. package/sdk-dist/docs/runtime-reference/entity-schema/README.md +4 -5
  32. package/sdk-dist/docs/runtime-reference/entity-schema/linkto.md +3 -3
  33. package/sdk-dist/docs/runtime-reference/entity-schema/query.md +3 -3
  34. package/sdk-dist/docs/runtime-reference/entity-schema/relation.md +3 -3
  35. package/sdk-dist/docs/runtime-reference/entity-schema/relationfield.md +3 -3
  36. package/sdk-dist/docs/runtime-reference/entity-schema/subform.md +2 -2
  37. package/sdk-dist/docs/runtime-reference/entity-schema.md +4 -4
  38. package/sdk-dist/docs/runtime-reference/examples/README.md +2 -2
  39. package/sdk-dist/docs/runtime-reference/examples/oms-01/README.md +12 -12
  40. package/sdk-dist/docs/runtime-reference/examples/oms-01/app-overview.md +1 -1
  41. package/sdk-dist/docs/runtime-reference/row-crud.md +11 -32
  42. package/sdk-dist/docs/runtime-reference/search-and-bulk-actions.md +16 -47
  43. package/sdk-dist/docs/runtime-reference/table-lifecycle.md +11 -27
  44. package/sdk-dist/docs/runtime-reference/uploads.md +1 -1
  45. package/sdk-dist/docs/runtime-reference/workflow/README.md +19 -0
  46. package/sdk-dist/generated/command_registry.generated.ts +814 -4102
  47. package/sdk-dist/generated/type_index.generated.ts +8 -403
  48. package/sdk-dist/generated/zod_registry.generated.ts +44 -500
  49. package/sdk-dist/types/app.ts +3 -10
  50. package/sdk-dist/types/common.ts +7 -0
  51. package/sdk-dist/types/global-action.ts +2 -1
  52. package/src/generated/command_registry.generated.ts +814 -4102
  53. package/src/generated/type_index.generated.ts +8 -403
  54. package/src/generated/zod_registry.generated.ts +44 -500
  55. package/src/runtime/body_loader.ts +11 -0
  56. package/src/runtime/command_registry.ts +22 -44
  57. package/src/runtime/execute.ts +157 -165
  58. package/src/runtime/http.ts +1 -1
  59. package/src/runtime/upload.ts +3 -3
  60. package/src/runtime/zod_registry.ts +7 -25
  61. package/src/tests/command_registry.test.ts +81 -31
  62. package/src/tests/execute_validation.test.ts +236 -603
  63. package/src/tests/help.test.ts +47 -66
  64. package/src/tests/upload.test.ts +4 -4
  65. package/src/tests/zod_registry.test.ts +0 -13
  66. package/sdk-dist/docs/runtime-reference/app-discovery.md +0 -68
@@ -11,89 +11,70 @@ const env = {
11
11
  ARCUBASE_TOKEN_EXPIRES_AT: '',
12
12
  }
13
13
 
14
- test('root help prints modules', async () => {
14
+ test('admin root help exposes reset surface nouns only', async () => {
15
15
  const out = await executeCLI('admin', ['--help'], env as any, async () => new Response('{}'))
16
16
  assert.equal(out.kind, 'help')
17
- assert.match(out.text, /app/)
17
+ assert.match(out.text, /\bapp\b/)
18
+ assert.match(out.text, /\btable\b/)
19
+ assert.match(out.text, /\baccess-rule\b/)
20
+ assert.match(out.text, /\bworkflow\b/)
21
+ assert.doesNotMatch(out.text, /\bentity\b/)
22
+ assert.doesNotMatch(out.text, /\bingress\b/)
18
23
  })
19
24
 
20
- test('root help does not require runtime env', async () => {
21
- const out = await executeCLI('admin', ['--help'], undefined, async () => new Response('{}'))
25
+ test('user root help exposes reset surface nouns only', async () => {
26
+ const out = await executeCLI('user', ['--help'], env as any, async () => new Response('{}'))
22
27
  assert.equal(out.kind, 'help')
23
- assert.match(out.text, /modules:/)
28
+ assert.match(out.text, /\bentry\b/)
29
+ assert.match(out.text, /\btable\b/)
30
+ assert.match(out.text, /\brow\b/)
31
+ assert.match(out.text, /\bupload\b/)
32
+ assert.match(out.text, /\bprofile\b/)
33
+ assert.match(out.text, /\bworkflow\b/)
34
+ assert.doesNotMatch(out.text, /\bglobal-action\b/)
35
+ assert.doesNotMatch(out.text, /\bentity\b/)
24
36
  })
25
37
 
26
- test('module help prints create-entity command', async () => {
38
+ test('admin module help lists reset app commands', async () => {
27
39
  const out = await executeCLI('admin', ['app', '--help'], env as any, async () => new Response('{}'))
28
40
  assert.equal(out.kind, 'help')
29
- assert.match(out.text, /create-entity/)
30
- assert.match(out.text, /inventory/)
41
+ assert.match(out.text, /list/)
42
+ assert.match(out.text, /get/)
43
+ assert.match(out.text, /create/)
44
+ assert.match(out.text, /update/)
45
+ assert.match(out.text, /delete/)
46
+ assert.doesNotMatch(out.text, /list-apps/)
47
+ assert.doesNotMatch(out.text, /create-entity/)
31
48
  })
32
49
 
33
- test('module help does not require runtime env', async () => {
34
- const out = await executeCLI('user', ['rows', '--help'], undefined, async () => new Response('{}'))
35
- assert.equal(out.kind, 'help')
36
- assert.match(out.text, /delete-entity-row/)
37
- })
38
-
39
- test('command help prints normalized external endpoint', async () => {
40
- const out = await executeCLI('admin', ['app-entity-share', 'get-app-entity-shares', '--help'], env as any, async () => new Response('{}'))
41
- assert.equal(out.kind, 'help')
42
- assert.match(out.text, /endpoint: \/apps\/:app_id\/entity-shares/)
43
- assert.doesNotMatch(out.text, /endpoint: \/api\//)
44
- })
45
-
46
- test('command help does not require runtime env', async () => {
47
- const out = await executeCLI('user', ['rows', 'delete-entity-row', '--help'], undefined, async () => new Response('{}'))
48
- assert.equal(out.kind, 'help')
49
- assert.match(out.text, /endpoint: \/entity\/:app_id\/:entity_id\/delete-item/)
50
- })
51
-
52
- test('command help prints runtime doc hints for request body commands', async () => {
53
- const out = await executeCLI('user', ['rows', 'update-entity-row', '--help'], undefined, async () => new Response('{}'))
54
- assert.equal(out.kind, 'help')
55
- assert.match(out.text, /docs:/)
56
- assert.match(out.text, /\/opt\/arcubase-sdk\/docs\/runtime-reference\/row-crud\.md/)
57
- assert.match(out.text, /\/opt\/arcubase-sdk\/docs\/runtime-reference\/examples\/README\.md/)
58
- })
59
-
60
- test('command help prints query-file support', async () => {
61
- const out = await executeCLI('user', ['rows', 'query-entity', '--help'], undefined, async () => new Response('{}'))
50
+ test('user row help replaces workflow row commands', async () => {
51
+ const out = await executeCLI('user', ['row', 'query', '--help'], undefined, async () => new Response('{}'))
62
52
  assert.equal(out.kind, 'help')
53
+ assert.match(out.text, /body: .*--body-file or --body-json/)
63
54
  assert.match(out.text, /query flags: --query-file/)
55
+ assert.doesNotMatch(out.text, /workflow query-entity/)
56
+ assert.doesNotMatch(out.text, /--entity-id/)
64
57
  })
65
58
 
66
- test('command help without request body can still point to lifecycle and examples docs', async () => {
67
- const out = await executeCLI('admin', ['entity', 'admin-get-entity-info', '--help'], undefined, async () => new Response('{}'))
68
- assert.equal(out.kind, 'help')
69
- assert.match(out.text, /\/opt\/arcubase-sdk\/docs\/runtime-reference\/table-lifecycle\.md/)
70
- assert.match(out.text, /\/opt\/arcubase-sdk\/docs\/runtime-reference\/examples\/README\.md/)
71
- })
72
-
73
- test('app inventory help explains app discovery purpose', async () => {
74
- const out = await executeCLI('admin', ['app', 'inventory', '--help'], undefined, async () => new Response('{}'))
59
+ test('admin table update-schema help uses table nouns and body-json', async () => {
60
+ const out = await executeCLI('admin', ['table', 'update-schema', '--help'], undefined, async () => new Response('{}'))
75
61
  assert.equal(out.kind, 'help')
76
- assert.match(out.text, /list all accessible apps and each app entity list/)
77
- assert.match(out.text, /use this before asking the user for app_id/)
62
+ assert.match(out.text, /body: .*--body-file or --body-json/)
63
+ assert.match(out.text, /path flags: --app-id, --table-id/)
64
+ assert.doesNotMatch(out.text, /--entity-id/)
65
+ assert.doesNotMatch(out.text, /admin-save-entity/)
78
66
  })
79
67
 
80
- test('admin-save-entity help prints row-operation next step', async () => {
81
- const out = await executeCLI('admin', ['entity', 'admin-save-entity', '--help'], undefined, async () => new Response('{}'))
82
- assert.equal(out.kind, 'help')
83
- assert.match(out.text, /switch to arcubase for row operations/)
84
- assert.match(out.text, /arcubase rows insert-entity/)
85
- assert.match(out.text, /arcubase rows query-entity/)
86
- })
68
+ test('admin access-rule help gives update whitelist and assign-users body-json examples', async () => {
69
+ const update = await executeCLI('admin', ['access-rule', 'update', '--help'], undefined, async () => new Response('{}'))
70
+ assert.equal(update.kind, 'help')
71
+ assert.match(update.text, /--app-id/)
72
+ assert.match(update.text, /--table-id/)
73
+ assert.match(update.text, /--rule-id/)
74
+ assert.match(update.text, /"update":\["enabled"\]/)
87
75
 
88
- test('wrong admin workflow command points to arcubase row command', async () => {
89
- await assert.rejects(
90
- () => executeCLI('admin', ['workflow', 'insert-entity'], env as any, async () => new Response('{}')),
91
- (error: any) => {
92
- assert.equal(error.code, 'UNKNOWN_COMMAND')
93
- assert.equal(error.details?.reason, 'workflow insert-entity is not a valid command group; use arcubase rows for row operations')
94
- assert.equal(error.details?.hint, 'use: arcubase rows insert-entity')
95
- assert.ok((error.details?.suggestions ?? []).includes('arcubase rows insert-entity'))
96
- return true
97
- }
98
- )
76
+ const assign = await executeCLI('admin', ['access-rule', 'assign-users', '--help'], undefined, async () => new Response('{}'))
77
+ assert.equal(assign.kind, 'help')
78
+ assert.match(assign.text, /"update":\["user_scope"\]/)
79
+ assert.match(assign.text, /"options":\{"user_scope":\[/)
99
80
  })
@@ -35,7 +35,7 @@ test('upload returns file field value array for row payloads', async () => {
35
35
  async (input, init) => {
36
36
  const url = String(input)
37
37
  calls.push({ url, method: init?.method })
38
- if (url === 'https://arcubase.example.com/upload/token') {
38
+ if (url === 'https://arcubase.example.com/api/upload/token') {
39
39
  return new Response(
40
40
  JSON.stringify({
41
41
  data: {
@@ -62,7 +62,7 @@ test('upload returns file field value array for row payloads', async () => {
62
62
 
63
63
  assert.equal(result.kind, 'result')
64
64
  assert.deepEqual(calls, [
65
- { url: 'https://arcubase.example.com/upload/token', method: 'POST' },
65
+ { url: 'https://arcubase.example.com/api/upload/token', method: 'POST' },
66
66
  { url: 'https://uploads.example.com', method: 'POST' },
67
67
  ])
68
68
  assert.deepEqual(result.data, [
@@ -89,7 +89,7 @@ test('upload supports s3-post-policy tokens', async () => {
89
89
  async (input, init) => {
90
90
  const url = String(input)
91
91
  calls.push({ url, method: init?.method })
92
- if (url === 'https://arcubase.example.com/upload/token') {
92
+ if (url === 'https://arcubase.example.com/api/upload/token') {
93
93
  return new Response(
94
94
  JSON.stringify({
95
95
  data: {
@@ -118,7 +118,7 @@ test('upload supports s3-post-policy tokens', async () => {
118
118
 
119
119
  assert.equal(result.kind, 'result')
120
120
  assert.deepEqual(calls, [
121
- { url: 'https://arcubase.example.com/upload/token', method: 'POST' },
121
+ { url: 'https://arcubase.example.com/api/upload/token', method: 'POST' },
122
122
  { url: 'https://uploads.example.com/private-bucket', method: 'POST' },
123
123
  ])
124
124
  assert.deepEqual(result.data, [
@@ -14,19 +14,6 @@ test('EntityQueryReqVO schema exists', () => {
14
14
  assert.ok(getBodySchema('EntityQueryReqVO'))
15
15
  })
16
16
 
17
- test('inline request type schema exists', () => {
18
- assert.ok(getBodySchema('{ name: string }'))
19
- })
20
-
21
- test('intersection request type schema exists', () => {
22
- assert.ok(getBodySchema('EntityImportReqVO & EntityImportActionVO'))
23
- })
24
-
25
- test('manual notification override schema exists', () => {
26
- assert.ok(getBodySchema('EntityUpdateNotificationsReqVO'))
27
- assert.equal(getUnsupportedBodySchemaReason('EntityUpdateNotificationsReqVO'), null)
28
- })
29
-
30
17
  test('unknown request type has no schema and no unsupported reason', () => {
31
18
  assert.equal(getBodySchema('DefinitelyMissingReqVO'), null)
32
19
  assert.equal(getUnsupportedBodySchemaReason('DefinitelyMissingReqVO'), null)
@@ -1,68 +0,0 @@
1
- # App Discovery
2
-
3
- Arcubase is a headless app platform.
4
-
5
- Core concepts:
6
-
7
- - app: the top-level business container
8
- - entity: a table inside an app
9
- - row: a record inside an entity
10
-
11
- Hard rule:
12
-
13
- - every operation happens inside one app
14
- - find the target app before schema work or row work
15
-
16
- Do not ask the user for `app_id` unless:
17
-
18
- - there is no matching app
19
- - there are multiple matching apps and you cannot resolve the ambiguity
20
-
21
- Do not ask the user for `entity_id` when creating a new table.
22
- Entity ids are assigned by Arcubase.
23
-
24
- ## First command
25
-
26
- Use the inventory command first:
27
-
28
- ```bash
29
- arcubase-admin app inventory
30
- ```
31
-
32
- It returns:
33
-
34
- - every accessible app
35
- - each app id and app name
36
- - each app entity list
37
-
38
- Use it to resolve:
39
-
40
- - which existing app matches the user's business name
41
- - whether the table already exists
42
- - whether the user is talking about the wrong app
43
-
44
- ## Resolution order
45
-
46
- 1. if the user gives an app name, run `arcubase-admin app inventory`
47
- 2. match the app by name yourself
48
- 3. if the match is unique, continue without asking for `app_id`
49
- 4. if there is no match, ask which app to use
50
- 5. if there are multiple matches, ask the user to choose by app name
51
-
52
- ## Existing app flow
53
-
54
- If the app already exists:
55
-
56
- 1. run `arcubase-admin app inventory`
57
- 2. find the app id
58
- 3. inspect the existing entity list
59
- 4. decide whether to create a new entity or write rows into an existing entity
60
-
61
- ## New app flow
62
-
63
- If the user clearly wants a brand-new app:
64
-
65
- 1. create the app with `arcubase-admin app create-app-by-tenants`
66
- 2. create the entity shell
67
- 3. save the schema
68
- 4. switch to `arcubase rows ...` for row operations