primitive-admin 1.1.0-alpha.2 → 1.1.0-alpha.21
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 +124 -4
- package/dist/bin/primitive.js +10 -0
- package/dist/bin/primitive.js.map +1 -1
- package/dist/src/commands/database-types.js +453 -0
- package/dist/src/commands/database-types.js.map +1 -0
- package/dist/src/commands/databases.js +636 -0
- package/dist/src/commands/databases.js.map +1 -0
- package/dist/src/commands/documents.js +105 -2
- package/dist/src/commands/documents.js.map +1 -1
- package/dist/src/commands/group-type-configs.js +189 -0
- package/dist/src/commands/group-type-configs.js.map +1 -0
- package/dist/src/commands/groups.js +366 -0
- package/dist/src/commands/groups.js.map +1 -0
- package/dist/src/commands/rule-sets.js +366 -0
- package/dist/src/commands/rule-sets.js.map +1 -0
- package/dist/src/commands/sync.js +959 -73
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/commands/tokens.js +17 -3
- package/dist/src/commands/tokens.js.map +1 -1
- package/dist/src/commands/users.js +58 -0
- package/dist/src/commands/users.js.map +1 -1
- package/dist/src/commands/workflows.js +21 -3
- package/dist/src/commands/workflows.js.map +1 -1
- package/dist/src/lib/api-client.js +240 -1
- package/dist/src/lib/api-client.js.map +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -150,12 +150,13 @@ Manage users within an app.
|
|
|
150
150
|
|
|
151
151
|
```bash
|
|
152
152
|
primitive users list [app-id] # List users
|
|
153
|
+
primitive users create <email> [--role admin|member] # Create/add user by email
|
|
153
154
|
primitive users invite [app-id] <email> [--role admin] # Invite user
|
|
154
155
|
primitive users remove [app-id] <user-id> # Remove user
|
|
155
156
|
primitive users set-role [app-id] <user-id> <role> # Change role
|
|
156
157
|
primitive users transfer-owner [app-id] <new-owner-id> # Transfer ownership
|
|
157
|
-
primitive users
|
|
158
|
-
primitive users invitations
|
|
158
|
+
primitive users mint-jwt <user-id> [--role <role>] # Mint test JWT (dev/test only)
|
|
159
|
+
primitive users invitations [app-id] # List pending invitations
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
### Waitlist
|
|
@@ -248,6 +249,120 @@ primitive workflows runs list <workflow-id>
|
|
|
248
249
|
primitive workflows runs status <workflow-id> <run-id>
|
|
249
250
|
```
|
|
250
251
|
|
|
252
|
+
### Tokens
|
|
253
|
+
|
|
254
|
+
Manage long-lived API access tokens for headless/server authentication.
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
primitive tokens create <app-id> --name "My Token" --user <user-id> # Create token
|
|
258
|
+
primitive tokens create <app-id> --name "CI/CD" --ttl 90d --user <uid> # With expiry
|
|
259
|
+
primitive tokens list [app-id] # List tokens
|
|
260
|
+
primitive tokens show <token-id> [app-id] # Show details
|
|
261
|
+
primitive tokens revoke <token-id> [app-id] # Revoke token
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Create options:**
|
|
265
|
+
- `--name <name>` - Token name (required)
|
|
266
|
+
- `--user <user-id>` - App user ID to associate the token with (required)
|
|
267
|
+
- `--ttl <duration>` - Token lifetime (e.g., 7d, 30d, 4w, 3m, 1y). Omit for never-expiring
|
|
268
|
+
|
|
269
|
+
### Databases
|
|
270
|
+
|
|
271
|
+
Manage online databases and permissions. `list` returns databases the user has direct access to; group-shared databases are listed via `primitive groups databases`.
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
primitive databases list [app-id] # List databases (direct access)
|
|
275
|
+
primitive databases create <title> [app-id] # Create database
|
|
276
|
+
primitive databases get <database-id> [app-id] # Get details
|
|
277
|
+
primitive databases update <database-id> [options] # Update title or type
|
|
278
|
+
primitive databases delete <database-id> [app-id] # Delete database
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Permissions:**
|
|
282
|
+
```bash
|
|
283
|
+
primitive databases permissions list <database-id> [app-id]
|
|
284
|
+
primitive databases permissions grant <database-id> --user-id <uid> --permission <perm> [app-id]
|
|
285
|
+
primitive databases permissions revoke <database-id> <user-id> [app-id]
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Permission values: `owner` (set at creation), `manager`
|
|
289
|
+
|
|
290
|
+
**Metadata:**
|
|
291
|
+
```bash
|
|
292
|
+
primitive databases metadata update <database-id> --data '{"key":"value"}' # Merge-update metadata
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Operations:**
|
|
296
|
+
```bash
|
|
297
|
+
primitive databases operations list <database-id> [app-id] # List registered operations
|
|
298
|
+
primitive databases operations execute <database-id> <op-name> --params '{}' # Execute operation
|
|
299
|
+
primitive databases operations execute <database-id> <op-name> --token <jwt> # Execute as specific user
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The `--token` flag lets you execute an operation as a specific user using a test JWT from `users mint-jwt`. Useful for testing access rules.
|
|
303
|
+
|
|
304
|
+
**Records (schema introspection):**
|
|
305
|
+
```bash
|
|
306
|
+
primitive databases records models <database-id> [app-id] # List model names
|
|
307
|
+
primitive databases records describe <database-id> <model> [app-id] # Show inferred schema
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Indexes:**
|
|
311
|
+
```bash
|
|
312
|
+
primitive databases indexes list <database-id> [--model <name>] # List indexes
|
|
313
|
+
primitive databases indexes create <database-id> <model> <field> [options] # Create index
|
|
314
|
+
primitive databases indexes drop <database-id> <model> <field> # Drop index
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Documents
|
|
318
|
+
|
|
319
|
+
Manage document ownership and group permissions.
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
primitive documents transfer-owner [app-id] <document-id> <new-owner-id> # Transfer ownership
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Group permissions on documents:**
|
|
326
|
+
```bash
|
|
327
|
+
primitive documents group-permissions list <document-id>
|
|
328
|
+
primitive documents group-permissions grant <document-id> --group-type <type> --group-id <id> --permission <perm>
|
|
329
|
+
primitive documents group-permissions revoke <document-id> <group-type> <group-id>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Permission values: `read-write`, `reader`
|
|
333
|
+
|
|
334
|
+
### Groups
|
|
335
|
+
|
|
336
|
+
Manage groups, members, and memberships.
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
primitive groups list [app-id] # List groups
|
|
340
|
+
primitive groups create [app-id] --type <type> --id <id> --name <name> # Create group
|
|
341
|
+
primitive groups get <group-type> <group-id> [app-id] # Get details
|
|
342
|
+
primitive groups update <group-type> <group-id> [app-id] # Update group
|
|
343
|
+
primitive groups delete <group-type> <group-id> [app-id] # Delete group
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Members:**
|
|
347
|
+
```bash
|
|
348
|
+
primitive groups members list <group-type> <group-id> [app-id]
|
|
349
|
+
primitive groups members add <group-type> <group-id> <user-id> [app-id]
|
|
350
|
+
primitive groups members remove <group-type> <group-id> <user-id> [app-id]
|
|
351
|
+
primitive groups members set-role <group-type> <group-id> <user-id> <role> [app-id]
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Memberships:**
|
|
355
|
+
```bash
|
|
356
|
+
primitive groups memberships <user-id> [app-id] # List user's group memberships
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
**Group resource access:**
|
|
360
|
+
```bash
|
|
361
|
+
primitive groups documents <group-type> <group-id> # List documents a group can access
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Group permissions on documents are managed via `primitive documents group-permissions` (see [Documents](#documents) above).
|
|
365
|
+
|
|
251
366
|
### Analytics
|
|
252
367
|
|
|
253
368
|
View usage analytics for an app.
|
|
@@ -476,8 +591,13 @@ cli/tests/
|
|
|
476
591
|
config.test.ts # Credentials and config management
|
|
477
592
|
output.test.ts # Output formatting functions
|
|
478
593
|
integration/
|
|
479
|
-
api-client.test.ts
|
|
480
|
-
commands.test.ts
|
|
594
|
+
api-client.test.ts # API client HTTP tests
|
|
595
|
+
commands.test.ts # CLI command tests
|
|
596
|
+
tokens.test.ts # Token lifecycle tests
|
|
597
|
+
databases.test.ts # Database CRUD, permissions, group permissions tests
|
|
598
|
+
documents.test.ts # Document group permissions, group resource listing tests
|
|
599
|
+
groups.test.ts # Group CRUD, members, memberships tests
|
|
600
|
+
classroom-e2e.test.ts # End-to-end classroom app workflow (types, rules, operations, access)
|
|
481
601
|
```
|
|
482
602
|
|
|
483
603
|
## Troubleshooting
|
package/dist/bin/primitive.js
CHANGED
|
@@ -18,6 +18,11 @@ import { registerSyncCommands } from "../src/commands/sync.js";
|
|
|
18
18
|
import { registerLlmCommands } from "../src/commands/llm.js";
|
|
19
19
|
import { registerComparisonsCommands } from "../src/commands/comparisons.js";
|
|
20
20
|
import { registerTokensCommands } from "../src/commands/tokens.js";
|
|
21
|
+
import { registerDatabasesCommands } from "../src/commands/databases.js";
|
|
22
|
+
import { registerGroupsCommands } from "../src/commands/groups.js";
|
|
23
|
+
import { registerRuleSetsCommands } from "../src/commands/rule-sets.js";
|
|
24
|
+
import { registerGroupTypeConfigsCommands } from "../src/commands/group-type-configs.js";
|
|
25
|
+
import { registerDatabaseTypesCommands } from "../src/commands/database-types.js";
|
|
21
26
|
import { registerGuidesCommands } from "../src/commands/guides.js";
|
|
22
27
|
import { registerDocumentsCommands } from "../src/commands/documents.js";
|
|
23
28
|
import { error } from "../src/lib/output.js";
|
|
@@ -67,6 +72,11 @@ registerSyncCommands(program);
|
|
|
67
72
|
registerLlmCommands(program);
|
|
68
73
|
registerComparisonsCommands(program);
|
|
69
74
|
registerTokensCommands(program);
|
|
75
|
+
registerDatabasesCommands(program);
|
|
76
|
+
registerGroupsCommands(program);
|
|
77
|
+
registerRuleSetsCommands(program);
|
|
78
|
+
registerGroupTypeConfigsCommands(program);
|
|
79
|
+
registerDatabaseTypesCommands(program);
|
|
70
80
|
registerGuidesCommands(program);
|
|
71
81
|
registerDocumentsCommands(program);
|
|
72
82
|
// Global error handler
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitive.js","sourceRoot":"","sources":["../../bin/primitive.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"primitive.js","sourceRoot":"","sources":["../../bin/primitive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { ApiClient } from "../lib/api-client.js";
|
|
2
|
+
import { getCurrentAppId } from "../lib/config.js";
|
|
3
|
+
import { success, error, info, keyValue, formatTable, formatId, formatDate, json, } from "../lib/output.js";
|
|
4
|
+
function resolveAppId(appId, options) {
|
|
5
|
+
const resolved = appId || options.app || getCurrentAppId();
|
|
6
|
+
if (!resolved) {
|
|
7
|
+
error("No app specified. Use <app-id>, --app, or 'primitive use <app-id>' to set context.");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
return resolved;
|
|
11
|
+
}
|
|
12
|
+
export function registerDatabaseTypesCommands(program) {
|
|
13
|
+
const dbTypes = program
|
|
14
|
+
.command("database-types")
|
|
15
|
+
.description("Manage database type configurations and operations")
|
|
16
|
+
.addHelpText("after", `
|
|
17
|
+
Examples:
|
|
18
|
+
$ primitive database-types list
|
|
19
|
+
$ primitive database-types get <database-type>
|
|
20
|
+
$ primitive database-types create <database-type>
|
|
21
|
+
$ primitive database-types update <database-type> --rule-set-id <id>
|
|
22
|
+
$ primitive database-types delete <database-type>
|
|
23
|
+
$ primitive database-types operations list <database-type>
|
|
24
|
+
$ primitive database-types operations create <database-type> <name> --type query --model Task --access true --definition '{"filter":{}}'
|
|
25
|
+
`);
|
|
26
|
+
// List type configs
|
|
27
|
+
dbTypes
|
|
28
|
+
.command("list")
|
|
29
|
+
.description("List database type configurations")
|
|
30
|
+
.argument("[app-id]", "App ID (uses current app if not specified)")
|
|
31
|
+
.option("--app <app-id>", "App ID")
|
|
32
|
+
.option("--json", "Output as JSON")
|
|
33
|
+
.action(async (appId, options) => {
|
|
34
|
+
const resolvedAppId = resolveAppId(appId, options);
|
|
35
|
+
const client = new ApiClient();
|
|
36
|
+
try {
|
|
37
|
+
const result = await client.listDatabaseTypeConfigs(resolvedAppId);
|
|
38
|
+
const list = Array.isArray(result) ? result : [];
|
|
39
|
+
if (options.json) {
|
|
40
|
+
json(list);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (list.length === 0) {
|
|
44
|
+
info("No database type configurations found.");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
console.log(formatTable(list, [
|
|
48
|
+
{ header: "TYPE", key: "databaseType" },
|
|
49
|
+
{ header: "RULE SET ID", key: "ruleSetId", format: (v) => v ? formatId(v) : "—" },
|
|
50
|
+
{ header: "TRIGGERS", key: "triggers", format: (v) => v ? "Yes" : "—" },
|
|
51
|
+
{ header: "MODIFIED", key: "modifiedAt", format: formatDate },
|
|
52
|
+
]));
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
error(err.message);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// Get type config
|
|
60
|
+
dbTypes
|
|
61
|
+
.command("get")
|
|
62
|
+
.description("Get database type configuration details")
|
|
63
|
+
.argument("<database-type>", "Database type name")
|
|
64
|
+
.option("--app <app-id>", "App ID")
|
|
65
|
+
.option("--json", "Output as JSON")
|
|
66
|
+
.action(async (databaseType, options) => {
|
|
67
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
68
|
+
const client = new ApiClient();
|
|
69
|
+
try {
|
|
70
|
+
const result = await client.getDatabaseTypeConfig(resolvedAppId, databaseType);
|
|
71
|
+
if (options.json) {
|
|
72
|
+
json(result);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
keyValue("Database Type", result.databaseType);
|
|
76
|
+
keyValue("Rule Set ID", result.ruleSetId || "—");
|
|
77
|
+
keyValue("Triggers", result.triggers ? "Yes" : "—");
|
|
78
|
+
keyValue("Metadata Access", result.metadataAccess || "—");
|
|
79
|
+
keyValue("Created", formatDate(result.createdAt));
|
|
80
|
+
keyValue("Modified", formatDate(result.modifiedAt));
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
error(err.message);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// Create type config
|
|
88
|
+
dbTypes
|
|
89
|
+
.command("create")
|
|
90
|
+
.description("Create a database type configuration")
|
|
91
|
+
.argument("<database-type>", "Database type name")
|
|
92
|
+
.option("--rule-set-id <id>", "Access rule set ID")
|
|
93
|
+
.option("--triggers <json>", "Trigger definitions as JSON string")
|
|
94
|
+
.option("--metadata-access <cel>", "Metadata access CEL expression")
|
|
95
|
+
.option("--app <app-id>", "App ID")
|
|
96
|
+
.option("--json", "Output as JSON")
|
|
97
|
+
.action(async (databaseType, options) => {
|
|
98
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
99
|
+
const client = new ApiClient();
|
|
100
|
+
try {
|
|
101
|
+
const data = { databaseType };
|
|
102
|
+
if (options.ruleSetId)
|
|
103
|
+
data.ruleSetId = options.ruleSetId;
|
|
104
|
+
if (options.triggers) {
|
|
105
|
+
try {
|
|
106
|
+
data.triggers = JSON.parse(options.triggers);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
error("Invalid JSON in --triggers.");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (options.metadataAccess)
|
|
114
|
+
data.metadataAccess = options.metadataAccess;
|
|
115
|
+
const result = await client.createDatabaseTypeConfig(resolvedAppId, data);
|
|
116
|
+
if (options.json) {
|
|
117
|
+
json(result);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
success("Database type configuration created.");
|
|
121
|
+
keyValue("Database Type", result.databaseType);
|
|
122
|
+
if (result.ruleSetId)
|
|
123
|
+
keyValue("Rule Set ID", result.ruleSetId);
|
|
124
|
+
if (result.triggers)
|
|
125
|
+
keyValue("Triggers", "Yes");
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
error(err.message);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// Update type config
|
|
133
|
+
dbTypes
|
|
134
|
+
.command("update")
|
|
135
|
+
.description("Update a database type configuration")
|
|
136
|
+
.argument("<database-type>", "Database type name")
|
|
137
|
+
.option("--rule-set-id <id>", "Access rule set ID (use 'none' to clear)")
|
|
138
|
+
.option("--triggers <json>", "Trigger definitions as JSON string (use 'none' to clear)")
|
|
139
|
+
.option("--metadata-access <cel>", "Metadata access CEL expression (use 'none' to clear)")
|
|
140
|
+
.option("--app <app-id>", "App ID")
|
|
141
|
+
.option("--json", "Output as JSON")
|
|
142
|
+
.action(async (databaseType, options) => {
|
|
143
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
144
|
+
const client = new ApiClient();
|
|
145
|
+
const data = {};
|
|
146
|
+
if (options.ruleSetId !== undefined) {
|
|
147
|
+
data.ruleSetId = options.ruleSetId === "none" ? null : options.ruleSetId;
|
|
148
|
+
}
|
|
149
|
+
if (options.triggers !== undefined) {
|
|
150
|
+
if (options.triggers === "none") {
|
|
151
|
+
data.triggers = null;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
try {
|
|
155
|
+
data.triggers = JSON.parse(options.triggers);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
error("Invalid JSON in --triggers.");
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (options.metadataAccess !== undefined) {
|
|
164
|
+
data.metadataAccess = options.metadataAccess === "none" ? null : options.metadataAccess;
|
|
165
|
+
}
|
|
166
|
+
if (Object.keys(data).length === 0) {
|
|
167
|
+
error("Provide at least one of --rule-set-id, --triggers, or --metadata-access.");
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const result = await client.updateDatabaseTypeConfig(resolvedAppId, databaseType, data);
|
|
172
|
+
if (options.json) {
|
|
173
|
+
json(result);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
success("Database type configuration updated.");
|
|
177
|
+
keyValue("Database Type", result.databaseType);
|
|
178
|
+
keyValue("Rule Set ID", result.ruleSetId || "—");
|
|
179
|
+
keyValue("Triggers", result.triggers ? "Yes" : "—");
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
error(err.message);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
// Delete type config
|
|
187
|
+
dbTypes
|
|
188
|
+
.command("delete")
|
|
189
|
+
.description("Delete a database type configuration")
|
|
190
|
+
.argument("<database-type>", "Database type name")
|
|
191
|
+
.option("--app <app-id>", "App ID")
|
|
192
|
+
.option("-y, --yes", "Skip confirmation prompt")
|
|
193
|
+
.action(async (databaseType, options) => {
|
|
194
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
195
|
+
if (!options.yes) {
|
|
196
|
+
const inquirer = await import("inquirer");
|
|
197
|
+
const { confirm } = await inquirer.default.prompt([
|
|
198
|
+
{
|
|
199
|
+
type: "confirm",
|
|
200
|
+
name: "confirm",
|
|
201
|
+
message: `Delete database type "${databaseType}"? This cannot be undone.`,
|
|
202
|
+
default: false,
|
|
203
|
+
},
|
|
204
|
+
]);
|
|
205
|
+
if (!confirm) {
|
|
206
|
+
info("Cancelled.");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const client = new ApiClient();
|
|
211
|
+
try {
|
|
212
|
+
await client.deleteDatabaseTypeConfig(resolvedAppId, databaseType);
|
|
213
|
+
success(`Database type "${databaseType}" deleted.`);
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
error(err.message);
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
// ---- Operations subcommand group ----
|
|
221
|
+
const operations = dbTypes
|
|
222
|
+
.command("operations")
|
|
223
|
+
.description("Manage operations (queries and mutations) for a database type");
|
|
224
|
+
// List operations
|
|
225
|
+
operations
|
|
226
|
+
.command("list")
|
|
227
|
+
.description("List operations for a database type")
|
|
228
|
+
.argument("<database-type>", "Database type name")
|
|
229
|
+
.option("--app <app-id>", "App ID")
|
|
230
|
+
.option("--json", "Output as JSON")
|
|
231
|
+
.action(async (databaseType, options) => {
|
|
232
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
233
|
+
const client = new ApiClient();
|
|
234
|
+
try {
|
|
235
|
+
const result = await client.listDatabaseTypeOperations(resolvedAppId, databaseType);
|
|
236
|
+
const list = Array.isArray(result) ? result : [];
|
|
237
|
+
if (options.json) {
|
|
238
|
+
json(list);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (list.length === 0) {
|
|
242
|
+
info("No operations found.");
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
console.log(formatTable(list, [
|
|
246
|
+
{ header: "NAME", key: "name" },
|
|
247
|
+
{ header: "TYPE", key: "type" },
|
|
248
|
+
{ header: "MODEL", key: "modelName" },
|
|
249
|
+
{ header: "ACCESS", key: "access", format: (v) => {
|
|
250
|
+
const s = String(v || "");
|
|
251
|
+
return s.length > 40 ? s.slice(0, 37) + "..." : s;
|
|
252
|
+
} },
|
|
253
|
+
{ header: "MODIFIED", key: "modifiedAt", format: formatDate },
|
|
254
|
+
]));
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
error(err.message);
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
// Get operation
|
|
262
|
+
operations
|
|
263
|
+
.command("get")
|
|
264
|
+
.description("Get operation details")
|
|
265
|
+
.argument("<database-type>", "Database type name")
|
|
266
|
+
.argument("<name>", "Operation name")
|
|
267
|
+
.option("--app <app-id>", "App ID")
|
|
268
|
+
.option("--json", "Output as JSON")
|
|
269
|
+
.action(async (databaseType, name, options) => {
|
|
270
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
271
|
+
const client = new ApiClient();
|
|
272
|
+
try {
|
|
273
|
+
const result = await client.getDatabaseTypeOperation(resolvedAppId, databaseType, name);
|
|
274
|
+
if (options.json) {
|
|
275
|
+
json(result);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
keyValue("Name", result.name);
|
|
279
|
+
keyValue("Type", result.type);
|
|
280
|
+
keyValue("Model Name", result.modelName);
|
|
281
|
+
keyValue("Access", result.access);
|
|
282
|
+
keyValue("Created", formatDate(result.createdAt));
|
|
283
|
+
keyValue("Modified", formatDate(result.modifiedAt));
|
|
284
|
+
console.log("\nDefinition:");
|
|
285
|
+
console.log(JSON.stringify(result.definition, null, 2));
|
|
286
|
+
if (result.params && Object.keys(result.params).length > 0) {
|
|
287
|
+
console.log("\nParameters:");
|
|
288
|
+
console.log(JSON.stringify(result.params, null, 2));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
error(err.message);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
// Create operation
|
|
297
|
+
operations
|
|
298
|
+
.command("create")
|
|
299
|
+
.description("Create a new operation (query or mutation)")
|
|
300
|
+
.argument("<database-type>", "Database type name")
|
|
301
|
+
.argument("<name>", "Operation name")
|
|
302
|
+
.requiredOption("--type <type>", "Operation type: query, mutation, count, aggregate, or pipeline")
|
|
303
|
+
.requiredOption("--model <model-name>", "Model name")
|
|
304
|
+
.requiredOption("--access <cel>", "Access CEL expression")
|
|
305
|
+
.requiredOption("--definition <json>", "Definition as JSON string")
|
|
306
|
+
.option("--params <json>", "Parameters schema as JSON string")
|
|
307
|
+
.option("--app <app-id>", "App ID")
|
|
308
|
+
.option("--json", "Output as JSON")
|
|
309
|
+
.action(async (databaseType, name, options) => {
|
|
310
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
311
|
+
const client = new ApiClient();
|
|
312
|
+
let definition;
|
|
313
|
+
try {
|
|
314
|
+
definition = JSON.parse(options.definition);
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
error("Invalid JSON in --definition.");
|
|
318
|
+
process.exit(1);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
let params;
|
|
322
|
+
if (options.params) {
|
|
323
|
+
try {
|
|
324
|
+
params = JSON.parse(options.params);
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
error("Invalid JSON in --params.");
|
|
328
|
+
process.exit(1);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
const data = {
|
|
334
|
+
name,
|
|
335
|
+
type: options.type,
|
|
336
|
+
modelName: options.model,
|
|
337
|
+
access: options.access,
|
|
338
|
+
definition,
|
|
339
|
+
};
|
|
340
|
+
if (params)
|
|
341
|
+
data.params = params;
|
|
342
|
+
const result = await client.createDatabaseTypeOperation(resolvedAppId, databaseType, data);
|
|
343
|
+
if (options.json) {
|
|
344
|
+
json(result);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
success("Operation created.");
|
|
348
|
+
keyValue("Name", result.name);
|
|
349
|
+
keyValue("Type", result.type);
|
|
350
|
+
keyValue("Model Name", result.modelName);
|
|
351
|
+
}
|
|
352
|
+
catch (err) {
|
|
353
|
+
error(err.message);
|
|
354
|
+
process.exit(1);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
// Update operation
|
|
358
|
+
operations
|
|
359
|
+
.command("update")
|
|
360
|
+
.description("Update an operation")
|
|
361
|
+
.argument("<database-type>", "Database type name")
|
|
362
|
+
.argument("<name>", "Operation name")
|
|
363
|
+
.option("--model <model-name>", "New model name")
|
|
364
|
+
.option("--access <cel>", "New access CEL expression")
|
|
365
|
+
.option("--definition <json>", "New definition as JSON string")
|
|
366
|
+
.option("--params <json>", "New parameters schema as JSON string")
|
|
367
|
+
.option("--app <app-id>", "App ID")
|
|
368
|
+
.option("--json", "Output as JSON")
|
|
369
|
+
.action(async (databaseType, name, options) => {
|
|
370
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
371
|
+
const client = new ApiClient();
|
|
372
|
+
const data = {};
|
|
373
|
+
if (options.model)
|
|
374
|
+
data.modelName = options.model;
|
|
375
|
+
if (options.access)
|
|
376
|
+
data.access = options.access;
|
|
377
|
+
if (options.definition) {
|
|
378
|
+
try {
|
|
379
|
+
data.definition = JSON.parse(options.definition);
|
|
380
|
+
}
|
|
381
|
+
catch {
|
|
382
|
+
error("Invalid JSON in --definition.");
|
|
383
|
+
process.exit(1);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (options.params) {
|
|
388
|
+
try {
|
|
389
|
+
data.params = JSON.parse(options.params);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
error("Invalid JSON in --params.");
|
|
393
|
+
process.exit(1);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (Object.keys(data).length === 0) {
|
|
398
|
+
error("Provide at least one of --model, --access, --definition, or --params.");
|
|
399
|
+
process.exit(1);
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const result = await client.updateDatabaseTypeOperation(resolvedAppId, databaseType, name, data);
|
|
403
|
+
if (options.json) {
|
|
404
|
+
json(result);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
success("Operation updated.");
|
|
408
|
+
keyValue("Name", result.name);
|
|
409
|
+
keyValue("Type", result.type);
|
|
410
|
+
keyValue("Model Name", result.modelName);
|
|
411
|
+
}
|
|
412
|
+
catch (err) {
|
|
413
|
+
error(err.message);
|
|
414
|
+
process.exit(1);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
// Delete operation
|
|
418
|
+
operations
|
|
419
|
+
.command("delete")
|
|
420
|
+
.description("Delete an operation")
|
|
421
|
+
.argument("<database-type>", "Database type name")
|
|
422
|
+
.argument("<name>", "Operation name")
|
|
423
|
+
.option("--app <app-id>", "App ID")
|
|
424
|
+
.option("-y, --yes", "Skip confirmation prompt")
|
|
425
|
+
.action(async (databaseType, name, options) => {
|
|
426
|
+
const resolvedAppId = resolveAppId(undefined, options);
|
|
427
|
+
if (!options.yes) {
|
|
428
|
+
const inquirer = await import("inquirer");
|
|
429
|
+
const { confirm } = await inquirer.default.prompt([
|
|
430
|
+
{
|
|
431
|
+
type: "confirm",
|
|
432
|
+
name: "confirm",
|
|
433
|
+
message: `Delete operation "${name}" from type "${databaseType}"?`,
|
|
434
|
+
default: false,
|
|
435
|
+
},
|
|
436
|
+
]);
|
|
437
|
+
if (!confirm) {
|
|
438
|
+
info("Cancelled.");
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
const client = new ApiClient();
|
|
443
|
+
try {
|
|
444
|
+
await client.deleteDatabaseTypeOperation(resolvedAppId, databaseType, name);
|
|
445
|
+
success(`Operation "${name}" deleted.`);
|
|
446
|
+
}
|
|
447
|
+
catch (err) {
|
|
448
|
+
error(err.message);
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
//# sourceMappingURL=database-types.js.map
|