@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.
Files changed (263) hide show
  1. package/FRAMEWORK.md +420 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1310 -0
  4. package/dist/adapters/cli.d.ts +43 -0
  5. package/dist/adapters/cli.d.ts.map +1 -0
  6. package/dist/adapters/cli.js +126 -0
  7. package/dist/adapters/cli.js.map +1 -0
  8. package/dist/cli/commands/auth.d.ts +26 -0
  9. package/dist/cli/commands/auth.d.ts.map +1 -0
  10. package/dist/cli/commands/auth.js +233 -0
  11. package/dist/cli/commands/auth.js.map +1 -0
  12. package/dist/cli/commands/cloud.d.ts +27 -0
  13. package/dist/cli/commands/cloud.d.ts.map +1 -0
  14. package/dist/cli/commands/cloud.js +232 -0
  15. package/dist/cli/commands/cloud.js.map +1 -0
  16. package/dist/cli/commands/generate.d.ts +25 -0
  17. package/dist/cli/commands/generate.d.ts.map +1 -0
  18. package/dist/cli/commands/generate.js +168 -0
  19. package/dist/cli/commands/generate.js.map +1 -0
  20. package/dist/cli/index.d.ts +8 -0
  21. package/dist/cli/index.d.ts.map +1 -0
  22. package/dist/cli/index.js +179 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/cloud/auth.d.ts +51 -0
  25. package/dist/cloud/auth.d.ts.map +1 -0
  26. package/dist/cloud/auth.js +194 -0
  27. package/dist/cloud/auth.js.map +1 -0
  28. package/dist/cloud/billing.d.ts +184 -0
  29. package/dist/cloud/billing.d.ts.map +1 -0
  30. package/dist/cloud/billing.js +179 -0
  31. package/dist/cloud/billing.js.map +1 -0
  32. package/dist/cloud/client.d.ts +39 -0
  33. package/dist/cloud/client.d.ts.map +1 -0
  34. package/dist/cloud/client.js +176 -0
  35. package/dist/cloud/client.js.map +1 -0
  36. package/dist/cloud/index.d.ts +44 -0
  37. package/dist/cloud/index.d.ts.map +1 -0
  38. package/dist/cloud/index.js +44 -0
  39. package/dist/cloud/index.js.map +1 -0
  40. package/dist/cloud/marketplace.d.ts +166 -0
  41. package/dist/cloud/marketplace.d.ts.map +1 -0
  42. package/dist/cloud/marketplace.js +159 -0
  43. package/dist/cloud/marketplace.js.map +1 -0
  44. package/dist/cloud/provisioning.d.ts +110 -0
  45. package/dist/cloud/provisioning.d.ts.map +1 -0
  46. package/dist/cloud/provisioning.js +148 -0
  47. package/dist/cloud/provisioning.js.map +1 -0
  48. package/dist/cloud/relay/endpoints.d.ts +62 -0
  49. package/dist/cloud/relay/endpoints.d.ts.map +1 -0
  50. package/dist/cloud/relay/endpoints.js +217 -0
  51. package/dist/cloud/relay/endpoints.js.map +1 -0
  52. package/dist/cloud/relay/health/index.d.ts +5 -0
  53. package/dist/cloud/relay/health/index.d.ts.map +1 -0
  54. package/dist/cloud/relay/health/index.js +9 -0
  55. package/dist/cloud/relay/health/index.js.map +1 -0
  56. package/dist/cloud/relay/stats/index.d.ts +5 -0
  57. package/dist/cloud/relay/stats/index.d.ts.map +1 -0
  58. package/dist/cloud/relay/stats/index.js +9 -0
  59. package/dist/cloud/relay/stats/index.js.map +1 -0
  60. package/dist/cloud/relay/sync/index.d.ts +5 -0
  61. package/dist/cloud/relay/sync/index.d.ts.map +1 -0
  62. package/dist/cloud/relay/sync/index.js +9 -0
  63. package/dist/cloud/relay/sync/index.js.map +1 -0
  64. package/dist/cloud/relay/usage/index.d.ts +5 -0
  65. package/dist/cloud/relay/usage/index.d.ts.map +1 -0
  66. package/dist/cloud/relay/usage/index.js +9 -0
  67. package/dist/cloud/relay/usage/index.js.map +1 -0
  68. package/dist/cloud/sponsors.d.ts +81 -0
  69. package/dist/cloud/sponsors.d.ts.map +1 -0
  70. package/dist/cloud/sponsors.js +130 -0
  71. package/dist/cloud/sponsors.js.map +1 -0
  72. package/dist/cloud/types.d.ts +169 -0
  73. package/dist/cloud/types.d.ts.map +1 -0
  74. package/dist/cloud/types.js +7 -0
  75. package/dist/cloud/types.js.map +1 -0
  76. package/dist/components/index.d.ts +43 -0
  77. package/dist/components/index.d.ts.map +1 -0
  78. package/dist/components/index.js +17 -0
  79. package/dist/components/index.js.map +1 -0
  80. package/dist/core/actors.d.ts +95 -0
  81. package/dist/core/actors.d.ts.map +1 -0
  82. package/dist/core/actors.js +158 -0
  83. package/dist/core/actors.js.map +1 -0
  84. package/dist/core/component/generator.d.ts +122 -0
  85. package/dist/core/component/generator.d.ts.map +1 -0
  86. package/dist/core/component/generator.js +307 -0
  87. package/dist/core/component/generator.js.map +1 -0
  88. package/dist/core/engine.d.ts +92 -0
  89. package/dist/core/engine.d.ts.map +1 -0
  90. package/dist/core/engine.js +199 -0
  91. package/dist/core/engine.js.map +1 -0
  92. package/dist/core/introspection.d.ts +141 -0
  93. package/dist/core/introspection.d.ts.map +1 -0
  94. package/dist/core/introspection.js +208 -0
  95. package/dist/core/introspection.js.map +1 -0
  96. package/dist/core/logic/generator.d.ts +76 -0
  97. package/dist/core/logic/generator.d.ts.map +1 -0
  98. package/dist/core/logic/generator.js +339 -0
  99. package/dist/core/logic/generator.js.map +1 -0
  100. package/dist/core/pluresdb/generator.d.ts +58 -0
  101. package/dist/core/pluresdb/generator.d.ts.map +1 -0
  102. package/dist/core/pluresdb/generator.js +162 -0
  103. package/dist/core/pluresdb/generator.js.map +1 -0
  104. package/dist/core/protocol.d.ts +121 -0
  105. package/dist/core/protocol.d.ts.map +1 -0
  106. package/dist/core/protocol.js +46 -0
  107. package/dist/core/protocol.js.map +1 -0
  108. package/dist/core/rules.d.ts +120 -0
  109. package/dist/core/rules.d.ts.map +1 -0
  110. package/dist/core/rules.js +81 -0
  111. package/dist/core/rules.js.map +1 -0
  112. package/dist/core/schema/loader.d.ts +47 -0
  113. package/dist/core/schema/loader.d.ts.map +1 -0
  114. package/dist/core/schema/loader.js +189 -0
  115. package/dist/core/schema/loader.js.map +1 -0
  116. package/dist/core/schema/normalize.d.ts +72 -0
  117. package/dist/core/schema/normalize.d.ts.map +1 -0
  118. package/dist/core/schema/normalize.js +190 -0
  119. package/dist/core/schema/normalize.js.map +1 -0
  120. package/dist/core/schema/types.d.ts +370 -0
  121. package/dist/core/schema/types.d.ts.map +1 -0
  122. package/dist/core/schema/types.js +161 -0
  123. package/dist/core/schema/types.js.map +1 -0
  124. package/dist/dsl/index.d.ts +152 -0
  125. package/dist/dsl/index.d.ts.map +1 -0
  126. package/dist/dsl/index.js +132 -0
  127. package/dist/dsl/index.js.map +1 -0
  128. package/dist/dsl.d.ts +124 -0
  129. package/dist/dsl.d.ts.map +1 -0
  130. package/dist/dsl.js +130 -0
  131. package/dist/dsl.js.map +1 -0
  132. package/dist/examples/advanced-todo/index.d.ts +55 -0
  133. package/dist/examples/advanced-todo/index.d.ts.map +1 -0
  134. package/dist/examples/advanced-todo/index.js +222 -0
  135. package/dist/examples/advanced-todo/index.js.map +1 -0
  136. package/dist/examples/auth-basic/index.d.ts +17 -0
  137. package/dist/examples/auth-basic/index.d.ts.map +1 -0
  138. package/dist/examples/auth-basic/index.js +122 -0
  139. package/dist/examples/auth-basic/index.js.map +1 -0
  140. package/dist/examples/cart/index.d.ts +19 -0
  141. package/dist/examples/cart/index.d.ts.map +1 -0
  142. package/dist/examples/cart/index.js +202 -0
  143. package/dist/examples/cart/index.js.map +1 -0
  144. package/dist/examples/hero-ecommerce/index.d.ts +39 -0
  145. package/dist/examples/hero-ecommerce/index.d.ts.map +1 -0
  146. package/dist/examples/hero-ecommerce/index.js +506 -0
  147. package/dist/examples/hero-ecommerce/index.js.map +1 -0
  148. package/dist/examples/svelte-counter/index.d.ts +31 -0
  149. package/dist/examples/svelte-counter/index.d.ts.map +1 -0
  150. package/dist/examples/svelte-counter/index.js +123 -0
  151. package/dist/examples/svelte-counter/index.js.map +1 -0
  152. package/dist/flows.d.ts +125 -0
  153. package/dist/flows.d.ts.map +1 -0
  154. package/dist/flows.js +160 -0
  155. package/dist/flows.js.map +1 -0
  156. package/dist/index.d.ts +67 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +59 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/integrations/pluresdb.d.ts +56 -0
  161. package/dist/integrations/pluresdb.d.ts.map +1 -0
  162. package/dist/integrations/pluresdb.js +46 -0
  163. package/dist/integrations/pluresdb.js.map +1 -0
  164. package/dist/integrations/svelte.d.ts +306 -0
  165. package/dist/integrations/svelte.d.ts.map +1 -0
  166. package/dist/integrations/svelte.js +447 -0
  167. package/dist/integrations/svelte.js.map +1 -0
  168. package/dist/registry.d.ts +94 -0
  169. package/dist/registry.d.ts.map +1 -0
  170. package/dist/registry.js +181 -0
  171. package/dist/registry.js.map +1 -0
  172. package/dist/runtime/terminal-adapter.d.ts +105 -0
  173. package/dist/runtime/terminal-adapter.d.ts.map +1 -0
  174. package/dist/runtime/terminal-adapter.js +113 -0
  175. package/dist/runtime/terminal-adapter.js.map +1 -0
  176. package/dist/step.d.ts +34 -0
  177. package/dist/step.d.ts.map +1 -0
  178. package/dist/step.js +111 -0
  179. package/dist/step.js.map +1 -0
  180. package/dist/types.d.ts +63 -0
  181. package/dist/types.d.ts.map +1 -0
  182. package/dist/types.js +6 -0
  183. package/dist/types.js.map +1 -0
  184. package/docs/MONETIZATION.md +394 -0
  185. package/docs/TERMINAL_NODE.md +588 -0
  186. package/docs/guides/canvas.md +389 -0
  187. package/docs/guides/getting-started.md +347 -0
  188. package/docs/guides/history-state-pattern.md +618 -0
  189. package/docs/guides/orchestration.md +617 -0
  190. package/docs/guides/parallel-state-pattern.md +767 -0
  191. package/docs/guides/svelte-integration.md +691 -0
  192. package/package.json +96 -0
  193. package/src/__tests__/actors.test.ts +270 -0
  194. package/src/__tests__/billing.test.ts +175 -0
  195. package/src/__tests__/cloud.test.ts +247 -0
  196. package/src/__tests__/dsl.test.ts +154 -0
  197. package/src/__tests__/edge-cases.test.ts +475 -0
  198. package/src/__tests__/engine.test.ts +137 -0
  199. package/src/__tests__/generators.test.ts +270 -0
  200. package/src/__tests__/introspection.test.ts +321 -0
  201. package/src/__tests__/protocol.test.ts +40 -0
  202. package/src/__tests__/provisioning.test.ts +162 -0
  203. package/src/__tests__/schema.test.ts +241 -0
  204. package/src/__tests__/svelte-integration.test.ts +431 -0
  205. package/src/__tests__/terminal-node.test.ts +352 -0
  206. package/src/adapters/cli.ts +175 -0
  207. package/src/cli/commands/auth.ts +271 -0
  208. package/src/cli/commands/cloud.ts +281 -0
  209. package/src/cli/commands/generate.ts +225 -0
  210. package/src/cli/index.ts +190 -0
  211. package/src/cloud/README.md +383 -0
  212. package/src/cloud/auth.ts +245 -0
  213. package/src/cloud/billing.ts +336 -0
  214. package/src/cloud/client.ts +221 -0
  215. package/src/cloud/index.ts +121 -0
  216. package/src/cloud/marketplace.ts +303 -0
  217. package/src/cloud/provisioning.ts +254 -0
  218. package/src/cloud/relay/endpoints.ts +307 -0
  219. package/src/cloud/relay/health/function.json +17 -0
  220. package/src/cloud/relay/health/index.ts +10 -0
  221. package/src/cloud/relay/host.json +15 -0
  222. package/src/cloud/relay/local.settings.json +8 -0
  223. package/src/cloud/relay/stats/function.json +17 -0
  224. package/src/cloud/relay/stats/index.ts +10 -0
  225. package/src/cloud/relay/sync/function.json +17 -0
  226. package/src/cloud/relay/sync/index.ts +10 -0
  227. package/src/cloud/relay/usage/function.json +17 -0
  228. package/src/cloud/relay/usage/index.ts +10 -0
  229. package/src/cloud/sponsors.ts +213 -0
  230. package/src/cloud/types.ts +198 -0
  231. package/src/components/README.md +125 -0
  232. package/src/components/TerminalNode.svelte +457 -0
  233. package/src/components/index.ts +46 -0
  234. package/src/core/actors.ts +205 -0
  235. package/src/core/component/generator.ts +432 -0
  236. package/src/core/engine.ts +243 -0
  237. package/src/core/introspection.ts +329 -0
  238. package/src/core/logic/generator.ts +420 -0
  239. package/src/core/pluresdb/generator.ts +229 -0
  240. package/src/core/protocol.ts +132 -0
  241. package/src/core/rules.ts +167 -0
  242. package/src/core/schema/loader.ts +247 -0
  243. package/src/core/schema/normalize.ts +322 -0
  244. package/src/core/schema/types.ts +557 -0
  245. package/src/dsl/index.ts +218 -0
  246. package/src/dsl.ts +214 -0
  247. package/src/examples/advanced-todo/App.svelte +506 -0
  248. package/src/examples/advanced-todo/README.md +371 -0
  249. package/src/examples/advanced-todo/index.ts +309 -0
  250. package/src/examples/auth-basic/index.ts +163 -0
  251. package/src/examples/cart/index.ts +259 -0
  252. package/src/examples/hero-ecommerce/index.ts +657 -0
  253. package/src/examples/svelte-counter/index.ts +168 -0
  254. package/src/flows.ts +268 -0
  255. package/src/index.ts +154 -0
  256. package/src/integrations/pluresdb.ts +93 -0
  257. package/src/integrations/svelte.ts +617 -0
  258. package/src/registry.ts +223 -0
  259. package/src/runtime/terminal-adapter.ts +175 -0
  260. package/src/step.ts +151 -0
  261. package/src/types.ts +70 -0
  262. package/templates/basic-app/README.md +147 -0
  263. package/templates/fullstack-app/README.md +279 -0
@@ -0,0 +1,394 @@
1
+ # GitHub-Based Monetization
2
+
3
+ This document describes the GitHub-native monetization implementation for Praxis Cloud.
4
+
5
+ ## Overview
6
+
7
+ Praxis Cloud uses GitHub as the exclusive authentication and billing provider, aligning with the Microsoft partnership constraint. This enables:
8
+
9
+ - **GitHub OAuth** for secure authentication
10
+ - **GitHub Sponsors** for recurring subscriptions
11
+ - **GitHub Marketplace** for enterprise SaaS billing (preparatory)
12
+ - **Auto-provisioning** based on GitHub identity
13
+
14
+ ## Architecture
15
+
16
+ ```
17
+ ┌─────────────────┐
18
+ │ GitHub User │
19
+ └────────┬────────┘
20
+ │ OAuth Device Flow
21
+
22
+ ┌─────────────────┐
23
+ │ Praxis CLI │
24
+ │ praxis login │
25
+ └────────┬────────┘
26
+ │ GitHub Token
27
+
28
+ ┌─────────────────┐ ┌──────────────────┐
29
+ │ Praxis Cloud │────▶│ GitHub Sponsors │
30
+ │ Relay Service │ │ API │
31
+ └────────┬────────┘ └──────────────────┘
32
+
33
+
34
+ ┌─────────────────┐
35
+ │ Auto-Provision │
36
+ │ Tenant/Storage │
37
+ └─────────────────┘
38
+ ```
39
+
40
+ ## Subscription Tiers
41
+
42
+ ### Free Tier
43
+ - **Cost**: Free
44
+ - **Limits**:
45
+ - 1,000 syncs/month
46
+ - 10 MB storage
47
+ - 1 app/project
48
+ - Community support
49
+
50
+ ### Solo Tier ($5/month via GitHub Sponsors)
51
+ - **Limits**:
52
+ - 50,000 syncs/month
53
+ - 1 GB storage
54
+ - 10 apps/projects
55
+ - Standard support
56
+
57
+ ### Team Tier ($20/month via GitHub Sponsors)
58
+ - **Limits**:
59
+ - 500,000 syncs/month
60
+ - 10 GB storage
61
+ - 50 apps/projects
62
+ - 10 team members
63
+ - Standard support
64
+
65
+ ### Enterprise Tier ($50/month via GitHub Sponsors/Marketplace)
66
+ - **Limits**:
67
+ - 5,000,000 syncs/month
68
+ - 100 GB storage
69
+ - 1,000 apps/projects
70
+ - Unlimited team members
71
+ - Priority support
72
+ - SLA guarantees
73
+
74
+ ## Authentication Flow
75
+
76
+ ### 1. CLI Authentication
77
+
78
+ ```bash
79
+ # Using device flow (recommended)
80
+ praxis login
81
+
82
+ # Using personal access token
83
+ praxis login --token ghp_xxxxx
84
+
85
+ # Check authentication
86
+ praxis whoami
87
+
88
+ # Logout
89
+ praxis logout
90
+ ```
91
+
92
+ ### 2. Device Flow Process
93
+
94
+ 1. User runs `praxis login`
95
+ 2. CLI requests device code from GitHub
96
+ 3. User visits verification URL and enters code
97
+ 4. CLI polls for access token
98
+ 5. Token and user info stored locally in `~/.praxis/auth.json`
99
+ 6. CLI checks GitHub Sponsors status
100
+ 7. Auto-provisions tenant and storage
101
+
102
+ ### 3. Programmatic Authentication
103
+
104
+ ```typescript
105
+ import { authenticateWithDeviceFlow } from "@plures/praxis/cloud";
106
+
107
+ const result = await authenticateWithDeviceFlow("YOUR_CLIENT_ID");
108
+ if (result.success) {
109
+ console.log(`Authenticated as ${result.user?.login}`);
110
+ console.log(`Token: ${result.token}`);
111
+ }
112
+ ```
113
+
114
+ ## GitHub App Setup
115
+
116
+ ### Creating the GitHub App
117
+
118
+ 1. Visit https://github.com/settings/apps/new
119
+ 2. Use the manifest at `github/app/manifest.yml`
120
+ 3. Configure OAuth callback URL
121
+ 4. Enable webhooks for sponsorship events
122
+ 5. Generate and store client secret
123
+
124
+ ### Required Permissions
125
+
126
+ - **User permissions**: `emails:read`
127
+ - **OAuth scopes**: `read:user`, `user:email`
128
+ - **Webhook events**: `sponsorship`, `marketplace_purchase`
129
+
130
+ ### Environment Variables
131
+
132
+ ```bash
133
+ # GitHub OAuth
134
+ GITHUB_CLIENT_ID=your_client_id
135
+ GITHUB_CLIENT_SECRET=your_client_secret
136
+
137
+ # Praxis Cloud
138
+ PRAXIS_RELAY_ENDPOINT=https://praxis-relay.azurewebsites.net
139
+ PRAXIS_APP_ID=your_app_id
140
+ ```
141
+
142
+ ## GitHub Sponsors Integration
143
+
144
+ ### Setting Up Sponsors Tiers
145
+
146
+ 1. Enable GitHub Sponsors for your organization
147
+ 2. Create tiers matching Praxis pricing:
148
+ - Solo: $5/month
149
+ - Team: $20/month
150
+ - Enterprise: $50/month
151
+ 3. Configure webhook to notify relay service
152
+
153
+ ### Checking Subscription Status
154
+
155
+ ```typescript
156
+ import { createSponsorsClient } from "@plures/praxis/cloud";
157
+
158
+ const client = createSponsorsClient(githubToken);
159
+ const subscription = await client.getSubscription("username");
160
+
161
+ console.log(`Tier: ${subscription.tier}`);
162
+ console.log(`Status: ${subscription.status}`);
163
+ ```
164
+
165
+ ### Handling Sponsorship Events
166
+
167
+ Webhook payload example:
168
+
169
+ ```json
170
+ {
171
+ "action": "created",
172
+ "sponsorship": {
173
+ "sponsor": {
174
+ "login": "username",
175
+ "id": 12345
176
+ },
177
+ "tier": {
178
+ "name": "Solo",
179
+ "monthly_price_in_cents": 500
180
+ }
181
+ }
182
+ }
183
+ ```
184
+
185
+ ## GitHub Marketplace Integration (Preparatory)
186
+
187
+ ### Marketplace Plans
188
+
189
+ Plans are pre-configured in `src/cloud/marketplace.ts`:
190
+
191
+ - **Praxis Cloud Solo**: $5/month or $50/year
192
+ - **Praxis Cloud Team**: $20/month or $200/year
193
+ - **Praxis Cloud Enterprise**: $50/month or $500/year
194
+
195
+ ### Marketplace Listing
196
+
197
+ See `github/marketplace/` for listing templates and screenshots.
198
+
199
+ ### Webhook Handler
200
+
201
+ ```typescript
202
+ import { createMarketplaceClient } from "@plures/praxis/cloud";
203
+
204
+ const client = createMarketplaceClient(githubToken);
205
+
206
+ // Handle webhook event
207
+ app.post("/webhook/marketplace", (req, res) => {
208
+ const event = req.body;
209
+ const result = client.handleWebhookEvent(event);
210
+
211
+ if (result) {
212
+ // Provision or update tenant
213
+ console.log(`User ${result.userLogin} subscribed to ${result.subscription.tier}`);
214
+ }
215
+
216
+ res.status(200).send("OK");
217
+ });
218
+ ```
219
+
220
+ ## Auto-Provisioning
221
+
222
+ ### Tenant Creation
223
+
224
+ When a user authenticates, a tenant is automatically provisioned:
225
+
226
+ ```typescript
227
+ import { provisionTenant, createTenant } from "@plures/praxis/cloud";
228
+
229
+ const result = await provisionTenant(githubUser, subscription);
230
+
231
+ if (result.success) {
232
+ console.log(`Tenant ID: ${result.tenant.id}`);
233
+ console.log(`Storage: ${result.tenant.storageNamespace}`);
234
+ }
235
+ ```
236
+
237
+ ### Storage Namespace
238
+
239
+ Storage namespaces follow Azure Blob Storage naming rules:
240
+
241
+ - Format: `gh-{username}-{hash}`
242
+ - Example: `gh-testuser-0009ix`
243
+ - Lowercase, alphanumeric, hyphens only
244
+ - 3-63 characters
245
+
246
+ ### Access Control
247
+
248
+ Access to cloud features is controlled by subscription tier:
249
+
250
+ ```typescript
251
+ import { hasAccessToTier, SubscriptionTier } from "@plures/praxis/cloud";
252
+
253
+ if (hasAccessToTier(subscription, SubscriptionTier.TEAM)) {
254
+ // Allow team features
255
+ }
256
+ ```
257
+
258
+ ## Usage Tracking
259
+
260
+ ### Checking Usage
261
+
262
+ ```bash
263
+ praxis cloud usage
264
+ ```
265
+
266
+ Output:
267
+ ```
268
+ App ID: my-app
269
+
270
+ Metrics:
271
+ Total Syncs: 1,234
272
+ Events Forwarded: 5,678
273
+ Facts Synced: 12,345
274
+ Storage Used: 45.67 KB
275
+
276
+ Period: 720.0 hours
277
+ ```
278
+
279
+ ### Enforcing Limits
280
+
281
+ ```typescript
282
+ import { checkUsageLimits } from "@plures/praxis/cloud";
283
+
284
+ const result = checkUsageLimits(subscription, {
285
+ syncCount: 1500,
286
+ storageBytes: 15 * 1024 * 1024,
287
+ teamMembers: 1,
288
+ appCount: 2,
289
+ });
290
+
291
+ if (!result.withinLimits) {
292
+ console.error("Usage limits exceeded:");
293
+ result.violations.forEach(v => console.error(` - ${v}`));
294
+ }
295
+ ```
296
+
297
+ ## Security
298
+
299
+ ### Token Storage
300
+
301
+ Authentication tokens are stored securely:
302
+
303
+ - **Location**: `~/.praxis/auth.json`
304
+ - **Permissions**: `0600` (owner read/write only)
305
+ - **Contents**: Encrypted in production
306
+
307
+ ### Best Practices
308
+
309
+ 1. **Never commit tokens** to source control
310
+ 2. **Rotate tokens regularly**
311
+ 3. **Use environment variables** for CI/CD
312
+ 4. **Revoke tokens** when no longer needed
313
+ 5. **Use GitHub App tokens** for production services
314
+
315
+ ## Development
316
+
317
+ ### Local Testing
318
+
319
+ ```bash
320
+ # Set up test environment
321
+ export GITHUB_CLIENT_ID=your_test_client_id
322
+ export GITHUB_TOKEN=ghp_test_token
323
+
324
+ # Run tests
325
+ npm test
326
+
327
+ # Test CLI commands
328
+ npm run build
329
+ node dist/cli/index.js login
330
+ ```
331
+
332
+ ### Mocking GitHub API
333
+
334
+ For tests, use mock responses:
335
+
336
+ ```typescript
337
+ // Mock GitHub API
338
+ vi.mock("../cloud/sponsors.js", () => ({
339
+ createSponsorsClient: vi.fn(() => ({
340
+ getSubscription: vi.fn(async () => ({
341
+ tier: SubscriptionTier.SOLO,
342
+ status: SubscriptionStatus.ACTIVE,
343
+ // ...
344
+ })),
345
+ })),
346
+ }));
347
+ ```
348
+
349
+ ## Troubleshooting
350
+
351
+ ### "Not authenticated" Error
352
+
353
+ ```bash
354
+ # Re-authenticate
355
+ praxis logout
356
+ praxis login
357
+ ```
358
+
359
+ ### "Token expired" Error
360
+
361
+ ```bash
362
+ # Refresh authentication
363
+ praxis login
364
+ ```
365
+
366
+ ### "Usage limits exceeded" Error
367
+
368
+ Check your current usage:
369
+
370
+ ```bash
371
+ praxis cloud usage
372
+ ```
373
+
374
+ Upgrade your tier:
375
+
376
+ ```bash
377
+ # Visit GitHub Sponsors
378
+ open https://github.com/sponsors/plures
379
+ ```
380
+
381
+ ## Resources
382
+
383
+ - [GitHub OAuth Documentation](https://docs.github.com/en/apps/oauth-apps)
384
+ - [GitHub Sponsors API](https://docs.github.com/en/graphql/reference/objects#sponsor)
385
+ - [GitHub Marketplace](https://docs.github.com/en/apps/github-marketplace)
386
+ - [Azure Blob Storage](https://docs.microsoft.com/en-us/azure/storage/blobs/)
387
+
388
+ ## Support
389
+
390
+ For billing or subscription issues:
391
+
392
+ - **GitHub Sponsors**: Contact via GitHub
393
+ - **Enterprise**: Email enterprise@plures.dev
394
+ - **Community**: https://github.com/plures/praxis/discussions