@plures/praxis 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/FRAMEWORK.md +420 -0
- package/LICENSE +21 -0
- package/README.md +1310 -0
- package/dist/adapters/cli.d.ts +43 -0
- package/dist/adapters/cli.d.ts.map +1 -0
- package/dist/adapters/cli.js +126 -0
- package/dist/adapters/cli.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +26 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +233 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/cloud.d.ts +27 -0
- package/dist/cli/commands/cloud.d.ts.map +1 -0
- package/dist/cli/commands/cloud.js +232 -0
- package/dist/cli/commands/cloud.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +25 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +168 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +179 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cloud/auth.d.ts +51 -0
- package/dist/cloud/auth.d.ts.map +1 -0
- package/dist/cloud/auth.js +194 -0
- package/dist/cloud/auth.js.map +1 -0
- package/dist/cloud/billing.d.ts +184 -0
- package/dist/cloud/billing.d.ts.map +1 -0
- package/dist/cloud/billing.js +179 -0
- package/dist/cloud/billing.js.map +1 -0
- package/dist/cloud/client.d.ts +39 -0
- package/dist/cloud/client.d.ts.map +1 -0
- package/dist/cloud/client.js +176 -0
- package/dist/cloud/client.js.map +1 -0
- package/dist/cloud/index.d.ts +44 -0
- package/dist/cloud/index.d.ts.map +1 -0
- package/dist/cloud/index.js +44 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/cloud/marketplace.d.ts +166 -0
- package/dist/cloud/marketplace.d.ts.map +1 -0
- package/dist/cloud/marketplace.js +159 -0
- package/dist/cloud/marketplace.js.map +1 -0
- package/dist/cloud/provisioning.d.ts +110 -0
- package/dist/cloud/provisioning.d.ts.map +1 -0
- package/dist/cloud/provisioning.js +148 -0
- package/dist/cloud/provisioning.js.map +1 -0
- package/dist/cloud/relay/endpoints.d.ts +62 -0
- package/dist/cloud/relay/endpoints.d.ts.map +1 -0
- package/dist/cloud/relay/endpoints.js +217 -0
- package/dist/cloud/relay/endpoints.js.map +1 -0
- package/dist/cloud/relay/health/index.d.ts +5 -0
- package/dist/cloud/relay/health/index.d.ts.map +1 -0
- package/dist/cloud/relay/health/index.js +9 -0
- package/dist/cloud/relay/health/index.js.map +1 -0
- package/dist/cloud/relay/stats/index.d.ts +5 -0
- package/dist/cloud/relay/stats/index.d.ts.map +1 -0
- package/dist/cloud/relay/stats/index.js +9 -0
- package/dist/cloud/relay/stats/index.js.map +1 -0
- package/dist/cloud/relay/sync/index.d.ts +5 -0
- package/dist/cloud/relay/sync/index.d.ts.map +1 -0
- package/dist/cloud/relay/sync/index.js +9 -0
- package/dist/cloud/relay/sync/index.js.map +1 -0
- package/dist/cloud/relay/usage/index.d.ts +5 -0
- package/dist/cloud/relay/usage/index.d.ts.map +1 -0
- package/dist/cloud/relay/usage/index.js +9 -0
- package/dist/cloud/relay/usage/index.js.map +1 -0
- package/dist/cloud/sponsors.d.ts +81 -0
- package/dist/cloud/sponsors.d.ts.map +1 -0
- package/dist/cloud/sponsors.js +130 -0
- package/dist/cloud/sponsors.js.map +1 -0
- package/dist/cloud/types.d.ts +169 -0
- package/dist/cloud/types.d.ts.map +1 -0
- package/dist/cloud/types.js +7 -0
- package/dist/cloud/types.js.map +1 -0
- package/dist/components/index.d.ts +43 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +17 -0
- package/dist/components/index.js.map +1 -0
- package/dist/core/actors.d.ts +95 -0
- package/dist/core/actors.d.ts.map +1 -0
- package/dist/core/actors.js +158 -0
- package/dist/core/actors.js.map +1 -0
- package/dist/core/component/generator.d.ts +122 -0
- package/dist/core/component/generator.d.ts.map +1 -0
- package/dist/core/component/generator.js +307 -0
- package/dist/core/component/generator.js.map +1 -0
- package/dist/core/engine.d.ts +92 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +199 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/introspection.d.ts +141 -0
- package/dist/core/introspection.d.ts.map +1 -0
- package/dist/core/introspection.js +208 -0
- package/dist/core/introspection.js.map +1 -0
- package/dist/core/logic/generator.d.ts +76 -0
- package/dist/core/logic/generator.d.ts.map +1 -0
- package/dist/core/logic/generator.js +339 -0
- package/dist/core/logic/generator.js.map +1 -0
- package/dist/core/pluresdb/generator.d.ts +58 -0
- package/dist/core/pluresdb/generator.d.ts.map +1 -0
- package/dist/core/pluresdb/generator.js +162 -0
- package/dist/core/pluresdb/generator.js.map +1 -0
- package/dist/core/protocol.d.ts +121 -0
- package/dist/core/protocol.d.ts.map +1 -0
- package/dist/core/protocol.js +46 -0
- package/dist/core/protocol.js.map +1 -0
- package/dist/core/rules.d.ts +120 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +81 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/schema/loader.d.ts +47 -0
- package/dist/core/schema/loader.d.ts.map +1 -0
- package/dist/core/schema/loader.js +189 -0
- package/dist/core/schema/loader.js.map +1 -0
- package/dist/core/schema/normalize.d.ts +72 -0
- package/dist/core/schema/normalize.d.ts.map +1 -0
- package/dist/core/schema/normalize.js +190 -0
- package/dist/core/schema/normalize.js.map +1 -0
- package/dist/core/schema/types.d.ts +370 -0
- package/dist/core/schema/types.d.ts.map +1 -0
- package/dist/core/schema/types.js +161 -0
- package/dist/core/schema/types.js.map +1 -0
- package/dist/dsl/index.d.ts +152 -0
- package/dist/dsl/index.d.ts.map +1 -0
- package/dist/dsl/index.js +132 -0
- package/dist/dsl/index.js.map +1 -0
- package/dist/dsl.d.ts +124 -0
- package/dist/dsl.d.ts.map +1 -0
- package/dist/dsl.js +130 -0
- package/dist/dsl.js.map +1 -0
- package/dist/examples/advanced-todo/index.d.ts +55 -0
- package/dist/examples/advanced-todo/index.d.ts.map +1 -0
- package/dist/examples/advanced-todo/index.js +222 -0
- package/dist/examples/advanced-todo/index.js.map +1 -0
- package/dist/examples/auth-basic/index.d.ts +17 -0
- package/dist/examples/auth-basic/index.d.ts.map +1 -0
- package/dist/examples/auth-basic/index.js +122 -0
- package/dist/examples/auth-basic/index.js.map +1 -0
- package/dist/examples/cart/index.d.ts +19 -0
- package/dist/examples/cart/index.d.ts.map +1 -0
- package/dist/examples/cart/index.js +202 -0
- package/dist/examples/cart/index.js.map +1 -0
- package/dist/examples/hero-ecommerce/index.d.ts +39 -0
- package/dist/examples/hero-ecommerce/index.d.ts.map +1 -0
- package/dist/examples/hero-ecommerce/index.js +506 -0
- package/dist/examples/hero-ecommerce/index.js.map +1 -0
- package/dist/examples/svelte-counter/index.d.ts +31 -0
- package/dist/examples/svelte-counter/index.d.ts.map +1 -0
- package/dist/examples/svelte-counter/index.js +123 -0
- package/dist/examples/svelte-counter/index.js.map +1 -0
- package/dist/flows.d.ts +125 -0
- package/dist/flows.d.ts.map +1 -0
- package/dist/flows.js +160 -0
- package/dist/flows.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/pluresdb.d.ts +56 -0
- package/dist/integrations/pluresdb.d.ts.map +1 -0
- package/dist/integrations/pluresdb.js +46 -0
- package/dist/integrations/pluresdb.js.map +1 -0
- package/dist/integrations/svelte.d.ts +306 -0
- package/dist/integrations/svelte.d.ts.map +1 -0
- package/dist/integrations/svelte.js +447 -0
- package/dist/integrations/svelte.js.map +1 -0
- package/dist/registry.d.ts +94 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +181 -0
- package/dist/registry.js.map +1 -0
- package/dist/runtime/terminal-adapter.d.ts +105 -0
- package/dist/runtime/terminal-adapter.d.ts.map +1 -0
- package/dist/runtime/terminal-adapter.js +113 -0
- package/dist/runtime/terminal-adapter.js.map +1 -0
- package/dist/step.d.ts +34 -0
- package/dist/step.d.ts.map +1 -0
- package/dist/step.js +111 -0
- package/dist/step.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/docs/MONETIZATION.md +394 -0
- package/docs/TERMINAL_NODE.md +588 -0
- package/docs/guides/canvas.md +389 -0
- package/docs/guides/getting-started.md +347 -0
- package/docs/guides/history-state-pattern.md +618 -0
- package/docs/guides/orchestration.md +617 -0
- package/docs/guides/parallel-state-pattern.md +767 -0
- package/docs/guides/svelte-integration.md +691 -0
- package/package.json +96 -0
- package/src/__tests__/actors.test.ts +270 -0
- package/src/__tests__/billing.test.ts +175 -0
- package/src/__tests__/cloud.test.ts +247 -0
- package/src/__tests__/dsl.test.ts +154 -0
- package/src/__tests__/edge-cases.test.ts +475 -0
- package/src/__tests__/engine.test.ts +137 -0
- package/src/__tests__/generators.test.ts +270 -0
- package/src/__tests__/introspection.test.ts +321 -0
- package/src/__tests__/protocol.test.ts +40 -0
- package/src/__tests__/provisioning.test.ts +162 -0
- package/src/__tests__/schema.test.ts +241 -0
- package/src/__tests__/svelte-integration.test.ts +431 -0
- package/src/__tests__/terminal-node.test.ts +352 -0
- package/src/adapters/cli.ts +175 -0
- package/src/cli/commands/auth.ts +271 -0
- package/src/cli/commands/cloud.ts +281 -0
- package/src/cli/commands/generate.ts +225 -0
- package/src/cli/index.ts +190 -0
- package/src/cloud/README.md +383 -0
- package/src/cloud/auth.ts +245 -0
- package/src/cloud/billing.ts +336 -0
- package/src/cloud/client.ts +221 -0
- package/src/cloud/index.ts +121 -0
- package/src/cloud/marketplace.ts +303 -0
- package/src/cloud/provisioning.ts +254 -0
- package/src/cloud/relay/endpoints.ts +307 -0
- package/src/cloud/relay/health/function.json +17 -0
- package/src/cloud/relay/health/index.ts +10 -0
- package/src/cloud/relay/host.json +15 -0
- package/src/cloud/relay/local.settings.json +8 -0
- package/src/cloud/relay/stats/function.json +17 -0
- package/src/cloud/relay/stats/index.ts +10 -0
- package/src/cloud/relay/sync/function.json +17 -0
- package/src/cloud/relay/sync/index.ts +10 -0
- package/src/cloud/relay/usage/function.json +17 -0
- package/src/cloud/relay/usage/index.ts +10 -0
- package/src/cloud/sponsors.ts +213 -0
- package/src/cloud/types.ts +198 -0
- package/src/components/README.md +125 -0
- package/src/components/TerminalNode.svelte +457 -0
- package/src/components/index.ts +46 -0
- package/src/core/actors.ts +205 -0
- package/src/core/component/generator.ts +432 -0
- package/src/core/engine.ts +243 -0
- package/src/core/introspection.ts +329 -0
- package/src/core/logic/generator.ts +420 -0
- package/src/core/pluresdb/generator.ts +229 -0
- package/src/core/protocol.ts +132 -0
- package/src/core/rules.ts +167 -0
- package/src/core/schema/loader.ts +247 -0
- package/src/core/schema/normalize.ts +322 -0
- package/src/core/schema/types.ts +557 -0
- package/src/dsl/index.ts +218 -0
- package/src/dsl.ts +214 -0
- package/src/examples/advanced-todo/App.svelte +506 -0
- package/src/examples/advanced-todo/README.md +371 -0
- package/src/examples/advanced-todo/index.ts +309 -0
- package/src/examples/auth-basic/index.ts +163 -0
- package/src/examples/cart/index.ts +259 -0
- package/src/examples/hero-ecommerce/index.ts +657 -0
- package/src/examples/svelte-counter/index.ts +168 -0
- package/src/flows.ts +268 -0
- package/src/index.ts +154 -0
- package/src/integrations/pluresdb.ts +93 -0
- package/src/integrations/svelte.ts +617 -0
- package/src/registry.ts +223 -0
- package/src/runtime/terminal-adapter.ts +175 -0
- package/src/step.ts +151 -0
- package/src/types.ts +70 -0
- package/templates/basic-app/README.md +147 -0
- package/templates/fullstack-app/README.md +279 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Commands for authenticating with GitHub for Praxis Cloud access.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as os from "os";
|
|
10
|
+
import { authenticateWithDeviceFlow } from "../../cloud/auth.js";
|
|
11
|
+
import { createSponsorsClient } from "../../cloud/sponsors.js";
|
|
12
|
+
import type { AuthResult } from "../../cloud/types.js";
|
|
13
|
+
|
|
14
|
+
const AUTH_DIR = path.join(os.homedir(), ".praxis");
|
|
15
|
+
const AUTH_FILE = path.join(AUTH_DIR, "auth.json");
|
|
16
|
+
const GITHUB_CLIENT_ID = "Ov23liQxF7P0BqUxVXHk"; // Demo client ID (replace in production)
|
|
17
|
+
|
|
18
|
+
interface StoredAuth {
|
|
19
|
+
token: string;
|
|
20
|
+
userId: number;
|
|
21
|
+
userLogin: string;
|
|
22
|
+
userName?: string;
|
|
23
|
+
userEmail?: string;
|
|
24
|
+
authenticatedAt: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Load stored authentication
|
|
29
|
+
*/
|
|
30
|
+
function loadAuth(): StoredAuth | null {
|
|
31
|
+
try {
|
|
32
|
+
if (fs.existsSync(AUTH_FILE)) {
|
|
33
|
+
const data = fs.readFileSync(AUTH_FILE, "utf-8");
|
|
34
|
+
return JSON.parse(data);
|
|
35
|
+
}
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.warn("Failed to load authentication:", error);
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Save authentication
|
|
44
|
+
*/
|
|
45
|
+
function saveAuth(auth: StoredAuth): void {
|
|
46
|
+
try {
|
|
47
|
+
// Ensure directory exists
|
|
48
|
+
if (!fs.existsSync(AUTH_DIR)) {
|
|
49
|
+
fs.mkdirSync(AUTH_DIR, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Save with restricted permissions
|
|
53
|
+
fs.writeFileSync(AUTH_FILE, JSON.stringify(auth, null, 2), { mode: 0o600 });
|
|
54
|
+
console.log(`\n✓ Authentication saved to ${AUTH_FILE}`);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error("Failed to save authentication:", error);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Delete stored authentication
|
|
63
|
+
*/
|
|
64
|
+
function deleteAuth(): void {
|
|
65
|
+
try {
|
|
66
|
+
if (fs.existsSync(AUTH_FILE)) {
|
|
67
|
+
fs.unlinkSync(AUTH_FILE);
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.warn("Failed to delete authentication:", error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Login command
|
|
76
|
+
*/
|
|
77
|
+
export async function loginCommand(options: { token?: string }): Promise<void> {
|
|
78
|
+
console.log("\n╔═══════════════════════════════════════════════════╗");
|
|
79
|
+
console.log("║ Praxis Cloud Authentication ║");
|
|
80
|
+
console.log("╚═══════════════════════════════════════════════════╝\n");
|
|
81
|
+
|
|
82
|
+
// Check if already authenticated
|
|
83
|
+
const existingAuth = loadAuth();
|
|
84
|
+
if (existingAuth) {
|
|
85
|
+
console.log("⚠ Already authenticated");
|
|
86
|
+
console.log(` User: ${existingAuth.userLogin}`);
|
|
87
|
+
console.log(` Authenticated at: ${new Date(existingAuth.authenticatedAt).toLocaleString()}\n`);
|
|
88
|
+
console.log("Run 'praxis logout' to log out first.");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let authResult: AuthResult;
|
|
93
|
+
|
|
94
|
+
if (options.token) {
|
|
95
|
+
// Use provided token
|
|
96
|
+
console.log("🔐 Using provided personal access token...");
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetch("https://api.github.com/user", {
|
|
100
|
+
headers: {
|
|
101
|
+
Authorization: `Bearer ${options.token}`,
|
|
102
|
+
Accept: "application/vnd.github.v3+json",
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (!response.ok) {
|
|
107
|
+
throw new Error(`Invalid token: ${response.statusText}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const userData = await response.json() as any;
|
|
111
|
+
|
|
112
|
+
authResult = {
|
|
113
|
+
success: true,
|
|
114
|
+
token: options.token,
|
|
115
|
+
user: {
|
|
116
|
+
id: userData.id,
|
|
117
|
+
login: userData.login,
|
|
118
|
+
email: userData.email,
|
|
119
|
+
name: userData.name,
|
|
120
|
+
avatarUrl: userData.avatar_url,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error("\n✗ Authentication failed");
|
|
125
|
+
console.error(` Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
// Use device flow
|
|
130
|
+
console.log("🔐 Authenticating with GitHub device flow...");
|
|
131
|
+
authResult = await authenticateWithDeviceFlow(GITHUB_CLIENT_ID);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!authResult.success || !authResult.token || !authResult.user) {
|
|
135
|
+
console.error("\n✗ Authentication failed");
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
console.log(`✓ Authenticated as ${authResult.user.login}`);
|
|
140
|
+
|
|
141
|
+
// Check GitHub Sponsors status
|
|
142
|
+
console.log("\n🔍 Checking GitHub Sponsors status...");
|
|
143
|
+
try {
|
|
144
|
+
const sponsorsClient = createSponsorsClient(authResult.token);
|
|
145
|
+
const subscription = await sponsorsClient.getSubscription(authResult.user.login);
|
|
146
|
+
|
|
147
|
+
console.log(`✓ Subscription tier: ${subscription.tier}`);
|
|
148
|
+
console.log(` Status: ${subscription.status}`);
|
|
149
|
+
console.log(` Provider: ${subscription.provider}`);
|
|
150
|
+
|
|
151
|
+
if (subscription.tier === "free") {
|
|
152
|
+
console.log("\n💡 Upgrade to a paid tier for more features!");
|
|
153
|
+
console.log(" Visit: https://github.com/sponsors/plures");
|
|
154
|
+
}
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.warn("\n⚠ Could not check Sponsors status");
|
|
157
|
+
console.warn(` Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Save authentication
|
|
161
|
+
const storedAuth: StoredAuth = {
|
|
162
|
+
token: authResult.token,
|
|
163
|
+
userId: authResult.user.id,
|
|
164
|
+
userLogin: authResult.user.login,
|
|
165
|
+
userName: authResult.user.name,
|
|
166
|
+
userEmail: authResult.user.email,
|
|
167
|
+
authenticatedAt: Date.now(),
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
saveAuth(storedAuth);
|
|
171
|
+
|
|
172
|
+
console.log("\n✓ Successfully logged in!");
|
|
173
|
+
console.log("\nNext steps:");
|
|
174
|
+
console.log(" • Use 'praxis cloud init' to set up cloud connection");
|
|
175
|
+
console.log(" • Use 'praxis whoami' to check your authentication");
|
|
176
|
+
console.log(" • Use 'praxis cloud status' to check subscription\n");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Logout command
|
|
181
|
+
*/
|
|
182
|
+
export async function logoutCommand(): Promise<void> {
|
|
183
|
+
const auth = loadAuth();
|
|
184
|
+
|
|
185
|
+
if (!auth) {
|
|
186
|
+
console.log("\n✗ Not currently logged in");
|
|
187
|
+
console.log(" Run 'praxis login' to authenticate\n");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
console.log(`\nLogging out user: ${auth.userLogin}...`);
|
|
192
|
+
|
|
193
|
+
deleteAuth();
|
|
194
|
+
|
|
195
|
+
console.log("✓ Successfully logged out\n");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Whoami command
|
|
200
|
+
*/
|
|
201
|
+
export async function whoamiCommand(): Promise<void> {
|
|
202
|
+
const auth = loadAuth();
|
|
203
|
+
|
|
204
|
+
if (!auth) {
|
|
205
|
+
console.log("\n✗ Not currently logged in");
|
|
206
|
+
console.log(" Run 'praxis login' to authenticate\n");
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log("\n╔═══════════════════════════════════════════════════╗");
|
|
211
|
+
console.log("║ Current Authentication ║");
|
|
212
|
+
console.log("╚═══════════════════════════════════════════════════╝\n");
|
|
213
|
+
|
|
214
|
+
console.log(`User: ${auth.userLogin}`);
|
|
215
|
+
if (auth.userName) {
|
|
216
|
+
console.log(`Name: ${auth.userName}`);
|
|
217
|
+
}
|
|
218
|
+
if (auth.userEmail) {
|
|
219
|
+
console.log(`Email: ${auth.userEmail}`);
|
|
220
|
+
}
|
|
221
|
+
console.log(`User ID: ${auth.userId}`);
|
|
222
|
+
console.log(`Authenticated: ${new Date(auth.authenticatedAt).toLocaleString()}`);
|
|
223
|
+
|
|
224
|
+
// Check token validity
|
|
225
|
+
console.log("\n🔍 Checking token validity...");
|
|
226
|
+
try {
|
|
227
|
+
const response = await fetch("https://api.github.com/user", {
|
|
228
|
+
headers: {
|
|
229
|
+
Authorization: `Bearer ${auth.token}`,
|
|
230
|
+
Accept: "application/vnd.github.v3+json",
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
if (response.ok) {
|
|
235
|
+
console.log("✓ Token is valid");
|
|
236
|
+
|
|
237
|
+
// Check subscription
|
|
238
|
+
console.log("\n🔍 Checking subscription...");
|
|
239
|
+
const sponsorsClient = createSponsorsClient(auth.token);
|
|
240
|
+
const subscription = await sponsorsClient.getSubscription(auth.userLogin);
|
|
241
|
+
|
|
242
|
+
console.log(`Tier: ${subscription.tier}`);
|
|
243
|
+
console.log(`Status: ${subscription.status}`);
|
|
244
|
+
console.log(`Provider: ${subscription.provider}`);
|
|
245
|
+
console.log("\nLimits:");
|
|
246
|
+
console.log(` Syncs/month: ${subscription.limits.maxSyncsPerMonth.toLocaleString()}`);
|
|
247
|
+
console.log(` Storage: ${(subscription.limits.maxStorageBytes / 1024 / 1024).toFixed(0)} MB`);
|
|
248
|
+
console.log(` Apps: ${subscription.limits.maxApps}`);
|
|
249
|
+
console.log(` Team members: ${subscription.limits.maxTeamMembers ?? "Unlimited"}`);
|
|
250
|
+
console.log(` Support: ${subscription.limits.supportLevel}`);
|
|
251
|
+
} else {
|
|
252
|
+
console.log("✗ Token is invalid or expired");
|
|
253
|
+
console.log(" Run 'praxis login' to re-authenticate");
|
|
254
|
+
}
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.error("\n✗ Failed to check token validity");
|
|
257
|
+
console.error(` Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.log();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get stored authentication token
|
|
265
|
+
*
|
|
266
|
+
* Used by other commands that need authentication
|
|
267
|
+
*/
|
|
268
|
+
export function getAuthToken(): string | null {
|
|
269
|
+
const auth = loadAuth();
|
|
270
|
+
return auth?.token || null;
|
|
271
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* CLI commands for Praxis Cloud connectivity.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { authenticateWithDeviceFlow } from "../../cloud/auth.js";
|
|
10
|
+
import { connectRelay } from "../../cloud/client.js";
|
|
11
|
+
import type { CloudRelayConfig } from "../../cloud/types.js";
|
|
12
|
+
|
|
13
|
+
const CONFIG_FILE = ".praxis-cloud.json";
|
|
14
|
+
const GITHUB_CLIENT_ID = "Ov23liQxF7P0BqUxVXHk"; // Demo client ID (replace in production)
|
|
15
|
+
|
|
16
|
+
interface StoredConfig {
|
|
17
|
+
endpoint: string;
|
|
18
|
+
appId: string;
|
|
19
|
+
authToken?: string;
|
|
20
|
+
autoSync?: boolean;
|
|
21
|
+
syncInterval?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Load stored cloud configuration
|
|
26
|
+
*/
|
|
27
|
+
function loadConfig(): StoredConfig | null {
|
|
28
|
+
try {
|
|
29
|
+
const configPath = path.join(process.cwd(), CONFIG_FILE);
|
|
30
|
+
if (fs.existsSync(configPath)) {
|
|
31
|
+
const data = fs.readFileSync(configPath, "utf-8");
|
|
32
|
+
return JSON.parse(data);
|
|
33
|
+
}
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.warn("Failed to load cloud configuration:", error);
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Save cloud configuration
|
|
42
|
+
*/
|
|
43
|
+
function saveConfig(config: StoredConfig): void {
|
|
44
|
+
try {
|
|
45
|
+
const configPath = path.join(process.cwd(), CONFIG_FILE);
|
|
46
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
47
|
+
console.log(`\n✓ Configuration saved to ${CONFIG_FILE}`);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("Failed to save cloud configuration:", error);
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Initialize cloud connection (wizard)
|
|
56
|
+
*/
|
|
57
|
+
export async function cloudInit(options: {
|
|
58
|
+
endpoint?: string;
|
|
59
|
+
appId?: string;
|
|
60
|
+
autoSync?: boolean;
|
|
61
|
+
interval?: string;
|
|
62
|
+
}): Promise<void> {
|
|
63
|
+
console.log("\n╔═══════════════════════════════════════════════════╗");
|
|
64
|
+
console.log("║ Welcome to Praxis Cloud Setup Wizard ║");
|
|
65
|
+
console.log("╚═══════════════════════════════════════════════════╝\n");
|
|
66
|
+
|
|
67
|
+
// Check if already configured
|
|
68
|
+
const existingConfig = loadConfig();
|
|
69
|
+
if (existingConfig) {
|
|
70
|
+
console.log("⚠ Existing cloud configuration found.");
|
|
71
|
+
console.log(` Endpoint: ${existingConfig.endpoint}`);
|
|
72
|
+
console.log(` App ID: ${existingConfig.appId}\n`);
|
|
73
|
+
// In production, prompt user to confirm overwrite
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get endpoint
|
|
77
|
+
let endpoint = options.endpoint;
|
|
78
|
+
if (!endpoint) {
|
|
79
|
+
// In production, prompt user for input
|
|
80
|
+
endpoint = "https://praxis-relay.azurewebsites.net";
|
|
81
|
+
console.log(`Using default endpoint: ${endpoint}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get app ID
|
|
85
|
+
let appId = options.appId;
|
|
86
|
+
if (!appId) {
|
|
87
|
+
// In production, prompt user for input or generate from git remote
|
|
88
|
+
appId = path.basename(process.cwd());
|
|
89
|
+
console.log(`Using app ID from directory name: ${appId}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Authenticate with GitHub
|
|
93
|
+
console.log("\n🔐 Authenticating with GitHub...");
|
|
94
|
+
const authResult = await authenticateWithDeviceFlow(GITHUB_CLIENT_ID);
|
|
95
|
+
|
|
96
|
+
if (!authResult.success || !authResult.token) {
|
|
97
|
+
console.error("\n✗ Authentication failed");
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(`✓ Authenticated as ${authResult.user?.login || "unknown"}`);
|
|
102
|
+
|
|
103
|
+
// Test connection
|
|
104
|
+
console.log("\n🔗 Testing connection to Praxis Cloud...");
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const config: CloudRelayConfig = {
|
|
108
|
+
endpoint,
|
|
109
|
+
appId,
|
|
110
|
+
authToken: authResult.token,
|
|
111
|
+
autoSync: options.autoSync,
|
|
112
|
+
syncInterval: options.interval ? parseInt(options.interval) : 5000,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const client = await connectRelay(endpoint, config);
|
|
116
|
+
const health = await client.getHealth();
|
|
117
|
+
|
|
118
|
+
if (health.status === "healthy") {
|
|
119
|
+
console.log("✓ Connected successfully!");
|
|
120
|
+
console.log(` Status: ${health.status}`);
|
|
121
|
+
console.log(` Version: ${health.version}`);
|
|
122
|
+
} else {
|
|
123
|
+
console.log(`⚠ Connected but service is ${health.status}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
await client.disconnect();
|
|
127
|
+
|
|
128
|
+
// Save configuration
|
|
129
|
+
const storedConfig: StoredConfig = {
|
|
130
|
+
endpoint,
|
|
131
|
+
appId,
|
|
132
|
+
authToken: authResult.token,
|
|
133
|
+
autoSync: options.autoSync,
|
|
134
|
+
syncInterval: config.syncInterval,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
saveConfig(storedConfig);
|
|
138
|
+
|
|
139
|
+
console.log("\n✓ Praxis Cloud is now configured!");
|
|
140
|
+
console.log("\nNext steps:");
|
|
141
|
+
console.log(" • Use 'praxis cloud status' to check connection");
|
|
142
|
+
console.log(" • Use 'praxis cloud sync' to manually sync");
|
|
143
|
+
console.log(" • Use 'praxis cloud usage' to view metrics");
|
|
144
|
+
console.log("\nIn your code:");
|
|
145
|
+
console.log(' import { connectRelay } from "@plures/praxis/cloud";');
|
|
146
|
+
console.log(` const relay = await connectRelay("${endpoint}", {`);
|
|
147
|
+
console.log(` appId: "${appId}",`);
|
|
148
|
+
console.log(` authToken: "<your-token>"`);
|
|
149
|
+
console.log(" });\n");
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error("\n✗ Failed to connect to Praxis Cloud");
|
|
152
|
+
console.error(` Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Check cloud connection status
|
|
159
|
+
*/
|
|
160
|
+
export async function cloudStatus(): Promise<void> {
|
|
161
|
+
const config = loadConfig();
|
|
162
|
+
|
|
163
|
+
if (!config) {
|
|
164
|
+
console.log("\n✗ No cloud configuration found");
|
|
165
|
+
console.log(" Run 'praxis cloud init' to set up cloud connection\n");
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log("\n╔═══════════════════════════════════════════════════╗");
|
|
170
|
+
console.log("║ Praxis Cloud Status ║");
|
|
171
|
+
console.log("╚═══════════════════════════════════════════════════╝\n");
|
|
172
|
+
|
|
173
|
+
console.log(`Endpoint: ${config.endpoint}`);
|
|
174
|
+
console.log(`App ID: ${config.appId}`);
|
|
175
|
+
console.log(`Auto Sync: ${config.autoSync ? "enabled" : "disabled"}`);
|
|
176
|
+
|
|
177
|
+
if (config.autoSync) {
|
|
178
|
+
console.log(`Sync Interval: ${config.syncInterval}ms`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const client = await connectRelay(config.endpoint, config);
|
|
183
|
+
const health = await client.getHealth();
|
|
184
|
+
|
|
185
|
+
console.log(`\nConnection: ✓ Connected`);
|
|
186
|
+
console.log(`Status: ${health.status}`);
|
|
187
|
+
console.log(`Version: ${health.version}`);
|
|
188
|
+
console.log("\nServices:");
|
|
189
|
+
console.log(` Relay: ${health.services.relay ? "✓" : "✗"}`);
|
|
190
|
+
console.log(` Event Grid: ${health.services.eventGrid ? "✓" : "✗"}`);
|
|
191
|
+
console.log(` Storage: ${health.services.storage ? "✓" : "✗"}`);
|
|
192
|
+
console.log(` Auth: ${health.services.auth ? "✓" : "✗"}`);
|
|
193
|
+
|
|
194
|
+
await client.disconnect();
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.log(`\nConnection: ✗ Failed`);
|
|
197
|
+
console.log(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
console.log();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Manually trigger cloud sync
|
|
205
|
+
*/
|
|
206
|
+
export async function cloudSync(): Promise<void> {
|
|
207
|
+
const config = loadConfig();
|
|
208
|
+
|
|
209
|
+
if (!config) {
|
|
210
|
+
console.log("\n✗ No cloud configuration found");
|
|
211
|
+
console.log(" Run 'praxis cloud init' to set up cloud connection\n");
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log("\n🔄 Syncing to Praxis Cloud...");
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const client = await connectRelay(config.endpoint, config);
|
|
219
|
+
|
|
220
|
+
// In production, collect actual facts and events to sync
|
|
221
|
+
await client.sync({
|
|
222
|
+
type: "delta",
|
|
223
|
+
appId: config.appId,
|
|
224
|
+
clock: {},
|
|
225
|
+
facts: [],
|
|
226
|
+
events: [],
|
|
227
|
+
timestamp: Date.now(),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
console.log("✓ Sync completed successfully\n");
|
|
231
|
+
|
|
232
|
+
await client.disconnect();
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error("\n✗ Sync failed");
|
|
235
|
+
console.error(` Error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* View cloud usage metrics
|
|
242
|
+
*/
|
|
243
|
+
export async function cloudUsage(): Promise<void> {
|
|
244
|
+
const config = loadConfig();
|
|
245
|
+
|
|
246
|
+
if (!config) {
|
|
247
|
+
console.log("\n✗ No cloud configuration found");
|
|
248
|
+
console.log(" Run 'praxis cloud init' to set up cloud connection\n");
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
console.log("\n╔═══════════════════════════════════════════════════╗");
|
|
253
|
+
console.log("║ Praxis Cloud Usage Metrics ║");
|
|
254
|
+
console.log("╚═══════════════════════════════════════════════════╝\n");
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
const client = await connectRelay(config.endpoint, config);
|
|
258
|
+
const usage = await client.getUsage();
|
|
259
|
+
|
|
260
|
+
console.log(`App ID: ${usage.appId}`);
|
|
261
|
+
console.log(`\nMetrics:`);
|
|
262
|
+
console.log(` Total Syncs: ${usage.syncCount}`);
|
|
263
|
+
console.log(` Events Forwarded: ${usage.eventCount}`);
|
|
264
|
+
console.log(` Facts Synced: ${usage.factCount}`);
|
|
265
|
+
console.log(` Storage Used: ${(usage.storageBytes / 1024).toFixed(2)} KB`);
|
|
266
|
+
|
|
267
|
+
const periodDuration = usage.periodEnd - usage.periodStart;
|
|
268
|
+
const durationHours = (periodDuration / 1000 / 60 / 60).toFixed(1);
|
|
269
|
+
console.log(`\nPeriod: ${durationHours} hours`);
|
|
270
|
+
console.log(` From: ${new Date(usage.periodStart).toLocaleString()}`);
|
|
271
|
+
console.log(` To: ${new Date(usage.periodEnd).toLocaleString()}`);
|
|
272
|
+
|
|
273
|
+
console.log();
|
|
274
|
+
|
|
275
|
+
await client.disconnect();
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error("\n✗ Failed to retrieve usage metrics");
|
|
278
|
+
console.error(` Error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
}
|