primitive-admin 1.0.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.
Files changed (38) hide show
  1. package/README.md +495 -0
  2. package/dist/bin/primitive.js +72 -0
  3. package/dist/bin/primitive.js.map +1 -0
  4. package/dist/src/commands/admins.js +268 -0
  5. package/dist/src/commands/admins.js.map +1 -0
  6. package/dist/src/commands/analytics.js +195 -0
  7. package/dist/src/commands/analytics.js.map +1 -0
  8. package/dist/src/commands/apps.js +238 -0
  9. package/dist/src/commands/apps.js.map +1 -0
  10. package/dist/src/commands/auth.js +178 -0
  11. package/dist/src/commands/auth.js.map +1 -0
  12. package/dist/src/commands/catalog.js +460 -0
  13. package/dist/src/commands/catalog.js.map +1 -0
  14. package/dist/src/commands/integrations.js +438 -0
  15. package/dist/src/commands/integrations.js.map +1 -0
  16. package/dist/src/commands/prompts.js +999 -0
  17. package/dist/src/commands/prompts.js.map +1 -0
  18. package/dist/src/commands/sync.js +598 -0
  19. package/dist/src/commands/sync.js.map +1 -0
  20. package/dist/src/commands/users.js +293 -0
  21. package/dist/src/commands/users.js.map +1 -0
  22. package/dist/src/commands/waitlist.js +176 -0
  23. package/dist/src/commands/waitlist.js.map +1 -0
  24. package/dist/src/commands/workflows.js +876 -0
  25. package/dist/src/commands/workflows.js.map +1 -0
  26. package/dist/src/lib/api-client.js +522 -0
  27. package/dist/src/lib/api-client.js.map +1 -0
  28. package/dist/src/lib/auth-flow.js +306 -0
  29. package/dist/src/lib/auth-flow.js.map +1 -0
  30. package/dist/src/lib/config.js +90 -0
  31. package/dist/src/lib/config.js.map +1 -0
  32. package/dist/src/lib/fetch.js +43 -0
  33. package/dist/src/lib/fetch.js.map +1 -0
  34. package/dist/src/lib/output.js +143 -0
  35. package/dist/src/lib/output.js.map +1 -0
  36. package/dist/src/types/index.js +2 -0
  37. package/dist/src/types/index.js.map +1 -0
  38. package/package.json +47 -0
@@ -0,0 +1,238 @@
1
+ import { ApiClient } from "../lib/api-client.js";
2
+ import { loadCredentials, getCurrentAppId } from "../lib/config.js";
3
+ import { success, error, info, keyValue, formatTable, formatId, json, divider, } from "../lib/output.js";
4
+ export function registerAppsCommands(program) {
5
+ const apps = program
6
+ .command("apps")
7
+ .description("Create, update, and manage applications")
8
+ .addHelpText("after", `
9
+ Examples:
10
+ $ primitive apps list
11
+ $ primitive apps create "My New App"
12
+ $ primitive apps update 01HXY... --mode invite-only --passkey
13
+ `);
14
+ // List apps
15
+ apps
16
+ .command("list")
17
+ .description("List all apps you have access to")
18
+ .option("--json", "Output as JSON")
19
+ .action(async (options) => {
20
+ const client = new ApiClient();
21
+ try {
22
+ const { apps: appsList } = await client.listApps();
23
+ if (options.json) {
24
+ json(appsList);
25
+ return;
26
+ }
27
+ if (!appsList || appsList.length === 0) {
28
+ info("No apps found.");
29
+ return;
30
+ }
31
+ console.log(formatTable(appsList, [
32
+ { header: "ID", key: "id", format: formatId },
33
+ { header: "NAME", key: "name" },
34
+ { header: "ROLE", key: "role" },
35
+ ]));
36
+ }
37
+ catch (err) {
38
+ error(err.message);
39
+ process.exit(1);
40
+ }
41
+ });
42
+ // Create app
43
+ apps
44
+ .command("create")
45
+ .description("Create a new app (super-admin only)")
46
+ .argument("<name>", "App name")
47
+ .option("--admin-email <email>", "Initial admin email (defaults to your email)")
48
+ .option("--json", "Output as JSON")
49
+ .action(async (name, options) => {
50
+ const client = new ApiClient();
51
+ const credentials = loadCredentials();
52
+ try {
53
+ const payload = { name };
54
+ if (options.adminEmail) {
55
+ payload.initialAdminEmail = options.adminEmail;
56
+ }
57
+ else if (credentials?.email) {
58
+ payload.initialAdminEmail = credentials.email;
59
+ }
60
+ const result = await client.createApp(payload);
61
+ if (options.json) {
62
+ json(result);
63
+ return;
64
+ }
65
+ success(`App created: ${result.app?.name || name}`);
66
+ keyValue("App ID", result.app?.appId || result.appId);
67
+ }
68
+ catch (err) {
69
+ error(err.message);
70
+ process.exit(1);
71
+ }
72
+ });
73
+ // Get app details
74
+ apps
75
+ .command("get")
76
+ .description("Get app details and settings")
77
+ .argument("[app-id]", "App ID (uses current app if not specified)")
78
+ .option("--json", "Output as JSON")
79
+ .action(async (appId, options) => {
80
+ const resolvedAppId = appId || getCurrentAppId();
81
+ if (!resolvedAppId) {
82
+ error("No app specified. Use --app or 'primitive use <app-id>' to set context.");
83
+ process.exit(1);
84
+ }
85
+ const client = new ApiClient();
86
+ try {
87
+ const [appInfo, settings] = await Promise.all([
88
+ client.getApp(resolvedAppId),
89
+ client.getAppSettings(resolvedAppId).catch(() => null),
90
+ ]);
91
+ if (options.json) {
92
+ json({ ...appInfo, settings });
93
+ return;
94
+ }
95
+ keyValue("App ID", appInfo.id || resolvedAppId);
96
+ keyValue("Name", appInfo.name);
97
+ if (settings) {
98
+ divider();
99
+ keyValue("Mode", settings.mode);
100
+ keyValue("Waitlist Enabled", settings.waitlistEnabled);
101
+ keyValue("Base URL", settings.baseUrl);
102
+ divider();
103
+ info("Authentication:");
104
+ keyValue(" Google OAuth", settings.googleOAuthEnabled);
105
+ keyValue(" Passkey", settings.passkeyEnabled);
106
+ keyValue(" Magic Link", settings.magicLinkEnabled);
107
+ if (settings.corsMode === "custom") {
108
+ divider();
109
+ info("CORS:");
110
+ keyValue(" Mode", settings.corsMode);
111
+ keyValue(" Allowed Origins", settings.corsAllowedOrigins?.join(", ") || "-");
112
+ keyValue(" Allow Credentials", settings.corsAllowCredentials);
113
+ }
114
+ }
115
+ }
116
+ catch (err) {
117
+ error(err.message);
118
+ process.exit(1);
119
+ }
120
+ });
121
+ // Update app
122
+ apps
123
+ .command("update")
124
+ .description("Update app settings")
125
+ .argument("[app-id]", "App ID (uses current app if not specified)")
126
+ .option("--name <name>", "App name")
127
+ .option("--mode <mode>", "Access mode: public, invite-only, domain")
128
+ .option("--waitlist <bool>", "Enable/disable waitlist")
129
+ .option("--base-url <url>", "Base URL for the app")
130
+ .option("--google-oauth <bool>", "Enable/disable Google OAuth")
131
+ .option("--passkey <bool>", "Enable/disable passkey authentication")
132
+ .option("--magic-link <bool>", "Enable/disable magic link authentication")
133
+ .option("--cors-mode <mode>", "CORS mode: universal, custom")
134
+ .option("--cors-origins <origins>", "Comma-separated list of allowed origins")
135
+ .option("--cors-credentials <bool>", "Allow credentials in CORS")
136
+ .option("--json", "Output as JSON")
137
+ .action(async (appId, options) => {
138
+ const resolvedAppId = appId || getCurrentAppId();
139
+ if (!resolvedAppId) {
140
+ error("No app specified. Use --app or 'primitive use <app-id>' to set context.");
141
+ process.exit(1);
142
+ }
143
+ const client = new ApiClient();
144
+ // Build update payload from options
145
+ const payload = {};
146
+ if (options.name)
147
+ payload.name = options.name;
148
+ if (options.mode)
149
+ payload.mode = options.mode;
150
+ if (options.waitlist !== undefined)
151
+ payload.waitlistEnabled = options.waitlist === "true";
152
+ if (options.baseUrl)
153
+ payload.baseUrl = options.baseUrl;
154
+ if (options.googleOauth !== undefined)
155
+ payload.googleOAuthEnabled = options.googleOauth === "true";
156
+ if (options.passkey !== undefined)
157
+ payload.passkeyEnabled = options.passkey === "true";
158
+ if (options.magicLink !== undefined)
159
+ payload.magicLinkEnabled = options.magicLink === "true";
160
+ if (options.corsMode)
161
+ payload.corsMode = options.corsMode;
162
+ if (options.corsOrigins)
163
+ payload.corsAllowedOrigins = options.corsOrigins.split(",").map((s) => s.trim());
164
+ if (options.corsCredentials !== undefined)
165
+ payload.corsAllowCredentials = options.corsCredentials === "true";
166
+ if (Object.keys(payload).length === 0) {
167
+ error("No update options specified.");
168
+ process.exit(1);
169
+ }
170
+ try {
171
+ const result = await client.updateAppSettings(resolvedAppId, payload);
172
+ if (options.json) {
173
+ json(result);
174
+ return;
175
+ }
176
+ success("App settings updated.");
177
+ }
178
+ catch (err) {
179
+ error(err.message);
180
+ process.exit(1);
181
+ }
182
+ });
183
+ // Delete app
184
+ apps
185
+ .command("delete")
186
+ .description("Delete an app (super-admin only)")
187
+ .argument("<app-id>", "App ID to delete")
188
+ .option("--confirm <name>", "Skip interactive prompt by providing app name")
189
+ .action(async (appId, options) => {
190
+ const client = new ApiClient();
191
+ // Fetch app details first to get the name
192
+ let appName;
193
+ try {
194
+ const appInfo = await client.getApp(appId);
195
+ appName = appInfo.name;
196
+ }
197
+ catch (err) {
198
+ error(`Failed to fetch app: ${err.message}`);
199
+ process.exit(1);
200
+ }
201
+ // Show app details
202
+ console.log();
203
+ keyValue("App ID", appId);
204
+ keyValue("App Name", appName);
205
+ console.log();
206
+ if (options.confirm) {
207
+ // Non-interactive: verify the provided name matches
208
+ if (options.confirm !== appName) {
209
+ error(`App name does not match. Expected "${appName}", got "${options.confirm}".`);
210
+ process.exit(1);
211
+ }
212
+ }
213
+ else {
214
+ // Interactive: require typing the app name
215
+ const inquirer = await import("inquirer");
216
+ const { typedName } = await inquirer.default.prompt([
217
+ {
218
+ type: "input",
219
+ name: "typedName",
220
+ message: `Type the app name to confirm deletion:`,
221
+ },
222
+ ]);
223
+ if (typedName !== appName) {
224
+ error(`App name does not match. Deletion cancelled.`);
225
+ process.exit(1);
226
+ }
227
+ }
228
+ try {
229
+ await client.deleteApp(appId);
230
+ success(`App "${appName}" (${appId}) deleted.`);
231
+ }
232
+ catch (err) {
233
+ error(err.message);
234
+ process.exit(1);
235
+ }
236
+ });
237
+ }
238
+ //# sourceMappingURL=apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.js","sourceRoot":"","sources":["../../../src/commands/apps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ import { loadCredentials, clearCredentials, setCurrentApp, clearCurrentApp, } from "../lib/config.js";
2
+ import { browserLogin } from "../lib/auth-flow.js";
3
+ import { ApiClient } from "../lib/api-client.js";
4
+ import { success, error, info, keyValue, formatId, json, } from "../lib/output.js";
5
+ const DEFAULT_SERVER_URL = process.env.PRIMITIVE_SERVER_URL || "https://primitiveapi.com";
6
+ export function registerAuthCommands(program) {
7
+ // Login command
8
+ program
9
+ .command("login")
10
+ .description("Authenticate with the Primitive admin API via browser OAuth")
11
+ .option("-s, --server <url>", "Server URL", DEFAULT_SERVER_URL)
12
+ .action(async (options) => {
13
+ const serverUrl = options.server.replace(/\/$/, ""); // Remove trailing slash
14
+ const result = await browserLogin(serverUrl);
15
+ if (result.success && result.credentials) {
16
+ success(`Logged in as ${result.credentials.email}`);
17
+ if (result.credentials.role === "super-admin") {
18
+ info("You have super-admin privileges.");
19
+ }
20
+ }
21
+ else {
22
+ error(`Login failed: ${result.error || "Unknown error"}`);
23
+ process.exit(1);
24
+ }
25
+ });
26
+ // Logout command
27
+ program
28
+ .command("logout")
29
+ .description("Clear stored credentials")
30
+ .action(() => {
31
+ clearCredentials();
32
+ success("Logged out successfully.");
33
+ });
34
+ // Whoami command
35
+ program
36
+ .command("whoami")
37
+ .description("Show current authenticated user")
38
+ .option("--json", "Output as JSON")
39
+ .action((options) => {
40
+ const credentials = loadCredentials();
41
+ if (!credentials) {
42
+ error("Not logged in. Run 'primitive login' first.");
43
+ process.exit(2);
44
+ }
45
+ if (options.json) {
46
+ json({
47
+ email: credentials.email,
48
+ adminId: credentials.adminId,
49
+ role: credentials.role,
50
+ serverUrl: credentials.serverUrl,
51
+ currentAppId: credentials.currentAppId,
52
+ currentAppName: credentials.currentAppName,
53
+ });
54
+ return;
55
+ }
56
+ keyValue("Email", credentials.email);
57
+ keyValue("Admin ID", credentials.adminId);
58
+ keyValue("Role", credentials.role);
59
+ keyValue("Server", credentials.serverUrl);
60
+ if (credentials.currentAppId) {
61
+ keyValue("Current App", credentials.currentAppName || credentials.currentAppId);
62
+ }
63
+ });
64
+ // Token command - print access token for scripting
65
+ program
66
+ .command("token")
67
+ .description("Print the current access token (for scripting)")
68
+ .action(() => {
69
+ const credentials = loadCredentials();
70
+ if (!credentials) {
71
+ error("Not logged in. Run 'primitive login' first.");
72
+ process.exit(2);
73
+ }
74
+ // Print only the token for easy piping
75
+ console.log(credentials.accessToken);
76
+ });
77
+ // Use command - set current app context
78
+ program
79
+ .command("use [app-id-or-name]")
80
+ .description("Set the current app context (interactive if no argument)")
81
+ .action(async (appIdOrName) => {
82
+ const credentials = loadCredentials();
83
+ if (!credentials) {
84
+ error("Not logged in. Run 'primitive login' first.");
85
+ process.exit(2);
86
+ }
87
+ const client = new ApiClient();
88
+ try {
89
+ const { apps } = await client.listApps();
90
+ if (!apps || apps.length === 0) {
91
+ error("No apps available.");
92
+ process.exit(1);
93
+ }
94
+ let selectedApp;
95
+ if (appIdOrName) {
96
+ // Try to find by ID or name
97
+ selectedApp = apps.find((app) => app.id === appIdOrName ||
98
+ app.name.toLowerCase() === appIdOrName.toLowerCase());
99
+ if (!selectedApp) {
100
+ // Try partial name match
101
+ const matches = apps.filter((app) => app.name.toLowerCase().includes(appIdOrName.toLowerCase()));
102
+ if (matches.length === 1) {
103
+ selectedApp = matches[0];
104
+ }
105
+ else if (matches.length > 1) {
106
+ error(`Multiple apps match "${appIdOrName}":`);
107
+ matches.forEach((app) => {
108
+ console.log(` - ${app.name} (${app.id})`);
109
+ });
110
+ process.exit(1);
111
+ }
112
+ else {
113
+ error(`No app found matching "${appIdOrName}"`);
114
+ process.exit(1);
115
+ }
116
+ }
117
+ }
118
+ else {
119
+ // Interactive selection
120
+ const { Separator } = await import("@inquirer/prompts");
121
+ const { default: searchPrompt } = await import("@inquirer/search");
122
+ selectedApp = await searchPrompt({
123
+ message: "Select an app:",
124
+ source: (input) => {
125
+ const term = (input || "").toLowerCase();
126
+ const filtered = apps.filter((app) => app.name.toLowerCase().includes(term) ||
127
+ app.id.toLowerCase().includes(term));
128
+ return filtered.map((app) => ({
129
+ name: `${app.name} (${formatId(app.id)})`,
130
+ value: app,
131
+ }));
132
+ },
133
+ });
134
+ }
135
+ if (selectedApp) {
136
+ setCurrentApp(selectedApp.id, selectedApp.name);
137
+ success(`Now using app: ${selectedApp.name} (${selectedApp.id})`);
138
+ }
139
+ }
140
+ catch (err) {
141
+ error(err.message || "Failed to list apps");
142
+ process.exit(1);
143
+ }
144
+ });
145
+ // Context command - show or clear current app context
146
+ program
147
+ .command("context")
148
+ .description("Show or manage current app context")
149
+ .argument("[action]", "Action: 'clear' to remove context")
150
+ .option("--json", "Output as JSON")
151
+ .action((action, options) => {
152
+ if (action === "clear") {
153
+ clearCurrentApp();
154
+ success("App context cleared.");
155
+ return;
156
+ }
157
+ const credentials = loadCredentials();
158
+ if (!credentials) {
159
+ error("Not logged in. Run 'primitive login' first.");
160
+ process.exit(2);
161
+ }
162
+ if (options.json) {
163
+ json({
164
+ currentAppId: credentials.currentAppId || null,
165
+ currentAppName: credentials.currentAppName || null,
166
+ });
167
+ return;
168
+ }
169
+ if (credentials.currentAppId) {
170
+ keyValue("Current App", credentials.currentAppName || "");
171
+ keyValue("App ID", credentials.currentAppId);
172
+ }
173
+ else {
174
+ info("No app context set. Use 'primitive use <app-id>' to set one.");
175
+ }
176
+ });
177
+ }
178
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/commands/auth.ts"],"names":[],"mappings":"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"}